diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 28072f153a4..b48a7d29f50 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -775,8 +775,9 @@ pub enum PatKind {
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum Mutability {
-    Mut,
+    // N.B. Order is deliberate, so that Not < Mut
     Not,
+    Mut,
 }
 
 impl Mutability {
@@ -787,12 +788,39 @@ impl Mutability {
         }
     }
 
-    pub fn prefix_str(&self) -> &'static str {
+    /// Returns `""` (empty string) or `"mut "` depending on the mutability.
+    pub fn prefix_str(self) -> &'static str {
         match self {
             Mutability::Mut => "mut ",
             Mutability::Not => "",
         }
     }
+
+    /// Returns `"&"` or `"&mut "` depending on the mutability.
+    pub fn ref_prefix_str(self) -> &'static str {
+        match self {
+            Mutability::Not => "&",
+            Mutability::Mut => "&mut ",
+        }
+    }
+
+    /// Returns `""` (empty string) or `"mutably "` depending on the mutability.
+    pub fn mutably_str(self) -> &'static str {
+        match self {
+            Mutability::Not => "",
+            Mutability::Mut => "mutably ",
+        }
+    }
+
+    /// Return `true` if self is mutable
+    pub fn is_mut(self) -> bool {
+        matches!(self, Self::Mut)
+    }
+
+    /// Return `true` if self is **not** mutable
+    pub fn is_not(self) -> bool {
+        matches!(self, Self::Not)
+    }
 }
 
 /// The kind of borrow in an `AddrOf` expression,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d1666dfbf64..4ec943f33e2 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1781,14 +1781,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // Given we are only considering `ImplicitSelf` types, we needn't consider
                     // the case where we have a mutable pattern to a reference as that would
                     // no longer be an `ImplicitSelf`.
-                    TyKind::Rptr(_, mt)
-                        if mt.ty.kind.is_implicit_self() && mt.mutbl == ast::Mutability::Mut =>
-                    {
-                        hir::ImplicitSelfKind::MutRef
-                    }
-                    TyKind::Rptr(_, mt) if mt.ty.kind.is_implicit_self() => {
-                        hir::ImplicitSelfKind::ImmRef
-                    }
+                    TyKind::Rptr(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl {
+                        hir::Mutability::Not => hir::ImplicitSelfKind::ImmRef,
+                        hir::Mutability::Mut => hir::ImplicitSelfKind::MutRef,
+                    },
                     _ => hir::ImplicitSelfKind::None,
                 }
             }),
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index a53940070f7..919117651e2 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -716,19 +716,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let moved_place = &self.move_data.move_paths[move_out.path].place;
                 let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
                 let move_span = move_spans.args_or_use();
-                let suggestion = if borrow_level == hir::Mutability::Mut {
-                    "&mut ".to_string()
-                } else {
-                    "&".to_string()
-                };
+                let suggestion = borrow_level.ref_prefix_str().to_owned();
                 (move_span.shrink_to_lo(), suggestion)
             })
             .collect();
         err.multipart_suggestion_verbose(
-            &format!(
-                "consider {}borrowing {value_name}",
-                if borrow_level == hir::Mutability::Mut { "mutably " } else { "" }
-            ),
+            format!("consider {}borrowing {value_name}", borrow_level.mutably_str()),
             sugg,
             Applicability::MaybeIncorrect,
         );
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 7457369aa58..5122f9808ed 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -389,13 +389,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             // diagnostic: if the span starts with a mutable borrow of
             // a local variable, then just suggest the user remove it.
             PlaceRef { local: _, projection: [] }
-                if {
-                    if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
-                        snippet.starts_with("&mut ")
-                    } else {
-                        false
-                    }
-                } =>
+                if self
+                    .infcx
+                    .tcx
+                    .sess
+                    .source_map()
+                    .span_to_snippet(span)
+                    .map_or(false, |snippet| snippet.starts_with("&mut ")) =>
             {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
                 err.span_suggestion(
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 077f33bb99c..a6bde884084 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -257,9 +257,9 @@ pub(crate) fn data_id_for_alloc_id(
     mutability: rustc_hir::Mutability,
 ) -> DataId {
     cx.todo.push(TodoItem::Alloc(alloc_id));
-    *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
-        module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap()
-    })
+    *cx.anon_allocs
+        .entry(alloc_id)
+        .or_insert_with(|| module.declare_anonymous_data(mutability.is_mut(), false).unwrap())
 }
 
 fn data_id_for_static(
@@ -343,12 +343,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                     }
                 };
                 let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
