[llvm] [ARM] Port Redundant Copy Elimination to ARM (PR #203706)

via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 13 08:05:32 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-arm

Author: mike-goutokuji (mike-goutokuji)

<details>
<summary>Changes</summary>

Based off AArch64's and RISC-V's version.

---

Patch is 39.89 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/203706.diff


15 Files Affected:

- (modified) llvm/lib/Target/ARM/ARM.h (+9) 
- (modified) llvm/lib/Target/ARM/ARMPassRegistry.def (+1) 
- (added) llvm/lib/Target/ARM/ARMRedundantCopyElimination.cpp (+613) 
- (modified) llvm/lib/Target/ARM/ARMTargetMachine.cpp (+11) 
- (modified) llvm/lib/Target/ARM/CMakeLists.txt (+1) 
- (modified) llvm/test/CodeGen/ARM/O3-pipeline.ll (+1) 
- (modified) llvm/test/CodeGen/ARM/arm-shrink-wrapping.ll (-4) 
- (modified) llvm/test/CodeGen/ARM/code-placement.ll (+2-2) 
- (added) llvm/test/CodeGen/ARM/machine-copy-remove.mir (+186) 
- (modified) llvm/test/CodeGen/ARM/v8m-tail-call.ll (+2-2) 
- (modified) llvm/test/CodeGen/Thumb/thumb-shrink-wrapping.ll (-4) 
- (modified) llvm/test/CodeGen/Thumb2/LowOverheadLoops/reductions.ll (-1) 
- (modified) llvm/test/CodeGen/Thumb2/mve-blockplacement.ll (+5-10) 
- (modified) llvm/test/CodeGen/Thumb2/mve-memtp-branch.ll (+8-16) 
- (modified) llvm/test/CodeGen/Thumb2/outlined-fn-may-clobber-lr-in-caller.ll (-1) 


``````````diff
diff --git a/llvm/lib/Target/ARM/ARM.h b/llvm/lib/Target/ARM/ARM.h
index 08caef8419d12..59533ba3a941e 100644
--- a/llvm/lib/Target/ARM/ARM.h
+++ b/llvm/lib/Target/ARM/ARM.h
@@ -58,6 +58,7 @@ FunctionPass *createARMSLSHardeningPass();
 FunctionPass *createARMIndirectThunks();
 Pass *createMVELaneInterleavingPass();
 FunctionPass *createARMFixCortexA57AES1742098Pass();
+FunctionPass *createARMRedundantCopyEliminationPass();
 
 void LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
                                   ARMAsmPrinter &AP);
@@ -81,6 +82,7 @@ void initializeMVETailPredicationPass(PassRegistry &);
 void initializeMVEVPTBlockPass(PassRegistry &);
 void initializeThumb2ITBlockPass(PassRegistry &);
 void initializeThumb2SizeReducePass(PassRegistry &);
+void initializeARMRedundantCopyEliminationPass(PassRegistry &);
 
 class ARMPreAllocLoadStoreOptPass
     : public OptionalPassInfoMixin<ARMPreAllocLoadStoreOptPass> {
@@ -95,6 +97,13 @@ class ARMLoadStoreOptPass : public OptionalPassInfoMixin<ARMLoadStoreOptPass> {
                         MachineFunctionAnalysisManager &MFAM);
 };
 
+class ARMRedundantCopyEliminationPass
+    : public OptionalPassInfoMixin<ARMRedundantCopyEliminationPass> {
+public:
+  PreservedAnalyses run(MachineFunction &MF,
+                        MachineFunctionAnalysisManager &MFAM);
+};
+
 } // end namespace llvm
 
 #endif // LLVM_LIB_TARGET_ARM_ARM_H
