[llvm] [MachineCSE] Expose dependent expressions during PRE (PR #226510)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 07:46:18 PDT 2026


https://github.com/Jinlock9 created https://github.com/llvm/llvm-project/pull/226510

Eliminate eligible common expressions during PRE so dependent chains introduced by instruction selection can be recognized in the same traversal.

Keep the actual hoisted representative in PREMap and rekey affected users before substituting registers. Preserve convergence, profitability, and register-constraint checks, and leave candidates with physical register operands to ordinary CSE.

Add focused MIR coverage and end-to-end RISC-V division/remainder tests that survive the O2 IR pipeline.

Related to #129516.

Assisted-by: OpenAI Codex

>From 60d8dc7fceec3393114b45bcbd7365bd0fd10717 Mon Sep 17 00:00:00 2001
From: Jinlock Choi <jinlock99 at gmail.com>
Date: Fri, 25 Sep 2026 22:31:28 +0800
Subject: [PATCH] [MachineCSE] Expose dependent expressions during PRE

Eliminate eligible common expressions during PRE so dependent chains
introduced by instruction selection can be recognized in the same
traversal.

Keep the actual hoisted representative in PREMap and rekey affected
users before substituting registers. Preserve convergence,
profitability, and register-constraint checks, and leave candidates
with physical register operands to ordinary CSE.

Add focused MIR coverage and end-to-end RISC-V division/remainder
tests that survive the O2 IR pipeline.

Related to #129516.

Assisted-by: OpenAI Codex
---
 llvm/lib/CodeGen/MachineCSE.cpp               |  67 +-
 .../RISCV/machine-cse-dependent-pre.ll        |  92 ++
 .../RISCV/machine-cse-dependent-pre.mir       | 786 ++++++++++++++++++
 3 files changed, 939 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/machine-cse-dependent-pre.ll
 create mode 100644 llvm/test/CodeGen/RISCV/machine-cse-dependent-pre.mir

diff --git a/llvm/lib/CodeGen/MachineCSE.cpp b/llvm/lib/CodeGen/MachineCSE.cpp
index 23ddccbdacd7a..b8d26e88263d5 100644
--- a/llvm/lib/CodeGen/MachineCSE.cpp
+++ b/llvm/lib/CodeGen/MachineCSE.cpp
@@ -123,6 +123,7 @@ class MachineCSEImpl {
   bool PerformCSE(MachineDomTreeNode *Node);
 
   bool isPRECandidate(MachineInstr *MI, SmallSet<MCRegister, 8> &PhysRefs);
+  bool eliminatePRECandidate(MachineInstr &MI, MachineInstr &CSMI);
   bool ProcessBlockPRE(MachineDominatorTree *MDT, MachineBasicBlock *MBB);
   bool PerformSimplePRE(MachineDominatorTree *DT);
   /// Heuristics to see if it's profitable to move common computations of MBB
@@ -818,6 +819,45 @@ bool MachineCSEImpl::isPRECandidate(MachineInstr *MI,
   return true;
 }
 
+// Eliminate a PRE candidate with no physical register operands using an earlier
+// dominating representative. Propagating its result now exposes dependent
+// expressions during the same PRE traversal.
+bool MachineCSEImpl::eliminatePRECandidate(MachineInstr &MI,
+                                           MachineInstr &CSMI) {
+  assert(&MI != &CSMI && DT->dominates(&CSMI, &MI));
+  if (MI.isConvergent() && MI.getParent() != CSMI.getParent())
+    return false;
+
+  Register OldReg = MI.getOperand(0).getReg();
+  Register NewReg = CSMI.getOperand(0).getReg();
+  assert(OldReg.isVirtual() && NewReg.isVirtual());
+  if (!isProfitableToCSE(NewReg, OldReg, CSMI.getParent(), &MI) ||
+      !MRI->constrainRegAttrs(NewReg, OldReg))
+    return false;
+
+  // PREMap hashes instruction contents. Remove stored users before changing
+  // their operands. A matching entry may represent a different instruction, so
+  // check pointer identity as well as expression equality.
+  SmallVector<MachineInstr *, 16> ChangedKeys;
+  for (MachineInstr &UseMI : MRI->use_nodbg_instructions(OldReg)) {
+    auto It = PREMap.find(&UseMI);
+    if (It != PREMap.end() && It->first == &UseMI) {
+      ChangedKeys.push_back(&UseMI);
+      PREMap.erase(It);
+    }
+  }
+
+  LLVM_DEBUG(dbgs() << "PRE CSE: " << MI << "*** to: " << CSMI);
+  MRI->replaceRegWith(OldReg, NewReg);
+  MI.eraseFromParent();
+  CSMI.clearRegisterDeads(NewReg);
+  MRI->clearKillFlags(NewReg);
+  for (MachineInstr *Key : ChangedKeys)
+    PREMap.try_emplace(Key, Key->getParent());
+  ++NumCSEs;
+  return true;
+}
+
 bool MachineCSEImpl::ProcessBlockPRE(MachineDominatorTree *DT,
                                      MachineBasicBlock *MBB) {
   bool Changed = false;
@@ -835,6 +875,11 @@ bool MachineCSEImpl::ProcessBlockPRE(MachineDominatorTree *DT,
         !DT->properlyDominates(MBB, MBB1) &&
         "MBB cannot properly dominate MBB1 while DFS through dominators tree!");
     auto CMBB = DT->findNearestCommonDominator(MBB, MBB1);
+    if (CMBB == MBB1) {
+      if (PhysRefs.empty())
+        Changed |= eliminatePRECandidate(MI, *It->first);
+      continue;
+    }
     if (!CMBB->isLegalToHoistInto())
       continue;
 
@@ -884,7 +929,17 @@ bool MachineCSEImpl::ProcessBlockPRE(MachineDominatorTree *DT,
 
         NewMI.getOperand(0).setReg(NewReg);
 
-        PREMap[&MI] = CMBB;
+        // The clone's uses are not at the original kill points.
+        NewMI.clearKillInfo();
+
+        // Store the actual representative before deleting either occurrence.
+        MachineInstr *PrevMI = It->first;
+        PREMap.erase(It);
+        PREMap.try_emplace(&NewMI, CMBB);
+        if (PhysRefs.empty()) {
+          eliminatePRECandidate(*PrevMI, NewMI);
+          eliminatePRECandidate(MI, NewMI);
+        }
         ++NumPREs;
         Changed = true;
       }
@@ -893,11 +948,11 @@ bool MachineCSEImpl::ProcessBlockPRE(MachineDominatorTree *DT,
   return Changed;
 }
 
-// This simple PRE (partial redundancy elimination) pass doesn't actually
-// eliminate partial redundancy but transforms it to full redundancy,
-// anticipating that the next CSE step will eliminate this created redundancy.
-// If CSE doesn't eliminate this, than created instruction will remain dead
-// and eliminated later by Remove Dead Machine Instructions pass.
+// Transform partial redundancy into full redundancy by hoisting expressions to
+// a common dominator. For candidates without physical register operands, also
+// eliminate redundant occurrences now to expose dependent expressions. The
+// following CSE traversal handles the remaining redundancies. If a hoisted
+// instruction remains unused, dead machine instruction elimination removes it.
 bool MachineCSEImpl::PerformSimplePRE(MachineDominatorTree *DT) {
   SmallVector<MachineDomTreeNode *, 32> BBs;
 
diff --git a/llvm/test/CodeGen/RISCV/machine-cse-dependent-pre.ll b/llvm/test/CodeGen/RISCV/machine-cse-dependent-pre.ll
new file mode 100644
index 0000000000000..a64fb9abde399
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/machine-cse-dependent-pre.ll
@@ -0,0 +1,92 @@
+; RUN: llc -O2 -mtriple=riscv64 -mattr=+m -verify-machineinstrs < %s | FileCheck %s
+; RUN: opt -S -mtriple=riscv64 -passes='default<O2>' %s | \
+; RUN:   llc -O2 -mtriple=riscv64 -mattr=+m -verify-machineinstrs | FileCheck %s
+;
+; Division and remainder are distinct IR operations. Selection lowers both
+; to MULHU followed by SRLI, so MachineCSE must expose the dependent shift
+; during PRE. One invocation should share the whole sequence in the loop.
+; This case also survives the ordinary O2 IR pipeline.
+;
+define void @divrem_loop(ptr %input, ptr %quotients, ptr %remainders, i64 %n) {
+; CHECK-LABEL: divrem_loop:
+; CHECK-NOT: mulhu
+; CHECK-NOT: srli
+; CHECK: mulhu [[HIGH:[a-z][a-z0-9]*]],
+; CHECK-NOT: mulhu
+; CHECK-NOT: srli
+; CHECK: srli {{[a-z][a-z0-9]*}}, [[HIGH]], 3
+; CHECK-NOT: mulhu
+; CHECK-NOT: srli
+; CHECK: .Lfunc_end{{[0-9]+}}:
+entry:
+  %empty = icmp eq i64 %n, 0
+  br i1 %empty, label %exit, label %loop
+loop:
+  %i = phi i64 [ 0, %entry ], [ %next, %latch ]
+  %ip = getelementptr i64, ptr %input, i64 %i
+  %x = load i64, ptr %ip, align 8
+  %bit = and i64 %x, 1
+  %cond = icmp eq i64 %bit, 0
+  br i1 %cond, label %then, label %else
+then:
+  %q = udiv i64 %x, 10
+  %qp = getelementptr i64, ptr %quotients, i64 %i
+  store i64 %q, ptr %qp, align 8
+  br label %latch
+else:
+  %r = urem i64 %x, 10
+  %rp = getelementptr i64, ptr %remainders, i64 %i
+  store i64 %r, ptr %rp, align 8
+  br label %latch
+latch:
+  %next = add i64 %i, 1
+  %done = icmp eq i64 %next, %n
+  br i1 %done, label %exit, label %loop
+exit:
+  ret void
+}
+
+; A deeper lowering needs three rounds of the original PRE/CSE sequence:
+; SRLI x, 3 -> MULHU -> SRLI high, 4. Expose all three levels in one traversal.
+; Quotient and remainder are distinct IR operations with a common lowering.
+define void @divrem_1000_loop(ptr %input, ptr %quotients, ptr %remainders, i64 %n) {
+; CHECK-LABEL: divrem_1000_loop:
+; CHECK-NOT: mulhu
+; CHECK-NOT: srli
+; CHECK: srli [[INPUT:[a-z][a-z0-9]*]], {{[a-z][a-z0-9]*}}, 3
+; CHECK-NOT: mulhu
+; CHECK-NOT: srli
+; CHECK: mulhu [[HIGH:[a-z][a-z0-9]*]], [[INPUT]],
+; CHECK-NOT: mulhu
+; CHECK-NOT: srli
+; CHECK: srli {{[a-z][a-z0-9]*}}, [[HIGH]], 4
+; CHECK-NOT: mulhu
+; CHECK-NOT: srli
+; CHECK: .Lfunc_end{{[0-9]+}}:
+entry:
+  %empty = icmp eq i64 %n, 0
+  br i1 %empty, label %exit, label %loop
+loop:
+  %i = phi i64 [ 0, %entry ], [ %next, %latch ]
+  %ip = getelementptr i64, ptr %input, i64 %i
+  %x = load i64, ptr %ip, align 8
+  %bit = and i64 %x, 1
+  %cond = icmp eq i64 %bit, 0
+  br i1 %cond, label %then, label %else
+then:
+  %q = udiv i64 %x, 1000
+  %qp = getelementptr i64, ptr %quotients, i64 %i
+  store i64 %q, ptr %qp, align 8
+  br label %latch
+else:
+  %r = urem i64 %x, 1000
+  %rp = getelementptr i64, ptr %remainders, i64 %i
+  store i64 %r, ptr %rp, align 8
+  br label %latch
+latch:
+  %next = add i64 %i, 1
+  %done = icmp eq i64 %next, %n
+  br i1 %done, label %exit, label %loop
+exit:
+  ret void
+}
diff --git a/llvm/test/CodeGen/RISCV/machine-cse-dependent-pre.mir b/llvm/test/CodeGen/RISCV/machine-cse-dependent-pre.mir
new file mode 100644
index 0000000000000..c015a8b8deccb
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/machine-cse-dependent-pre.mir
@@ -0,0 +1,786 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=riscv64 -run-pass=machine-cse -verify-machineinstrs %s -o - | FileCheck %s
+
+# Retain the IR CFG and named MIR blocks: simple PRE currently uses IR
+# reachability to distinguish partial redundancy from an acyclic diamond.
+--- |
+  define i64 @dependent_chain(i1 %cond, i1 %again) {
+  entry:
+    br label %loop
+  loop:
+    br i1 %cond, label %then, label %else
+  then:
+    br label %latch
+  else:
+    br label %latch
+  latch:
+    br i1 %again, label %loop, label %exit
+  exit:
+    ret i64 0
+  }
+
+  define i64 @repeated_operand(i1 %cond, i1 %again) {
+  entry:
+    br label %loop
+  loop:
+    br i1 %cond, label %then, label %else
+  then:
+    br label %latch
+  else:
+    br label %latch
+  latch:
+    br i1 %again, label %loop, label %exit
+  exit:
+    ret i64 0
+  }
+
+  define i64 @third_occurrence(i1 %cond, i1 %again) {
+  entry:
+    br label %loop
+  loop:
+    br i1 %cond, label %then, label %else
+  then:
+    br label %latch
+  else:
+    br label %latch
+  latch:
+    br i1 %again, label %loop, label %exit
+  exit:
+    ret i64 0
+  }
+
+  define i64 @acyclic_diamond(i1 %cond, i1 %again) {
+  entry:
+    br label %loop
+  loop:
+    br i1 %cond, label %then, label %else
+  then:
+    br label %latch
+  else:
+    br label %latch
+  latch:
+    br label %exit
+  exit:
+    ret i64 0
+  }
+
+  define i64 @physical_operand(i1 %cond, i1 %again) {
+  entry:
+    br label %loop
+  loop:
+    br i1 %cond, label %then, label %else
+  then:
+    br label %latch
+  else:
+    br label %latch
+  latch:
+    br i1 %again, label %loop, label %exit
+  exit:
+    ret i64 0
+  }
+
+  define i64 @incompatible_classes(i1 %cond, i1 %again) {
+  entry:
+    br label %loop
+  loop:
+    br i1 %cond, label %then, label %else
+  then:
+    br label %latch
+  else:
+    br label %latch
+  latch:
+    br i1 %again, label %loop, label %exit
+  exit:
+    ret i64 0
+  }
+
+  define i64 @debug_users(i1 %cond, i1 %again) !dbg !5 {
+  entry:
+    br label %loop
+  loop:
+    br i1 %cond, label %then, label %else
+  then:
+    br label %latch
+  else:
+    br label %latch
+  latch:
+    br i1 %again, label %loop, label %exit
+  exit:
+    ret i64 0
+  }
+
+  define i64 @subregister_uses(i1 %cond, i1 %again) {
+  entry:
+    br label %loop
+  loop:
+    br i1 %cond, label %then, label %else
+  then:
+    br label %latch
+  else:
+    br label %latch
+  latch:
+    br i1 %again, label %loop, label %exit
+  exit:
+    ret i64 0
+  }
+
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!2}
+  !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "test", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+  !1 = !DIFile(filename: "test.c", directory: "/")
+  !2 = !{i32 2, !"Debug Info Version", i32 3}
+  !3 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed)
+  !4 = !DISubroutineType(types: !{})
+  !5 = distinct !DISubprogram(name: "debug_users", scope: !1, file: !1, line: 1, type: !4, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
+  !6 = !DILocalVariable(name: "value", scope: !5, file: !1, line: 1, type: !3)
+  !7 = !DILocation(line: 1, column: 1, scope: !5)
+
+...
+---
+# Hoist both shifts and their dependent add.
+name: dependent_chain
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: dependent_chain
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY]], %bb.0, %4, %bb.4
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %6, %bb.4
+  ; CHECK-NEXT:   [[ANDI:%[0-9]+]]:gpr = ANDI [[PHI]], 1
+  ; CHECK-NEXT:   [[SRAI:%[0-9]+]]:gpr = SRAI [[PHI]], 7
+  ; CHECK-NEXT:   [[SRAI1:%[0-9]+]]:gpr = SRAI [[COPY1]], 7
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[SRAI]], [[SRAI1]]
+  ; CHECK-NEXT:   BEQ [[ANDI]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.then:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.else:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.latch:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.5(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[ADD]], %bb.2, [[ADD]], %bb.3
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], -1
+  ; CHECK-NEXT:   BNE [[ADDI]], $x0, %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    PseudoBR %bb.1
+  bb.1.loop:
+    %3:gpr = PHI %0, %bb.0, %12, %bb.4
+    %4:gpr = PHI %2, %bb.0, %13, %bb.4
+    %5:gpr = ANDI %3, 1
+    BEQ %5, $x0, %bb.2
+    PseudoBR %bb.3
+  bb.2.then:
+    %6:gpr = SRAI %3, 7
+    %7:gpr = SRAI %1, 7
+    %8:gpr = ADD killed %6, killed %7
+    PseudoBR %bb.4
+  bb.3.else:
+    %9:gpr = SRAI %3, 7
+    %10:gpr = SRAI %1, 7
+    %11:gpr = ADD killed %9, killed %10
+    PseudoBR %bb.4
+  bb.4.latch:
+    %12:gpr = PHI %8, %bb.2, %11, %bb.3
+    %13:gpr = ADDI %4, -1
+    BNE %13, $x0, %bb.1
+    PseudoBR %bb.5
+  bb.5.exit:
+    $x10 = COPY %12
+    PseudoRET implicit $x10
+...
+---
+# Rekey a stored user with two occurrences of the same old register.
+name: repeated_operand
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: repeated_operand
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY]], %bb.0, %4, %bb.4
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %6, %bb.4
+  ; CHECK-NEXT:   [[ANDI:%[0-9]+]]:gpr = ANDI [[PHI]], 1
+  ; CHECK-NEXT:   [[SRAI:%[0-9]+]]:gpr = SRAI [[PHI]], 7
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[SRAI]], [[SRAI]]
+  ; CHECK-NEXT:   BEQ [[ANDI]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.then:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.else:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.latch:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.5(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[ADD]], %bb.2, [[ADD]], %bb.3
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], -1
+  ; CHECK-NEXT:   BNE [[ADDI]], $x0, %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    PseudoBR %bb.1
+  bb.1.loop:
+    %3:gpr = PHI %0, %bb.0, %12, %bb.4
+    %4:gpr = PHI %2, %bb.0, %13, %bb.4
+    %5:gpr = ANDI %3, 1
+    BEQ %5, $x0, %bb.2
+    PseudoBR %bb.3
+  bb.2.then:
+    %6:gpr = SRAI %3, 7
+    %8:gpr = ADD %6, %6
+    PseudoBR %bb.4
+  bb.3.else:
+    %9:gpr = SRAI %3, 7
+    %11:gpr = ADD %9, %9
+    PseudoBR %bb.4
+  bb.4.latch:
+    %12:gpr = PHI %8, %bb.2, %11, %bb.3
+    %13:gpr = ADDI %4, -1
+    BNE %13, $x0, %bb.1
+    PseudoBR %bb.5
+  bb.5.exit:
+    $x10 = COPY %12
+    PseudoRET implicit $x10
+...
+---
+# Reuse the actual hoisted representative for a third occurrence.
+name: third_occurrence
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: third_occurrence
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY]], %bb.0, %4, %bb.4
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %6, %bb.4
+  ; CHECK-NEXT:   [[ANDI:%[0-9]+]]:gpr = ANDI [[PHI]], 1
+  ; CHECK-NEXT:   [[SRAI:%[0-9]+]]:gpr = SRAI [[PHI]], 7
+  ; CHECK-NEXT:   [[SRAI1:%[0-9]+]]:gpr = SRAI [[COPY1]], 7
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[SRAI]], [[SRAI1]]
+  ; CHECK-NEXT:   BEQ [[ANDI]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.then:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.else:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.latch:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.5(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[ADD]], %bb.2, [[ADD]], %bb.3
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], -1
+  ; CHECK-NEXT:   BNE [[ADDI]], $x0, %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[ADD]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    PseudoBR %bb.1
+  bb.1.loop:
+    %3:gpr = PHI %0, %bb.0, %12, %bb.4
+    %4:gpr = PHI %2, %bb.0, %13, %bb.4
+    %5:gpr = ANDI %3, 1
+    BEQ %5, $x0, %bb.2
+    PseudoBR %bb.3
+  bb.2.then:
+    %6:gpr = SRAI %3, 7
+    %7:gpr = SRAI %1, 7
+    %8:gpr = ADD killed %6, killed %7
+    PseudoBR %bb.4
+  bb.3.else:
+    %9:gpr = SRAI %3, 7
+    %10:gpr = SRAI %1, 7
+    %11:gpr = ADD killed %9, killed %10
+    PseudoBR %bb.4
+  bb.4.latch:
+    %12:gpr = PHI %8, %bb.2, %11, %bb.3
+    %14:gpr = SRAI %3, 7
+    %15:gpr = SRAI %1, 7
+    %16:gpr = ADD killed %14, killed %15
+    %13:gpr = ADDI %4, -1
+    BNE %13, $x0, %bb.1
+    PseudoBR %bb.5
+  bb.5.exit:
+    $x10 = COPY %16
+    PseudoRET implicit $x10
+...
+---
+# Preserve the existing reachability restriction on PRE.
+name: acyclic_diamond
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: acyclic_diamond
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY]], %bb.0
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0
+  ; CHECK-NEXT:   [[ANDI:%[0-9]+]]:gpr = ANDI [[PHI]], 1
+  ; CHECK-NEXT:   BEQ [[ANDI]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.then:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SRAI:%[0-9]+]]:gpr = SRAI [[PHI]], 7
+  ; CHECK-NEXT:   [[SRAI1:%[0-9]+]]:gpr = SRAI [[COPY1]], 7
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD killed [[SRAI]], killed [[SRAI1]]
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.else:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SRAI2:%[0-9]+]]:gpr = SRAI [[PHI]], 7
+  ; CHECK-NEXT:   [[SRAI3:%[0-9]+]]:gpr = SRAI [[COPY1]], 7
+  ; CHECK-NEXT:   [[ADD1:%[0-9]+]]:gpr = ADD killed [[SRAI2]], killed [[SRAI3]]
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.latch:
+  ; CHECK-NEXT:   successors: %bb.5(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[ADD]], %bb.2, [[ADD1]], %bb.3
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], -1
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    PseudoBR %bb.1
+  bb.1.loop:
+    %3:gpr = PHI %0, %bb.0
+    %4:gpr = PHI %2, %bb.0
+    %5:gpr = ANDI %3, 1
+    BEQ %5, $x0, %bb.2
+    PseudoBR %bb.3
+  bb.2.then:
+    %6:gpr = SRAI %3, 7
+    %7:gpr = SRAI %1, 7
+    %8:gpr = ADD killed %6, killed %7
+    PseudoBR %bb.4
+  bb.3.else:
+    %9:gpr = SRAI %3, 7
+    %10:gpr = SRAI %1, 7
+    %11:gpr = ADD killed %9, killed %10
+    PseudoBR %bb.4
+  bb.4.latch:
+    %12:gpr = PHI %8, %bb.2, %11, %bb.3
+    %13:gpr = ADDI %4, -1
+    PseudoBR %bb.5
+  bb.5.exit:
+    $x10 = COPY %12
+    PseudoRET implicit $x10
+...
+---
+# Leave physical-register candidates to the ordinary CSE traversal.
+name: physical_operand
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: physical_operand
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY]], %bb.0, %4, %bb.4
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %6, %bb.4
+  ; CHECK-NEXT:   [[ANDI:%[0-9]+]]:gpr = ANDI [[PHI]], 1
+  ; CHECK-NEXT:   [[SRAI:%[0-9]+]]:gpr = SRAI $x0, 7
+  ; CHECK-NEXT:   [[SRAI1:%[0-9]+]]:gpr = SRAI [[COPY1]], 7
+  ; CHECK-NEXT:   BEQ [[ANDI]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.then:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[SRAI]], [[SRAI1]]
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.else:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADD1:%[0-9]+]]:gpr = ADD [[SRAI]], [[SRAI1]]
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.latch:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.5(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[ADD]], %bb.2, [[ADD1]], %bb.3
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], -1
+  ; CHECK-NEXT:   BNE [[ADDI]], $x0, %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    PseudoBR %bb.1
+  bb.1.loop:
+    %3:gpr = PHI %0, %bb.0, %12, %bb.4
+    %4:gpr = PHI %2, %bb.0, %13, %bb.4
+    %5:gpr = ANDI %3, 1
+    BEQ %5, $x0, %bb.2
+    PseudoBR %bb.3
+  bb.2.then:
+    %6:gpr = SRAI $x0, 7
+    %7:gpr = SRAI %1, 7
+    %8:gpr = ADD killed %6, killed %7
+    PseudoBR %bb.4
+  bb.3.else:
+    %9:gpr = SRAI $x0, 7
+    %10:gpr = SRAI %1, 7
+    %11:gpr = ADD killed %9, killed %10
+    PseudoBR %bb.4
+  bb.4.latch:
+    %12:gpr = PHI %8, %bb.2, %11, %bb.3
+    %13:gpr = ADDI %4, -1
+    BNE %13, $x0, %bb.1
+    PseudoBR %bb.5
+  bb.5.exit:
+    $x10 = COPY %12
+    PseudoRET implicit $x10
+...
+---
+# Do not substitute results with incompatible register classes.
+name: incompatible_classes
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: incompatible_classes
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY]], %bb.0, %4, %bb.4
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %6, %bb.4
+  ; CHECK-NEXT:   [[ANDI:%[0-9]+]]:gpr = ANDI [[PHI]], 1
+  ; CHECK-NEXT:   [[SRAI:%[0-9]+]]:gprc = SRAI [[PHI]], 7
+  ; CHECK-NEXT:   [[SRAI1:%[0-9]+]]:gpr = SRAI [[COPY1]], 7
+  ; CHECK-NEXT:   BEQ [[ANDI]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.then:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[SRAI]], [[SRAI1]]
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.else:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SRAI2:%[0-9]+]]:gprx7 = SRAI [[PHI]], 7
+  ; CHECK-NEXT:   [[ADD1:%[0-9]+]]:gpr = ADD killed [[SRAI2]], [[SRAI1]]
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.latch:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.5(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[ADD]], %bb.2, [[ADD1]], %bb.3
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], -1
+  ; CHECK-NEXT:   BNE [[ADDI]], $x0, %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    PseudoBR %bb.1
+  bb.1.loop:
+    %3:gpr = PHI %0, %bb.0, %12, %bb.4
+    %4:gpr = PHI %2, %bb.0, %13, %bb.4
+    %5:gpr = ANDI %3, 1
+    BEQ %5, $x0, %bb.2
+    PseudoBR %bb.3
+  bb.2.then:
+    %6:gprc = SRAI %3, 7
+    %7:gpr = SRAI %1, 7
+    %8:gpr = ADD killed %6, killed %7
+    PseudoBR %bb.4
+  bb.3.else:
+    %9:gprx7 = SRAI %3, 7
+    %10:gpr = SRAI %1, 7
+    %11:gpr = ADD killed %9, killed %10
+    PseudoBR %bb.4
+  bb.4.latch:
+    %12:gpr = PHI %8, %bb.2, %11, %bb.3
+    %13:gpr = ADDI %4, -1
+    BNE %13, $x0, %bb.1
+    PseudoBR %bb.5
+  bb.5.exit:
+    $x10 = COPY %12
+    PseudoRET implicit $x10
+...
+---
+# Rewrite debug register uses and drop the source location on hoisted clones.
+name: debug_users
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: debug_users
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY]], %bb.0, %4, %bb.4
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %6, %bb.4
+  ; CHECK-NEXT:   [[ANDI:%[0-9]+]]:gpr = ANDI [[PHI]], 1
+  ; CHECK-NEXT:   [[SRAI:%[0-9]+]]:gpr = SRAI [[PHI]], 7
+  ; CHECK-NEXT:   [[SRAI1:%[0-9]+]]:gpr = SRAI [[COPY1]], 7
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[SRAI]], [[SRAI1]]
+  ; CHECK-NEXT:   BEQ [[ANDI]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.then:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   DBG_VALUE [[SRAI]], $noreg, !6, !DIExpression(), debug-location !DILocation(line: 1, column: 1, scope: !3)
+  ; CHECK-NEXT:   DBG_VALUE [[ADD]], $noreg, !6, !DIExpression(), debug-location !DILocation(line: 1, column: 1, scope: !3)
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.else:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   DBG_VALUE [[SRAI]], $noreg, !6, !DIExpression(), debug-location !DILocation(line: 1, column: 1, scope: !3)
+  ; CHECK-NEXT:   DBG_VALUE [[ADD]], $noreg, !6, !DIExpression(), debug-location !DILocation(line: 1, column: 1, scope: !3)
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.latch:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.5(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[ADD]], %bb.2, [[ADD]], %bb.3
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], -1
+  ; CHECK-NEXT:   BNE [[ADDI]], $x0, %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    PseudoBR %bb.1
+  bb.1.loop:
+    %3:gpr = PHI %0, %bb.0, %12, %bb.4
+    %4:gpr = PHI %2, %bb.0, %13, %bb.4
+    %5:gpr = ANDI %3, 1
+    BEQ %5, $x0, %bb.2
+    PseudoBR %bb.3
+  bb.2.then:
+    %6:gpr = SRAI %3, 7, debug-location !7
+    DBG_VALUE %6, $noreg, !6, !DIExpression(), debug-location !7
+    %7:gpr = SRAI %1, 7
+    %8:gpr = ADD killed %6, killed %7, debug-location !7
+    DBG_VALUE %8, $noreg, !6, !DIExpression(), debug-location !7
+    PseudoBR %bb.4
+  bb.3.else:
+    %9:gpr = SRAI %3, 7, debug-location !7
+    DBG_VALUE %9, $noreg, !6, !DIExpression(), debug-location !7
+    %10:gpr = SRAI %1, 7
+    %11:gpr = ADD killed %9, killed %10, debug-location !7
+    DBG_VALUE %11, $noreg, !6, !DIExpression(), debug-location !7
+    PseudoBR %bb.4
+  bb.4.latch:
+    %12:gpr = PHI %8, %bb.2, %11, %bb.3
+    %13:gpr = ADDI %4, -1
+    BNE %13, $x0, %bb.1
+    PseudoBR %bb.5
+  bb.5.exit:
+    $x10 = COPY %12
+    PseudoRET implicit $x10
+...
+---
+# Preserve subregister indices when rewriting uses of eliminated results.
+name: subregister_uses
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: subregister_uses
+  ; CHECK: bb.0.entry:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $x10
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $x11
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $x12
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1.loop:
+  ; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:gpr = PHI [[COPY]], %bb.0, %4, %bb.4
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:gpr = PHI [[COPY2]], %bb.0, %6, %bb.4
+  ; CHECK-NEXT:   [[ANDI:%[0-9]+]]:gpr = ANDI [[PHI]], 1
+  ; CHECK-NEXT:   [[SRAI:%[0-9]+]]:gpr = SRAI [[PHI]], 7
+  ; CHECK-NEXT:   [[SRAI1:%[0-9]+]]:gpr = SRAI [[COPY1]], 7
+  ; CHECK-NEXT:   [[ADD:%[0-9]+]]:gpr = ADD [[SRAI]], [[SRAI1]]
+  ; CHECK-NEXT:   BEQ [[ANDI]], $x0, %bb.2
+  ; CHECK-NEXT:   PseudoBR %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2.then:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gprf32 = COPY [[SRAI]].sub_32
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3.else:
+  ; CHECK-NEXT:   successors: %bb.4(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gprf32 = COPY [[SRAI]].sub_32
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4.latch:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.5(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI2:%[0-9]+]]:gpr = PHI [[ADD]], %bb.2, [[ADD]], %bb.3
+  ; CHECK-NEXT:   [[ADDI:%[0-9]+]]:gpr = ADDI [[PHI1]], -1
+  ; CHECK-NEXT:   BNE [[ADDI]], $x0, %bb.1
+  ; CHECK-NEXT:   PseudoBR %bb.5
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5.exit:
+  ; CHECK-NEXT:   $x10 = COPY [[PHI2]]
+  ; CHECK-NEXT:   PseudoRET implicit $x10
+  bb.0.entry:
+    liveins: $x10, $x11, $x12
+    %0:gpr = COPY $x10
+    %1:gpr = COPY $x11
+    %2:gpr = COPY $x12
+    PseudoBR %bb.1
+  bb.1.loop:
+    %3:gpr = PHI %0, %bb.0, %12, %bb.4
+    %4:gpr = PHI %2, %bb.0, %13, %bb.4
+    %5:gpr = ANDI %3, 1
+    BEQ %5, $x0, %bb.2
+    PseudoBR %bb.3
+  bb.2.then:
+    %6:gpr = SRAI %3, 7
+    %14:gprf32 = COPY %6.sub_32
+    %7:gpr = SRAI %1, 7
+    %8:gpr = ADD killed %6, killed %7
+    PseudoBR %bb.4
+  bb.3.else:
+    %9:gpr = SRAI %3, 7
+    %15:gprf32 = COPY %9.sub_32
+    %10:gpr = SRAI %1, 7
+    %11:gpr = ADD killed %9, killed %10
+    PseudoBR %bb.4
+  bb.4.latch:
+    %12:gpr = PHI %8, %bb.2, %11, %bb.3
+    %13:gpr = ADDI %4, -1
+    BNE %13, $x0, %bb.1
+    PseudoBR %bb.5
+  bb.5.exit:
+    $x10 = COPY %12
+    PseudoRET implicit $x10
+...



More information about the llvm-commits mailing list