Index: include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h
===================================================================
--- include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h
+++ include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h
@@ -622,6 +622,8 @@
   /// \pre \p Reg is a virtual register that either has a bank or a class.
   /// \returns The constrained register class, or nullptr if there is none.
   /// \note This is a generic variant of MachineRegisterInfo::constrainRegClass
+  /// \note Use MachineRegisterInfo::constrainRegAttrs instead for any non-isel
+  /// purpose, including non-select passes of GlobalISel
   static const TargetRegisterClass *
   constrainGenericRegister(unsigned Reg, const TargetRegisterClass &RC,
                            MachineRegisterInfo &MRI);
Index: include/llvm/CodeGen/MachineRegisterInfo.h
===================================================================
--- include/llvm/CodeGen/MachineRegisterInfo.h
+++ include/llvm/CodeGen/MachineRegisterInfo.h
@@ -548,12 +548,16 @@
   /// except that it also changes any definitions of the register as well.
   ///
   /// Note that it is usually necessary to first constrain ToReg's register
-  /// class to match the FromReg constraints using:
+  /// class and register bank to match the FromReg constraints using one of the
+  /// methods:
   ///
   ///   constrainRegClass(ToReg, getRegClass(FromReg))
+  ///   constrainRegAttrs(ToReg, FromReg)
+  ///   RegisterBankInfo::constrainGenericRegister(ToReg,
+  ///       *MRI.getRegClass(FromReg), MRI)
   ///
-  /// That function will return NULL if the virtual registers have incompatible
-  /// constraints.
+  /// These functions will return a falsy result if the virtual registers have
+  /// incompatible constraints.
   ///
   /// Note that if ToReg is a physical register the function will replace and
   /// apply sub registers to ToReg in order to obtain a final/proper physical
@@ -653,10 +657,30 @@
   /// new register class, or NULL if no such class exists.
   /// This should only be used when the constraint is known to be trivial, like
   /// GR32 -> GR32_NOSP. Beware of increasing register pressure.
+  ///
+  /// \note Assumes that the register has a register class assigned.
+  /// Use RegisterBankInfo::constrainGenericRegister in GlobalISel's
+  /// InstructionSelect pass and constrainRegAttrs in every other pass,
+  /// including non-select passes of GlobalISel, instead.
   const TargetRegisterClass *constrainRegClass(unsigned Reg,
                                                const TargetRegisterClass *RC,
                                                unsigned MinNumRegs = 0);
 
+  /// Constrain the register class or the register bank of the virtual register
+  /// \p Reg to be a common subclass and a common bank of both registers
+  /// provided respectively. Do nothing if any of the attributes (classes,
+  /// banks, or low-level types) of the registers are deemed incompatible, or if
+  /// the resulting register will have a class smaller than before and of size
+  /// less than \p MinNumRegs. Return true if such register attributes exist,
+  /// false otherwise.
+  ///
+  /// \note Assumes that each register has either a low-level type or a class
+  /// assigned, but not both. Use this method instead of constrainRegClass and
+  /// RegisterBankInfo::constrainGenericRegister everywhere but SelectionDAG
+  /// ISel / FastISel and GlobalISel's InstructionSelect pass respectively.
+  bool constrainRegAttrs(unsigned Reg, unsigned ConstrainingReg,
+                         unsigned MinNumRegs = 0);
+
   /// recomputeRegClass - Try to find a legal super-class of Reg's register
   /// class that still satisfies the constraints from the instructions using
   /// Reg.  Returns true if Reg was upgraded.
Index: lib/CodeGen/MachineCSE.cpp
===================================================================
--- lib/CodeGen/MachineCSE.cpp
+++ lib/CodeGen/MachineCSE.cpp
@@ -176,8 +176,7 @@
     // class given a super-reg class and subreg index.
     if (DefMI->getOperand(1).getSubReg())
       continue;
-    const TargetRegisterClass *RC = MRI->getRegClass(Reg);
-    if (!MRI->constrainRegClass(SrcReg, RC))
+    if (!MRI->constrainRegAttrs(SrcReg, Reg))
       continue;
     DEBUG(dbgs() << "Coalescing: " << *DefMI);
     DEBUG(dbgs() << "***     to: " << *MI);
@@ -588,11 +587,11 @@
         break;
       }
 