-                    module
-                        .declare_anonymous_data(
-                            alloc.inner().mutability == rustc_hir::Mutability::Mut,
-                            false,
-                        )
-                        .unwrap()
+                    module.declare_anonymous_data(alloc.inner().mutability.is_mut(), false).unwrap()
                 });
                 (data_id, alloc, None)
             }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index cf590a43826..2f5dd519b26 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1500,7 +1500,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
         let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
         let (pointer_count, underlying_ty) = match element_ty1.kind() {
-            ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => {
+            ty::RawPtr(p) if p.ty == in_elem && p.mutbl.is_mut() => {
                 (ptr_count(element_ty1), non_ptr(element_ty1))
             }
             _ => {
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index 0c1819bb0c7..6e2fbf96cbf 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -130,10 +130,7 @@ impl hir::Pat<'_> {
     pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
         let mut result = None;
         self.each_binding(|annotation, _, _, _| match annotation {
-            hir::BindingAnnotation::REF => match result {
-                None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not),
-                _ => {}
-            },
+            hir::BindingAnnotation::REF if result.is_none() => result = Some(hir::Mutability::Not),
             hir::BindingAnnotation::REF_MUT => result = Some(hir::Mutability::Mut),
             _ => {}
         });
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index d6a5736bbf4..193ecdb1678 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -370,7 +370,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
     let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                        mt_b: ty::TypeAndMut<'tcx>,
                        mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
-        if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
+        if mt_a.mutbl < mt_b.mutbl {
             infcx
                 .err_ctxt()
                 .report_mismatched_types(
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index d66b6585fb6..cc5114dba5e 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -292,7 +292,7 @@ fn emit_newtype_suggestion_for_raw_ptr(
     diag: &mut Diagnostic,
 ) {
     if !self_ty.needs_subst() {
-        let mut_key = if ptr_ty.mutbl == rustc_middle::mir::Mutability::Mut { "mut " } else { "" };
+        let mut_key = ptr_ty.mutbl.prefix_str();
         let msg_sugg = "consider introducing a new wrapper type".to_owned();
         let sugg = vec![
             (
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index d70ec94f5b6..99a7f52efdb 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -398,7 +398,7 @@ impl<'a> State<'a> {
             }
             hir::ForeignItemKind::Static(t, m) => {
                 self.head("static");
-                if m == hir::Mutability::Mut {
+                if m.is_mut() {
                     self.word_space("mut");
                 }
                 self.print_ident(item.ident);
@@ -519,7 +519,7 @@ impl<'a> State<'a> {
             }
             hir::ItemKind::Static(ty, m, expr) => {
                 self.head("static");
-                if m == hir::Mutability::Mut {
+                if m.is_mut() {
                     self.word_space("mut");
                 }
                 self.print_ident(item.ident);
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index e93e8b0bada..e25a9e9036a 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -574,8 +574,5 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 }
 
 fn arms_contain_ref_bindings<'tcx>(arms: &'tcx [hir::Arm<'tcx>]) -> Option<hir::Mutability> {
-    arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max_by_key(|m| match *m {
-        hir::Mutability::Mut => 1,
-        hir::Mutability::Not => 0,
-    })
+    arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max()
 }
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 25b6cf4ef2e..1c14c1d35f7 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -257,15 +257,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         return None;
                     };
 
-                    let mutbl = match mutbl {
-                        hir::Mutability::Not => AutoBorrowMutability::Not,
-                        hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                            // For initial two-phase borrow
-                            // deployment, conservatively omit
-                            // overloaded function call ops.
-                            allow_two_phase_borrow: AllowTwoPhase::No,
-                        },
-                    };
+                    // For initial two-phase borrow
+                    // deployment, conservatively omit
+                    // overloaded function call ops.
+                    let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::No);
+
                     autoref = Some(Adjustment {
                         kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
                         target: method.sig.inputs()[0],
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 5e1e44dcb6d..1cea8c9dadc 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -951,7 +951,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         m_cast: ty::TypeAndMut<'tcx>,
     ) -> Result<CastKind, CastError> {
         // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
-        if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not {
+        if m_expr.mutbl >= m_cast.mutbl {
             if let ty::Array(ety, _) = m_expr.ty.kind() {
                 // Due to the limitations of LLVM global constants,
                 // region pointers end up pointing at copies of
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 2c24b9ef14e..1ceb07def72 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -202,7 +202,7 @@ fn check_panic_info_fn(
     let arg_is_panic_info = match *inputs[0].kind() {
         ty::Ref(region, ty, mutbl) => match *ty.kind() {
             ty::Adt(ref adt, _) => {
-                adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
+                adt.did() == panic_info_did && mutbl.is_not() && !region.is_static()
             }
             _ => false,
         },
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index b6e37d9ec8e..6b6d54db506 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -108,11 +108,7 @@ fn coerce_mutbls<'tcx>(
     from_mutbl: hir::Mutability,
     to_mutbl: hir::Mutability,
 ) -> RelateResult<'tcx, ()> {
-    match (from_mutbl, to_mutbl) {
-        (hir::Mutability::Mut, hir::Mutability::Mut | hir::Mutability::Not)
-        | (hir::Mutability::Not, hir::Mutability::Not) => Ok(()),
-        (hir::Mutability::Not, hir::Mutability::Mut) => Err(TypeError::Mutability),
-    }
+    if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) }
 }
 
 /// Do not require any adjustments, i.e. coerce `x -> x`.
@@ -456,7 +452,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             return Err(err);
         };
 
-        if ty == a && mt_a.mutbl == hir::Mutability::Not && autoderef.step_count() == 1 {
+        if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 {
             // As a special case, if we would produce `&'a *x`, that's
             // a total no-op. We end up with the type `&'a T` just as
             // we started with.  In that case, just skip it
@@ -468,7 +464,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             // `self.x` both have `&mut `type would be a move of
             // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
             // which is a borrow.
-            assert_eq!(mutbl_b, hir::Mutability::Not); // can only coerce &T -> &U
+            assert!(mutbl_b.is_not()); // can only coerce &T -> &U
             return success(vec![], ty, obligations);
         }
 
@@ -482,12 +478,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let ty::Ref(r_borrow, _, _) = ty.kind() else {
             span_bug!(span, "expected a ref type, got {:?}", ty);
         };
-        let mutbl = match mutbl_b {
-            hir::Mutability::Not => AutoBorrowMutability::Not,
-            hir::Mutability::Mut => {
-                AutoBorrowMutability::Mut { allow_two_phase_borrow: self.allow_two_phase }
-            }
-        };
+        let mutbl = AutoBorrowMutability::new(mutbl_b, self.allow_two_phase);
         adjustments.push(Adjustment {
             kind: Adjust::Borrow(AutoBorrow::Ref(*r_borrow, mutbl)),
             target: ty,
@@ -556,15 +547,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
                 let coercion = Coercion(self.cause.span);
                 let r_borrow = self.next_region_var(coercion);
-                let mutbl = match mutbl_b {
-                    hir::Mutability::Not => AutoBorrowMutability::Not,
-                    hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                        // We don't allow two-phase borrows here, at least for initial
-                        // implementation. If it happens that this coercion is a function argument,
-                        // the reborrow in coerce_borrowed_ptr will pick it up.
-                        allow_two_phase_borrow: AllowTwoPhase::No,
-                    },
-                };
+
+                // We don't allow two-phase borrows here, at least for initial
+                // implementation. If it happens that this coercion is a function argument,
+                // the reborrow in coerce_borrowed_ptr will pick it up.
+                let mutbl = AutoBorrowMutability::new(mutbl_b, AllowTwoPhase::No);
+
                 Some((
                     Adjustment { kind: Adjust::Deref(None), target: ty_a },
                     Adjustment {
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 934d1240442..2106dce6f40 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -19,6 +19,7 @@ use rustc_trait_selection::traits::ObligationCause;
 
 use super::method::probe;
 
+use std::cmp::min;
 use std::iter;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -855,31 +856,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             ..
                         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
                         {
-                            if mutability == hir::Mutability::Mut {
+                            if mutability.is_mut() {
                                 // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
                                 return None;
                             }
                         }
 
                         let sugg_expr = if needs_parens { format!("({src})") } else { src };
-                        return Some(match mutability {
-                            hir::Mutability::Mut => (
-                                sp,
-                                "consider mutably borrowing here".to_string(),
-                                format!("{prefix}&mut {sugg_expr}"),
-                                Applicability::MachineApplicable,
-                                false,
-                                false,
-                            ),
-                            hir::Mutability::Not => (
-                                sp,
-                                "consider borrowing here".to_string(),
-                                format!("{prefix}&{sugg_expr}"),
-                                Applicability::MachineApplicable,
-                                false,
-                                false,
-                            ),
-                        });
+                        return Some((
+                            sp,
+                            format!("consider {}borrowing here", mutability.mutably_str()),
+                            format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()),
+                            Applicability::MachineApplicable,
+                            false,
+                            false,
+                        ));
                     }
                 }
             }
@@ -937,51 +928,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     && let Ok(src) = sm.span_to_snippet(sp)
                 {
                     let derefs = "*".repeat(steps);
-                    if let Some((span, src, applicability)) = match mutbl_b {
-                        hir::Mutability::Mut => {
-                            let new_prefix = "&mut ".to_owned() + &derefs;
-                            match mutbl_a {
-                                hir::Mutability::Mut => {
-                                    replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
-                                        let pos = sp.lo() + BytePos(5);
-                                        let sp = sp.with_lo(pos).with_hi(pos);
-                                        (sp, derefs, Applicability::MachineApplicable)
-                                    })
-                                }
-                                hir::Mutability::Not => {
-                                    replace_prefix(&src, "&", &new_prefix).map(|_| {
-                                        let pos = sp.lo() + BytePos(1);
-                                        let sp = sp.with_lo(pos).with_hi(pos);
-                                        (
-                                            sp,
-                                            format!("mut {derefs}"),
-                                            Applicability::Unspecified,
-                                        )
-                                    })
-                                }
-                            }
-                        }
-                        hir::Mutability::Not => {
-                            let new_prefix = "&".to_owned() + &derefs;
-                            match mutbl_a {
-                                hir::Mutability::Mut => {
-                                    replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
-                                        let lo = sp.lo() + BytePos(1);
-                                        let hi = sp.lo() + BytePos(5);
-                                        let sp = sp.with_lo(lo).with_hi(hi);
-                                        (sp, derefs, Applicability::MachineApplicable)
-                                    })
-                                }
-                                hir::Mutability::Not => {
-                                    replace_prefix(&src, "&", &new_prefix).map(|_| {
-                                        let pos = sp.lo() + BytePos(1);
-                                        let sp = sp.with_lo(pos).with_hi(pos);
-                                        (sp, derefs, Applicability::MachineApplicable)
-                                    })
-                                }
-                            }
-                        }
-                    } {
+                    let old_prefix = mutbl_a.ref_prefix_str();
+                    let new_prefix = mutbl_b.ref_prefix_str().to_owned() + &derefs;
+
+                    let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| {
+                        // skip `&` or `&mut ` if both mutabilities are mutable
+                        let lo = sp.lo() + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
+                        // skip `&` or `&mut `
+                        let hi = sp.lo() + BytePos(old_prefix.len() as _);
+                        let sp = sp.with_lo(lo).with_hi(hi);
+
+                        (
+                            sp,
+                            format!("{}{derefs}", if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }),
+                            if mutbl_b <= mutbl_a { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect }
+                        )
+                    });
+
+                    if let Some((span, src, applicability)) = suggestion {
                         return Some((
                             span,
                             "consider dereferencing".to_string(),
@@ -1005,10 +969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // If the expression has `&`, removing it would fix the error
                             prefix_span = prefix_span.with_hi(inner.span.lo());
                             expr = inner;
-                            remove += match mutbl {
-                                hir::Mutability::Not => "&",
-                                hir::Mutability::Mut => "&mut ",
-                            };
+                            remove.push_str(mutbl.ref_prefix_str());
                             steps -= 1;
                         } else {
                             break;
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index c0aff8f240f..25fdf31d53f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -345,8 +345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             if annotation {
                 let suggest_annotation = match expr.peel_drop_temps().kind {
-                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&",
-                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ",
+                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, _) => mutbl.ref_prefix_str(),
                     _ => return true,
                 };
                 let mut tuple_indexes = Vec::new();
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index e968ccc11e5..f50a16dcb23 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -170,14 +170,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                 let base_ty = target;
 
                 target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
-                let mutbl = match mutbl {
-                    hir::Mutability::Not => AutoBorrowMutability::Not,
-                    hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                        // Method call receivers are the primary use case
-                        // for two-phase borrows.
-                        allow_two_phase_borrow: AllowTwoPhase::Yes,
-                    },
-                };
+
+                // Method call receivers are the primary use case
+                // for two-phase borrows.
+                let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::Yes);
+
                 adjustments.push(Adjustment {
                     kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
                     target,
@@ -202,7 +199,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
                 target = match target.kind() {
                     &ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
-                        assert_eq!(mutbl, hir::Mutability::Mut);
+                        assert!(mutbl.is_mut());
                         self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
                     }
                     other => panic!("Cannot adjust receiver type {:?} to const ptr", other),
diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index 89746ce54a6..dea14dd93d6 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -5,7 +5,6 @@ use crate::{
 use hir::def_id::DefId;
 use hir::HirId;
 use hir::ItemKind;
-use rustc_ast::Mutability;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -88,14 +87,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let derefs = "*".repeat(pick.autoderefs);
 
                     let autoref = match pick.autoref_or_ptr_adjustment {
-                        Some(probe::AutorefOrPtrAdjustment::Autoref {
-                            mutbl: Mutability::Mut,
-                            ..
-                        }) => "&mut ",
-                        Some(probe::AutorefOrPtrAdjustment::Autoref {
-                            mutbl: Mutability::Not,
-                            ..
-                        }) => "&",
+                        Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => {
+                            mutbl.ref_prefix_str()
+                        }
                         Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
                     };
                     if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
@@ -386,8 +380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let derefs = "*".repeat(pick.autoderefs);
 
         let autoref = match pick.autoref_or_ptr_adjustment {
-            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ",
-            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&",
+            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(),
             Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
         };
 
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 5ca74f713af..9814d3a9dd5 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1147,19 +1147,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && assoc.kind == ty::AssocKind::Fn
             {
                 let sig = self.tcx.fn_sig(assoc.def_id);
-                if let Some(first) = sig.inputs().skip_binder().get(0) {
-                    if first.peel_refs() == rcvr_ty.peel_refs() {
-                        None
-                    } else {
-                        Some(if first.is_region_ptr() {
-                            if first.is_mutable_ptr() { "&mut " } else { "&" }
-                        } else {
-                            ""
-                        })
-                    }
-                } else {
+                sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() {
                     None
-                }
+                } else {
+                    Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()))
+                })
             } else {
                 None
             };
@@ -2627,11 +2619,7 @@ fn print_disambiguation_help<'tcx>(
     let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
         let args = format!(
             "({}{})",
-            if rcvr_ty.is_region_ptr() {
-                if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
-            } else {
-                ""
-            },
+            rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),
             std::iter::once(receiver)
                 .chain(args.iter())
                 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index adc7a21f265..b12d84af4ad 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -263,14 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let by_ref_binop = !op.node.is_by_value();
                 if is_assign == IsAssign::Yes || by_ref_binop {
                     if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() {
-                        let mutbl = match mutbl {
-                            hir::Mutability::Not => AutoBorrowMutability::Not,
-                            hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                                // Allow two-phase borrows for binops in initial deployment
-                                // since they desugar to methods
-                                allow_two_phase_borrow: AllowTwoPhase::Yes,
-                            },
-                        };
+                        let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes);
                         let autoref = Adjustment {
                             kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
                             target: method.sig.inputs()[0],
@@ -280,14 +273,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
                 if by_ref_binop {
                     if let ty::Ref(region, _, mutbl) = method.sig.inputs()[1].kind() {
-                        let mutbl = match mutbl {
-                            hir::Mutability::Not => AutoBorrowMutability::Not,
-                            hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                                // Allow two-phase borrows for binops in initial deployment
-                                // since they desugar to methods
-                                allow_two_phase_borrow: AllowTwoPhase::Yes,
-                            },
-                        };
+                        // Allow two-phase borrows for binops in initial deployment
+                        // since they desugar to methods
+                        let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes);
+
                         let autoref = Adjustment {
                             kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
                             target: method.sig.inputs()[1],
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 2fe1b1d8999..decd317d9fc 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -702,7 +702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
 
             let mut_var_suggestion = 'block: {
-                if !matches!(mutbl, ast::Mutability::Mut) {
+                if mutbl.is_not() {
                     break 'block None;
                 }
 
@@ -749,7 +749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
                         vec![
                             (pat.span.until(inner.span), "".to_owned()),
-                            (ty_span.shrink_to_lo(), format!("&{}", mutbl.prefix_str())),
+                            (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
                         ],
                         Applicability::MachineApplicable
                     );
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 7b3178e610f..31235ce1918 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -15,7 +15,7 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
 use rustc_middle::ty::{self, DefIdTree, InferConst};
 use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
@@ -508,10 +508,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     [
                         ..,
                         Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
-                    ] => match mut_ {
-                        AutoBorrowMutability::Mut { .. } => "&mut ",
-                        AutoBorrowMutability::Not => "&",
-                    },
+                    ] => hir::Mutability::from(*mut_).ref_prefix_str(),
                     _ => "",
                 };
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 4b5aa3badda..7fb8ed8c233 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1268,10 +1268,10 @@ declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
 
 impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
-        if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) =
+        if let Some((&ty::Ref(_, _, from_mutbl), &ty::Ref(_, _, to_mutbl))) =
             get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
         {
-            if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
+            if from_mutbl < to_mutbl {
                 cx.struct_span_lint(
                     MUTABLE_TRANSMUTES,
                     expr.span,
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index b8e6f0258d0..7036c4a7b27 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -159,6 +159,18 @@ pub enum AutoBorrowMutability {
     Not,
 }
 
+impl AutoBorrowMutability {
+    /// Creates an `AutoBorrowMutability` from a mutability and allowance of two phase borrows.
+    ///
+    /// Note that when `mutbl.is_not()`, `allow_two_phase_borrow` is ignored
+    pub fn new(mutbl: hir::Mutability, allow_two_phase_borrow: AllowTwoPhase) -> Self {
+        match mutbl {
+            hir::Mutability::Not => Self::Not,
+            hir::Mutability::Mut => Self::Mut { allow_two_phase_borrow },
+        }
+    }
+}
+
 impl From<AutoBorrowMutability> for hir::Mutability {
     fn from(m: AutoBorrowMutability) -> Self {
         match m {
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index 9fcba3e46f1..74048ff7da3 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -169,7 +169,7 @@ impl<'hir> Sig for hir::Ty<'hir> {
                 let mut prefix = "&".to_owned();
                 prefix.push_str(&lifetime.name.ident().to_string());
                 prefix.push(' ');
-                if let hir::Mutability::Mut = mt.mutbl {
+                if mt.mutbl.is_mut() {
                     prefix.push_str("mut ");
                 };
 
@@ -332,7 +332,7 @@ impl<'hir> Sig for hir::Item<'hir> {
         match self.kind {
             hir::ItemKind::Static(ref ty, m, ref body) => {
                 let mut text = "static ".to_owned();
-                if m == hir::Mutability::Mut {
+                if m.is_mut() {
                     text.push_str("mut ");
                 }
                 let name = self.ident.to_string();
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index b6378af7ba0..2cca480f271 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -622,7 +622,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
                 });
 
                 match inner_ty.kind() {
-                    ty::Str if *mutbl == hir::Mutability::Not => {
+                    ty::Str if mutbl.is_not() => {
                         match ct.kind() {
                             ty::ConstKind::Value(valtree) => {
                                 let slice =
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 5c13b6400ae..da6ca30cc9a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1055,7 +1055,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 {
                     (
                         mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))),
-                        matches!(mutability, hir::Mutability::Mut),
+                        mutability.is_mut(),
                     )
                 } else {
                     (false, false)
@@ -1344,7 +1344,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         .sess
                         .source_map()
                         .span_take_while(span, |c| c.is_whitespace() || *c == '&');
-                    if points_at_arg && mutability == hir::Mutability::Not && refs_number > 0 {
+                    if points_at_arg && mutability.is_not() && refs_number > 0 {
                         err.span_suggestion_verbose(
                             sp,
                             "consider changing this borrow's mutability",