[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