-      // Don't perform CSE if the result of the old instruction cannot exist
-      // within the register class of the new instruction.
-      const TargetRegisterClass *OldRC = MRI->getRegClass(OldReg);
-      if (!MRI->constrainRegClass(NewReg, OldRC)) {
-        DEBUG(dbgs() << "*** Not the same register class, avoid CSE!\n");
+      // Don't perform CSE if the result of the new instruction cannot exist
+      // within the constraints (register class, bank, or low-level type) of
+      // the old instruction.
+      if (!MRI->constrainRegAttrs(NewReg, OldReg)) {
+        DEBUG(dbgs() << "*** Not the same register constraints, avoid CSE!\n");
         DoCSE = false;
         break;
       }
Index: lib/CodeGen/MachineRegisterInfo.cpp
===================================================================
--- lib/CodeGen/MachineRegisterInfo.cpp
+++ lib/CodeGen/MachineRegisterInfo.cpp
@@ -65,23 +65,66 @@
   VRegInfo[Reg].first = &RegBank;
 }
 
-const TargetRegisterClass *
-MachineRegisterInfo::constrainRegClass(unsigned Reg,
-                                       const TargetRegisterClass *RC,
-                                       unsigned MinNumRegs) {
-  const TargetRegisterClass *OldRC = getRegClass(Reg);
+static const TargetRegisterClass *
+constrainRegClass(MachineRegisterInfo &MRI, unsigned Reg,
+                  const TargetRegisterClass *OldRC,
+                  const TargetRegisterClass *RC, unsigned MinNumRegs) {
   if (OldRC == RC)
     return RC;
   const TargetRegisterClass *NewRC =
-    getTargetRegisterInfo()->getCommonSubClass(OldRC, RC);
+      MRI.getTargetRegisterInfo()->getCommonSubClass(OldRC, RC);
   if (!NewRC || NewRC == OldRC)
     return NewRC;
   if (NewRC->getNumRegs() < MinNumRegs)
     return nullptr;
-  setRegClass(Reg, NewRC);
+  MRI.setRegClass(Reg, NewRC);
   return NewRC;
 }
 
+const TargetRegisterClass *
+MachineRegisterInfo::constrainRegClass(unsigned Reg,
+                                       const TargetRegisterClass *RC,
+                                       unsigned MinNumRegs) {
+  return ::constrainRegClass(*this, Reg, getRegClass(Reg), RC, MinNumRegs);
+}
+
+bool
+MachineRegisterInfo::constrainRegAttrs(unsigned Reg,
+                                       unsigned ConstrainingReg,
+                                       unsigned MinNumRegs) {
+  auto const *OldRC = getRegClassOrNull(Reg);
+  auto const *RC = getRegClassOrNull(ConstrainingReg);
+  // A virtual register at any point must have either a low-level type
+  // or a class assigned, but not both. The only exception is the internals of
+  // GlobalISel's instruction selection pass, which is allowed to temporarily
+  // introduce registers with types and classes both.
+  assert((OldRC || getType(Reg).isValid()) && "Reg has neither class nor type");
+  assert((!OldRC || !getType(Reg).isValid()) && "Reg has class and type both");
+  assert((RC || getType(ConstrainingReg).isValid()) &&
+         "ConstrainingReg has neither class nor type");
+  assert((!RC || !getType(ConstrainingReg).isValid()) &&
+         "ConstrainingReg has class and type both");
+  if (OldRC && RC)
+    return ::constrainRegClass(*this, Reg, OldRC, RC, MinNumRegs);
+  // If one of the virtual registers is generic (used in generic machine
+  // instructions, has a low-level type, doesn't have a class), and the other is
+  // concrete (used in target specific instructions, doesn't have a low-level
+  // type, has a class), we can not unify them.
+  if (OldRC || RC)
+    return false;
+  // At this point, both registers are guaranteed to have a valid low-level
+  // type, and they must agree.
+  if (getType(Reg) != getType(ConstrainingReg))
+    return false;
+  auto const *OldRB = getRegBankOrNull(Reg);
+  auto const *RB = getRegBankOrNull(ConstrainingReg);
+  if (OldRB)
+    return !RB || RB == OldRB;
+  if (RB)
+    setRegBank(Reg, *RB);
+  return true;
+}
+
 bool
 MachineRegisterInfo::recomputeRegClass(unsigned Reg) {
   const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
Index: test/CodeGen/AArch64/GlobalISel/machine-cse-mid-pipeline.mir
===================================================================
--- /dev/null
+++ test/CodeGen/AArch64/GlobalISel/machine-cse-mid-pipeline.mir
@@ -0,0 +1,181 @@
+# RUN: llc -run-pass machine-cse -global-isel -verify-machineinstrs -mtriple aarch64-apple-ios %s -o - | FileCheck %s
+---
+name:            irtranslated
+legalized:       false
+regBankSelected: false
+selected:        false
+body:             |
+  ; CHECK-LABEL: name: irtranslated
+  ; CHECK:      %[[ONE:[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; CHECK-NEXT: %[[TWO:[0-9]+]]:_(s32) = G_ADD %[[ONE]], %[[ONE]]
+  ; CHECK-NEXT: %[[SUM:[0-9]+]]:_(s32) = G_ADD %[[TWO]], %[[TWO]]
+  ; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s32)
+  ; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
+  bb.0:
+    %0:_(s32) = G_CONSTANT i32 1
+    %1:_(s32) = G_ADD %0, %0
+    %2:_(s32) = G_ADD %0, %0
+    %3:_(s32) = G_ADD %1, %2
+    %w0 = COPY %3(s32)
+    RET_ReallyLR implicit %w0
+...
+---
+name:            regbankselected
+legalized:       true
+regBankSelected: true
+selected:        false
+body:             |
+  ; CHECK-LABEL: name: regbankselected
+  ; CHECK:      %[[ONE:[0-9]+]]:gpr(s32) = G_CONSTANT i32 1
+  ; CHECK-NEXT: %[[TWO:[0-9]+]]:gpr(s32) = G_ADD %[[ONE]], %[[ONE]]
+  ; CHECK-NEXT: %[[SUM:[0-9]+]]:gpr(s32) = G_ADD %[[TWO]], %[[TWO]]
+  ; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s32)
+  ; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
+  bb.0:
+    %0:gpr(s32) = G_CONSTANT i32 1
+    %1:gpr(s32) = G_ADD %0, %0
+    %2:gpr(s32) = G_ADD %0, %0
+    %3:gpr(s32) = G_ADD %1, %2
+    %w0 = COPY %3(s32)
+    RET_ReallyLR implicit %w0
+...
+---
+name:            legalized
+legalized:       true
+regBankSelected: false
+selected:        false
+body:             |
+  ; CHECK-LABEL: name: legalized
+  ; CHECK:      %[[ONE:[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; CHECK-NEXT: %[[TWO:[0-9]+]]:gpr(s32) = G_ADD %[[ONE]], %[[ONE]]
+  ; CHECK-NEXT: %[[SUM:[0-9]+]]:_(s32) = G_ADD %[[TWO]], %[[TWO]]
+  ; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s32)
+  ; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
+  bb.0:
+    %0:_(s32) = G_CONSTANT i32 1
+    %1:_(s32) = G_ADD %0, %0
+    %2:gpr(s32) = G_ADD %0, %0
+    %3:_(s32) = G_ADD %1, %2
+    %w0 = COPY %3(s32)
+    RET_ReallyLR implicit %w0
+...
+---
+name:            legalized_sym
+legalized:       true
+regBankSelected: false
+selected:        false
+body:             |
+  ; CHECK-LABEL: name: legalized_sym
+  ; CHECK:      %[[ONE:[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; CHECK-NEXT: %[[TWO:[0-9]+]]:gpr(s32) = G_ADD %[[ONE]], %[[ONE]]
+  ; CHECK-NEXT: %[[SUM:[0-9]+]]:_(s32) = G_ADD %[[TWO]], %[[TWO]]
+  ; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s32)
+  ; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
+  bb.0:
+    %0:_(s32) = G_CONSTANT i32 1
+    %1:gpr(s32) = G_ADD %0, %0
+    %2:_(s32) = G_ADD %0, %0
+    %3:_(s32) = G_ADD %1, %2
+    %w0 = COPY %3(s32)
+    RET_ReallyLR implicit %w0
+...
+---
+name:            int_extensions
+alignment:       2
+legalized:       false
+regBankSelected: false
+selected:        false
+body:             |
+  ; CHECK-LABEL: name: int_extensions
+  ; CHECK:      %[[ONE:[0-9]+]]:_(s8) = G_CONSTANT i8 1
+  ; CHECK-NEXT: %[[S16:[0-9]+]]:_(s16) = G_SEXT %[[ONE]](s8)
+  ; CHECK-NEXT: %[[S32:[0-9]+]]:_(s32) = G_SEXT %[[ONE]](s8)
+  ; CHECK-NEXT: %[[S16_Z64:[0-9]+]]:_(s64) = G_ZEXT %[[S16]](s16)
+  ; CHECK-NEXT: %[[S32_Z64:[0-9]+]]:_(s64) = G_ZEXT %[[S32]](s32)
+  ; CHECK-NEXT: %[[SUM:[0-9]+]]:_(s64) = G_ADD %[[S16_Z64]], %[[S32_Z64]]
+  ; CHECK-NEXT: %[[RET:[wx][0-9]+]] = COPY %[[SUM]](s64)
+  ; CHECK-NEXT: RET_ReallyLR implicit %[[RET]]
+  bb.0.entry:
+    %0:_(s8) = G_CONSTANT i8 1
+    %1:_(s16) = G_SEXT %0(s8)
+    %2:_(s32) = G_SEXT %0(s8)
+    %3:_(s64) = G_ZEXT %1(s16)
+    %4:_(s64) = G_ZEXT %2(s32)
+    %5:_(s64) = G_ADD %3, %4
+    %x0 = COPY %5(s64)
+    RET_ReallyLR implicit %x0
+...
+---
+name:            generic
+legalized:       true
+regBankSelected: false
+selected:        false
+body:             |
+  ; CHECK-LABEL: name: generic
+  ; CHECK:      %[[SG:[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, %{{[0-9]+}}
+  ; CHECK-NEXT: %{{[0-9]+}}:_(s32) = G_ADD %[[SG]], %[[SG]]
+  bb.0:
+    %0:_(s32) = COPY %w0
+    %1:_(s32) = COPY %w1
+    %2:_(s32) = G_ADD %0, %1
+    %3:_(s32) = COPY %2(s32)
+    %4:_(s32) = G_ADD %3, %3
+    %w0 = COPY %4(s32)
+    RET_ReallyLR implicit %w0
+...
+---
+name:            generic_to_concrete_copy
+legalized:       true
+regBankSelected: false
+selected:        false
+body:             |
+  ; CHECK-LABEL: name: generic_to_concrete_copy
+  ; CHECK:      %[[S1:[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, %{{[0-9]+}}
+  ; CHECK-NEXT: %[[S2:[0-9]+]]:gpr32 = COPY %[[S1]](s32)
+  ; CHECK-NEXT: %{{[0-9]+}}:gpr32 = ADDWrr %[[S2]], %[[S2]]
+  bb.0:
+    %0:_(s32) = COPY %w0
+    %1:_(s32) = COPY %w1
+    %2:_(s32) = G_ADD %0, %1
+    %3:gpr32 = COPY %2(s32)
+    %4:gpr32 = ADDWrr %3, %3
+    %w0 = COPY %4
+    RET_ReallyLR implicit %w0
+...
+---
+name:            concrete_to_generic_copy
+legalized:       true
+regBankSelected: false
+selected:        false
+body:             |
+  ; CHECK-LABEL: name: concrete_to_generic_copy
+  ; CHECK:      %[[S1:[0-9]+]]:gpr32 = ADDWrr %{{[0-9]+}}, %{{[0-9]+}}
+  ; CHECK-NEXT: %[[S2:[0-9]+]]:_(s32) = COPY %[[S1]]
+  ; CHECK-NEXT: %{{[0-9]+}}:_(s32) = G_ADD %[[S2]], %[[S2]]
+  bb.0:
+    %0:gpr32 = COPY %w0
+    %1:gpr32 = COPY %w1
+    %2:gpr32 = ADDWrr %0, %1
+    %3:_(s32) = COPY %2
+    %4:_(s32) = G_ADD %3, %3
+    %w0 = COPY %4(s32)
+    RET_ReallyLR implicit %w0
+...
+---
+name:            concrete
+legalized:       true
+regBankSelected: false
+selected:        false
+body:             |
+  ; CHECK-LABEL: name: concrete
+  ; CHECK:      %[[SC:[0-9]+]]:gpr32 = ADDWrr %{{[0-9]+}}, %{{[0-9]+}}
+  ; CHECK-NEXT: %{{[0-9]+}}:gpr32 = ADDWrr %[[SC]], %[[SC]]
+  bb.0:
+    %0:gpr32 = COPY %w0
+    %1:gpr32 = COPY %w1
+    %2:gpr32 = ADDWrr %0, %1
+    %3:gpr32 = COPY %2
+    %4:gpr32 = ADDWrr %3, %3
+    %w0 = COPY %4
+    RET_ReallyLR implicit %w0
+...