diff --git a/llvm/lib/Target/ARM/ARMPassRegistry.def b/llvm/lib/Target/ARM/ARMPassRegistry.def
index 968411531182b..51bf43c8f9b2f 100644
--- a/llvm/lib/Target/ARM/ARMPassRegistry.def
+++ b/llvm/lib/Target/ARM/ARMPassRegistry.def
@@ -28,4 +28,5 @@
 #endif
 MACHINE_FUNCTION_PASS("arm-ldst-opt", ARMLoadStoreOptPass())
 MACHINE_FUNCTION_PASS("arm-prera-ldst-opt", ARMPreAllocLoadStoreOptPass())
+MACHINE_FUNCTION_PASS("arm-copyelim", ARMRedundantCopyEliminationPass())
 #undef MACHINE_FUNCTION_PASS
diff --git a/llvm/lib/Target/ARM/ARMRedundantCopyElimination.cpp b/llvm/lib/Target/ARM/ARMRedundantCopyElimination.cpp
new file mode 100644
index 0000000000000..f3f0a69e21c7b
--- /dev/null
+++ b/llvm/lib/Target/ARM/ARMRedundantCopyElimination.cpp
@@ -0,0 +1,613 @@
+//=- ARMRedundantCopyElimination.cpp - Remove useless copy for ARM -=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// This pass removes unnecessary copies/moves in BBs based on a dominating
+// condition.
+//
+// We handle four cases:
+// 1. For BBs that are targets of tCBZ/tCBNZ instructions, we know the value of
+//    the source register is zero on the taken/not-taken path.
+// 2. If a CPSR-setting instruction defines a GPR, we can remove a redundant
+//    zero move on the appropriate conditional path.
+// 3. If the CPSR-setting instruction is a comparison against a constant, we can
+//    remove a redundant move immediate on the appropriate path.
+// 4. If the CPSR-setting instruction is a register comparison, we can remove a
+//    redundant copy/move between the compared registers on the EQ path.
+//
+// This pass should be run after register allocation.
+//
+// FIXME: This could also be extended to check the whole dominance subtree below
+// the comparison if the compile time regression is acceptable.
+//
+//===----------------------------------------------------------------------===//
+#include "ARM.h"
+#include "ARMBaseInstrInfo.h"
+#include "Utils/ARMBaseInfo.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/CodeGen/LiveRegUnits.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "arm-copyelim"
+
+STATISTIC(NumCopiesRemoved, "Number of copies removed.");
+
+struct RegImm {
+  MCPhysReg Reg;
+  int32_t Imm;
+  RegImm(MCPhysReg Reg, int32_t Imm) : Reg(Reg), Imm(Imm) {}
+};
+
+struct RegEqual {
+  MCPhysReg Reg1;
+  MCPhysReg Reg2;
+  RegEqual(MCPhysReg Reg1, MCPhysReg Reg2) : Reg1(Reg1), Reg2(Reg2) {}
+};
+
+namespace {
+class ARMRedundantCopyEliminationImpl {
+public:
+  bool run(MachineFunction &MF);
+
+private:
+  const MachineRegisterInfo *MRI;
+  const TargetRegisterInfo *TRI;
+  const TargetInstrInfo *TII;
+
+  LiveRegUnits DomBBClobberedRegs, DomBBUsedRegs;
+  LiveRegUnits OptBBClobberedRegs, OptBBUsedRegs;
+
+  bool getCBZKnownRegs(MachineInstr &CondBr, MachineBasicBlock *MBB,
+                       SmallVectorImpl<RegImm> &KnownRegs,
+                       MachineBasicBlock::iterator &FirstUse);
+  bool knownRegValInBlock(MachineInstr &CondBr, MachineBasicBlock *MBB,
+                          SmallVectorImpl<RegImm> &KnownRegs,
+                          SmallVectorImpl<RegEqual> &KnownEqualRegs,
+                          MachineBasicBlock::iterator &FirstUse);
+  bool optimizeBlock(MachineBasicBlock *MBB);
+};
+
+class ARMRedundantCopyElimination : public MachineFunctionPass {
+public:
+  static char ID;
+  ARMRedundantCopyElimination() : MachineFunctionPass(ID) {}
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+  MachineFunctionProperties getRequiredProperties() const override {
+    return MachineFunctionProperties().setNoVRegs();
+  }
+  StringRef getPassName() const override {
+    return "ARM Redundant Copy Elimination";
+  }
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesCFG();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+};
+
+char ARMRedundantCopyElimination::ID = 0;
+
+} // end anonymous namespace
+
+INITIALIZE_PASS(ARMRedundantCopyElimination, "arm-copyelim",
+                "ARM Redundant Copy Elimination", false, false)
+
+static bool isCompareImm(const MachineInstr &MI, MCPhysReg &SrcReg,
+                         int32_t &Imm) {
+  switch (MI.getOpcode()) {
+  case ARM::CMPri:
+  case ARM::t2CMPri:
+  case ARM::tCMPi8:
+    SrcReg = MI.getOperand(0).getReg();
+    Imm = MI.getOperand(1).getImm();
+    return true;
+  case ARM::CMNri:
+  case ARM::t2CMNri:
+    SrcReg = MI.getOperand(0).getReg();
+    Imm = -MI.getOperand(1).getImm();
+    return true;
+  default:
+    return false;
+  }
+}
+
+static bool isCompareReg(const MachineInstr &MI, MCPhysReg &Rn, MCPhysReg &Rm) {
+  switch (MI.getOpcode()) {
+  case ARM::CMPrr:
+  case ARM::t2CMPrr:
+  case ARM::tCMPr:
+  case ARM::tCMPhir:
+    Rn = MI.getOperand(0).getReg();
+    Rm = MI.getOperand(1).getReg();
+    return true;
+  default:
+    return false;
+  }
+}
+
+static bool isFlagSettingAluWithDest(const MachineInstr &MI) {
+  if (!MI.definesRegister(ARM::CPSR, /*TRI=*/nullptr))
+    return false;
+  if (MI.getNumOperands() == 0 || !MI.getOperand(0).isReg())
+    return false;
+  return MI.getOperand(0).isDef();
+}
+
+static bool isKnownZeroSource(const MachineInstr &MI,
+                              ArrayRef<RegImm> KnownRegs) {
+  if (MI.getNumOperands() < 2 || !MI.getOperand(1).isReg())
+    return false;
+  MCPhysReg SrcReg = MI.getOperand(1).getReg();
+  for (const RegImm &KnownReg : KnownRegs) {
+    if (KnownReg.Imm == 0 && KnownReg.Reg == SrcReg)
+      return true;
+  }
+  return false;
+}
+
+static bool getMoveImmediateValue(const MachineInstr &MI, int64_t &ImmVal) {
+  for (const MachineOperand &MO : MI.operands()) {
+    if (MO.isImm()) {
+      ImmVal = MO.getImm();
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool isRedundantZeroAssign(const MachineInstr &MI, MCPhysReg DefReg,
+                                  ArrayRef<RegImm> KnownRegs) {
+  for (const RegImm &KnownReg : KnownRegs) {
+    if (KnownReg.Imm != 0)
+      continue;
+    if (KnownReg.Reg != DefReg)
+      continue;
+    int64_t ImmVal;
+    if (MI.isMoveImmediate() && getMoveImmediateValue(MI, ImmVal) && ImmVal == 0)
+      return true;
+    if (MI.isCopy() && isKnownZeroSource(MI, KnownRegs))
+      return true;
+    switch (MI.getOpcode()) {
+    case ARM::MOVr:
+    case ARM::t2MOVr:
+    case ARM::tMOVr:
+      if (isKnownZeroSource(MI, KnownRegs))
+        return true;
+      break;
+    default:
+      break;
+    }
+  }
+  return false;
+}
+
+static bool isRedundantEqualRegAssign(const MachineInstr &MI,
+                                      ArrayRef<RegEqual> KnownEqualRegs) {
+  if (MI.getNumOperands() < 2 || !MI.getOperand(0).isReg() ||
+      !MI.getOperand(1).isReg())
+    return false;
+  MCPhysReg DefReg = MI.getOperand(0).getReg();
+  MCPhysReg SrcReg = MI.getOperand(1).getReg();
+  for (const RegEqual &Eq : KnownEqualRegs) {
+    if ((DefReg == Eq.Reg1 && SrcReg == Eq.Reg2) ||
+        (DefReg == Eq.Reg2 && SrcReg == Eq.Reg1))
+      return true;
+  }
+  return false;
+}
+
+static bool shouldStopPredScan(ArrayRef<RegImm> KnownRegs,
+                               ArrayRef<RegEqual> KnownEqualRegs,
+                               const LiveRegUnits &Clobbered) {
+  bool AnyKnownReg = any_of(KnownRegs, [&](const RegImm &K) {
+    return Clobbered.available(K.Reg);
+  });
+  bool AnyKnownEqual = any_of(KnownEqualRegs, [&](const RegEqual &Eq) {
+    return Clobbered.available(Eq.Reg1) && Clobbered.available(Eq.Reg2);
+  });
+  return !AnyKnownReg && !AnyKnownEqual;
+}
+
+static void propagateEqualRegThroughCopy(MCPhysReg CopyDstReg, MCPhysReg CopySrcReg,
+                                         ArrayRef<RegEqual> KnownEqualRegs,
+                                         SmallVectorImpl<RegEqual> &Out) {
+  Out.push_back(RegEqual(CopyDstReg, CopySrcReg));
+  for (const RegEqual &Eq : KnownEqualRegs) {
+    if (CopySrcReg == Eq.Reg1)
+      Out.push_back(RegEqual(CopyDstReg, Eq.Reg2));
+    else if (CopySrcReg == Eq.Reg2)
+      Out.push_back(RegEqual(CopyDstReg, Eq.Reg1));
+    else if (CopyDstReg == Eq.Reg1)
+      Out.push_back(RegEqual(CopySrcReg, Eq.Reg2));
+    else if (CopyDstReg == Eq.Reg2)
+      Out.push_back(RegEqual(CopySrcReg, Eq.Reg1));
+  }
+}
+
+bool ARMRedundantCopyEliminationImpl::getCBZKnownRegs(
+    MachineInstr &CondBr, MachineBasicBlock *MBB,
+    SmallVectorImpl<RegImm> &KnownRegs,
+    MachineBasicBlock::iterator &FirstUse) {
+  unsigned Opc = CondBr.getOpcode();
+  if (Opc != ARM::tCBZ && Opc != ARM::tCBNZ)
+    return false;
+
+  MCPhysReg Reg = CondBr.getOperand(0).getReg();
+  MachineBasicBlock *Target = CondBr.getOperand(1).getMBB();
+  if ((Opc == ARM::tCBZ && Target == MBB) ||
+      (Opc == ARM::tCBNZ && Target != MBB)) {
+    FirstUse = CondBr;
+    KnownRegs.push_back(RegImm(Reg, 0));
+    return true;
+  }
+  return false;
+}
+
+bool ARMRedundantCopyEliminationImpl::knownRegValInBlock(
+    MachineInstr &CondBr, MachineBasicBlock *MBB,
+    SmallVectorImpl<RegImm> &KnownRegs,
+    SmallVectorImpl<RegEqual> &KnownEqualRegs,
+    MachineBasicBlock::iterator &FirstUse) {
+  if (!isCondBranchOpcode(CondBr.getOpcode()))
+    return false;
+
+  ARMCC::CondCodes CC = (ARMCC::CondCodes)CondBr.getOperand(1).getImm();
+  if (CC != ARMCC::EQ && CC != ARMCC::NE)
+    return false;
+
+  MachineBasicBlock *BrTarget = CondBr.getOperand(0).getMBB();
+  if ((CC == ARMCC::EQ && BrTarget != MBB) ||
+      (CC == ARMCC::NE && BrTarget == MBB))
+    return false;
+
+  MachineBasicBlock *PredMBB = *MBB->pred_begin();
+  assert(PredMBB == CondBr.getParent() &&
+         "Conditional branch not in predecessor block!");
+  if (CondBr == PredMBB->begin())
+    return false;
+
+  DomBBClobberedRegs.clear();
+  DomBBUsedRegs.clear();
+
+  MachineBasicBlock::reverse_iterator RIt = CondBr.getReverseIterator();
+  for (MachineInstr &PredI : make_range(std::next(RIt), PredMBB->rend())) {
+    MCPhysReg SrcReg;
+    int32_t KnownImm;
+    if (isCompareImm(PredI, SrcReg, KnownImm)) {
+      Register PredReg;
+      if (getInstrPredicate(PredI, PredReg) != ARMCC::AL)
+        return false;
+      bool Res = false;
+      if (DomBBClobberedRegs.available(SrcReg)) {
+        FirstUse = PredI;
+        KnownRegs.push_back(RegImm(SrcReg, KnownImm));
+        Res = true;
+      }
+      return Res;
+    }
+
+    MCPhysReg Rn;
+    MCPhysReg Rm;
+    if (isCompareReg(PredI, Rn, Rm)) {
+      Register PredReg;
+      if (getInstrPredicate(PredI, PredReg) != ARMCC::AL)
+        return false;
+      if (DomBBClobberedRegs.available(Rn) &&
+          DomBBClobberedRegs.available(Rm)) {
+        FirstUse = PredI;
+        KnownEqualRegs.push_back(RegEqual(Rn, Rm));
+        return true;
+      }
+      return false;
+    }
+
+    if (isFlagSettingAluWithDest(PredI)) {
+      Register PredReg;
+      if (getInstrPredicate(PredI, PredReg) != ARMCC::AL)
+        return false;
+      MCPhysReg DstReg = PredI.getOperand(0).getReg();
+      if (!DomBBClobberedRegs.available(DstReg))
+        return false;
+      FirstUse = PredI;
+      KnownRegs.push_back(RegImm(DstReg, 0));
+      return true;
+    }
+
+    if (PredI.definesRegister(ARM::CPSR, /*TRI=*/nullptr))
+      return false;
+
+    LiveRegUnits::accumulateUsedDefed(PredI, DomBBClobberedRegs, DomBBUsedRegs,
+                                      TRI);
+  }
+  return false;
+}
+
+bool ARMRedundantCopyEliminationImpl::optimizeBlock(MachineBasicBlock *MBB) {
+  if (MBB->pred_size() != 1)
+    return false;
+
+  MachineBasicBlock *PredMBB = *MBB->pred_begin();
+  if (PredMBB->succ_size() != 2)
+    return false;
+
+  MachineBasicBlock::iterator FirstUse;
+  bool SeenFirstUse = false;
+  SmallVector<RegImm, 4> KnownRegs;
+  SmallVector<RegEqual, 2> KnownEqualRegs;
+  MachineBasicBlock::iterator CondBrIt = PredMBB->end();
+  for (MachineInstr &Term : PredMBB->terminators()) {
+    if (Term.getOpcode() == ARM::tCBZ || Term.getOpcode() == ARM::tCBNZ) {
+      CondBrIt = Term.getIterator();
+      if (getCBZKnownRegs(Term, MBB, KnownRegs, FirstUse))
+        break;
+      KnownRegs.clear();
+      CondBrIt = PredMBB->end();
+    }
+  }
+
+  if (KnownRegs.empty() && KnownEqualRegs.empty()) {
+    MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
+    SmallVector<MachineOperand, 4> Cond;
+    if (TII->analyzeBranch(*PredMBB, TBB, FBB, Cond, /*AllowModify*/ false) ||
+        Cond.size() != 2)
+      return false;
+
+    for (MachineInstr &MI : reverse(PredMBB->instrs())) {
+      if (!isCondBranchOpcode(MI.getOpcode()))
+        continue;
+      CondBrIt = MI.getIterator();
+      if (!knownRegValInBlock(MI, MBB, KnownRegs, KnownEqualRegs, FirstUse))
+        return false;
+      break;
+    }
+    if (CondBrIt == PredMBB->end())
+      return false;
+  }
+
+  if (KnownRegs.empty() && KnownEqualRegs.empty())
+    return false;
+
+  OptBBClobberedRegs.clear();
+  OptBBUsedRegs.clear();
+
+  for (auto PredI = CondBrIt;; --PredI) {
+    if (FirstUse == PredI)
+      SeenFirstUse = true;
+
+    if (PredI->isCopy()) {
+      MCPhysReg CopyDstReg = PredI->getOperand(0).getReg();
+      MCPhysReg CopySrcReg = PredI->getOperand(1).getReg();
+      for (const RegImm &KnownReg : KnownRegs) {
+        if (!OptBBClobberedRegs.available(KnownReg.Reg))
+          continue;
+        if (CopySrcReg == KnownReg.Reg &&
+            OptBBClobberedRegs.available(CopyDstReg)) {
+          KnownRegs.push_back(RegImm(CopyDstReg, KnownReg.Imm));
+          if (SeenFirstUse)
+            FirstUse = PredI;
+          break;
+        }
+        if (CopyDstReg == KnownReg.Reg &&
+            OptBBClobberedRegs.available(CopySrcReg)) {
+          KnownRegs.push_back(RegImm(CopySrcReg, KnownReg.Imm));
+          if (SeenFirstUse)
+            FirstUse = PredI;
+          break;
+        }
+      }
+      SmallVector<RegEqual, 2> NewEqual;
+      if (OptBBClobberedRegs.available(CopyDstReg) &&
+          OptBBClobberedRegs.available(CopySrcReg)) {
+        propagateEqualRegThroughCopy(CopyDstReg, CopySrcReg, KnownEqualRegs,
+                                     NewEqual);
+      }
+      if (!NewEqual.empty()) {
+        KnownEqualRegs.append(NewEqual.begin(), NewEqual.end());
+        if (SeenFirstUse)
+          FirstUse = PredI;
+      }
+    }
+
+    if (PredI == PredMBB->begin())
+      break;
+
+    LiveRegUnits::accumulateUsedDefed(*PredI, OptBBClobberedRegs, OptBBUsedRegs,
+                                      TRI);
+    if (shouldStopPredScan(KnownRegs, KnownEqualRegs, OptBBClobberedRegs))
+      break;
+  }
+
+  if (KnownRegs.empty() && KnownEqualRegs.empty())
+    return false;
+
+  bool Changed = false;
+  SmallSetVector<unsigned, 4> UsedKnownRegs;
+  MachineBasicBlock::iterator LastChange = MBB->begin();
+  for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E;) {
+    MachineInstr *MI = &*I;
+    ++I;
+    bool RemovedMI = false;
+    bool IsCopy = MI->isCopy();
+    bool IsMoveImm = MI->isMoveImmediate();
+    bool IsRegMov = false;
+    switch (MI->getOpcode()) {
+    case ARM::MOVr:
+    case ARM::t2MOVr:
+    case ARM::tMOVr:
+      IsRegMov = true;
+      break;
+    }
+    if (IsCopy || IsMoveImm || IsRegMov) {
+      Register DefReg = MI->getOperand(0).getReg();
+      if (!MRI->isReserved(DefReg)) {
+        if ((IsCopy || IsRegMov) && !KnownEqualRegs.empty() &&
+            isRedundantEqualRegAssign(*MI, KnownEqualRegs)) {
+          // Don't remove an instruction that has other live defs.
+          if (any_of(MI->operands(), [DefReg](MachineOperand &O) {
+                return O.isReg() && O.isDef() && !O.isDead() &&
+                       O.getReg() != DefReg;
+              }))
+            continue;
+
+          for (const RegEqual &Eq : KnownEqualRegs) {
+            if (MI->getOperand(0).getReg() == Eq.Reg1 ||
+                MI->getOperand(0).getReg() == Eq.Reg2 ||
+                MI->getOperand(1).getReg() == Eq.Reg1 ||
+                MI->getOperand(1).getReg() == Eq.Reg2) {
+              UsedKnownRegs.insert(Eq.Reg1);
+              UsedKnownRegs.insert(Eq.Reg2);
+            }
+          }
+          LLVM_DEBUG(dbgs() << "Remove redundant equal-reg move: " << *MI);
+          MI->eraseFromParent();
+          Changed = true;
+          LastChange = I;
+          ++NumCopiesRemoved;
+          RemovedMI = true;
+        }
+
+        for (RegImm &KnownReg : KnownRegs) {
+          if (RemovedMI)
+            break;
+          if (KnownReg.Reg != DefReg)
+            continue;
+
+          bool ShouldRemove = false;
+          if (KnownReg.Imm == 0 &&
+              isRedundantZeroAssign(*MI, DefReg, KnownRegs))
+            ShouldRemove = true;
+          else if (IsMoveImm) {
+            int64_t ImmVal;
+            if (getMoveImmediateValue(*MI, ImmVal) && KnownReg.Imm == ImmVal)
+              ShouldRemove = true;
+          }
+
+          if (!ShouldRemove)
+            continue;
+
+          MCPhysReg CmpReg = KnownReg.Reg;
+          if (any_of(MI->operands(), [CmpReg](MachineOperand &O) {
+                return O.isReg() && O.isDef() && !O.isDead() &&
+                       O.getReg() != CmpReg;
+              }))
+            continue;
+
+          if (IsCopy)
+            LLVM_DEBUG(dbgs() << "Remove redundant Copy : " << *MI);
+          else
+            LLVM_DEBUG(dbgs() << "Remove redundant Move : " << *MI);
+
+          MI->eraseFromParent();
+          Changed = true;
+          LastChange = I;
+          ++NumCopiesRemoved;
+          UsedKnownRegs.insert(KnownReg.Reg);
+          RemovedMI = true;
+          break;
+        }
+      }
+    }
+
+    if (RemovedMI)
+      continue;
+
+    for (unsigned RI = 0; RI < KnownRegs.size();) {
+      if (MI->modifiesRegister(KnownRegs[RI].Reg, TRI)) {
+        std::swap(KnownRegs[RI], KnownRegs[KnownRegs.size() - 1]);
+        KnownRegs.pop_back();
+      } else {
+        ++RI;
+      }
+    }
+
+    for (unsigned RI = 0; RI < KnownEqualRegs.size();) {
+      if (MI->modifiesRegister(KnownEqualRegs[RI].Reg1, TRI) ||
+          MI->modifiesRegister(KnownEqualRegs[RI].Reg2, TRI)) {
+        std::swap(KnownEqualRegs[RI],
+                  KnownEqualRegs[KnownEqualRegs.size() - 1]);
+        KnownEqualRegs.pop_back();
+      } else {
+        ++RI;
+      }
+    }
+
+    if (KnownRegs.empty() && KnownEqualRegs.empty())
+      break;
+  }
+
+  if (!Changed)
+    return false;
+
+  for (MCPhysReg KnownReg : UsedKnownRegs)
+    if (!MBB->isLiveIn(KnownReg))
+      MBB->addLiveIn(KnownReg);
+
+  LLVM_DEBUG(dbgs() << "Clearing kill flags.\n\tFirstUse: " << *FirstUse
+                    << "\tLastChange: ");
+  if (LastChange == MBB->end())
+    LLVM_DEBUG(dbgs() << "<end>\n");
+  else
...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/203706


More information about the llvm-commits mailing list