65#define DEBUG_TYPE "aarch64-copyelim"
67STATISTIC(NumCopiesRemoved,
"Number of copies removed.");
70class AArch64RedundantCopyEliminationImpl {
91 bool knownRegValInBlock(MachineInstr &CondBr, MachineBasicBlock *
MBB,
92 SmallVectorImpl<RegImm> &KnownRegs,
100 AArch64RedundantCopyEliminationLegacy() : MachineFunctionPass(ID) {}
102 bool runOnMachineFunction(MachineFunction &MF)
override;
104 MachineFunctionProperties getRequiredProperties()
const override {
105 return MachineFunctionProperties().setNoVRegs();
107 StringRef getPassName()
const override {
108 return "AArch64 Redundant Copy Elimination";
111 void getAnalysisUsage(AnalysisUsage &AU)
const override {
116char AArch64RedundantCopyEliminationLegacy::ID = 0;
120 "AArch64 redundant copy elimination pass",
false,
false)
134bool AArch64RedundantCopyEliminationImpl::knownRegValInBlock(
137 unsigned Opc = CondBr.getOpcode();
141 if (((
Opc == AArch64::CBZW ||
Opc == AArch64::CBZX) &&
142 MBB == CondBr.getOperand(1).getMBB()) ||
143 ((
Opc == AArch64::CBNZW ||
Opc == AArch64::CBNZX) &&
144 MBB != CondBr.getOperand(1).getMBB())) {
146 KnownRegs.push_back(RegImm(CondBr.getOperand(0).getReg(), 0));
151 if (
Opc != AArch64::Bcc)
167 "Conditional branch not in predecessor block!");
168 if (CondBr == PredMBB->
begin())
173 DomBBClobberedRegs.clear();
174 DomBBUsedRegs.clear();
181 switch (PredI.getOpcode()) {
186 case AArch64::ADDSWri:
187 case AArch64::ADDSXri:
191 case AArch64::SUBSWri:
192 case AArch64::SUBSXri: {
194 if (!PredI.getOperand(1).isReg())
196 MCPhysReg DstReg = PredI.getOperand(0).getReg();
197 MCPhysReg SrcReg = PredI.getOperand(1).getReg();
204 if (PredI.getOperand(2).isImm() && DomBBClobberedRegs.available(SrcReg) &&
207 int32_t KnownImm = PredI.getOperand(2).getImm();
208 int32_t Shift = PredI.getOperand(3).getImm();
211 KnownImm = -KnownImm;
213 KnownRegs.push_back(RegImm(SrcReg, KnownImm));
219 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
224 if (!DomBBClobberedRegs.available(DstReg))
228 KnownRegs.push_back(RegImm(DstReg, 0));
234 case AArch64::ADCSWr:
235 case AArch64::ADCSXr:
236 case AArch64::ADDSWrr:
237 case AArch64::ADDSWrs:
238 case AArch64::ADDSWrx:
239 case AArch64::ADDSXrr:
240 case AArch64::ADDSXrs:
241 case AArch64::ADDSXrx:
242 case AArch64::ADDSXrx64:
243 case AArch64::ANDSWri:
244 case AArch64::ANDSWrr:
245 case AArch64::ANDSWrs:
246 case AArch64::ANDSXri:
247 case AArch64::ANDSXrr:
248 case AArch64::ANDSXrs:
249 case AArch64::BICSWrr:
250 case AArch64::BICSWrs:
251 case AArch64::BICSXrs:
252 case AArch64::BICSXrr:
253 case AArch64::SBCSWr:
254 case AArch64::SBCSXr:
255 case AArch64::SUBSWrr:
256 case AArch64::SUBSWrs:
257 case AArch64::SUBSWrx:
258 case AArch64::SUBSXrr:
259 case AArch64::SUBSXrs:
260 case AArch64::SUBSXrx:
261 case AArch64::SUBSXrx64: {
262 MCPhysReg DstReg = PredI.getOperand(0).getReg();
263 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
268 if (!DomBBClobberedRegs.available(DstReg))
273 KnownRegs.push_back(RegImm(DstReg, 0));
279 if (PredI.definesRegister(AArch64::NZCV,
nullptr))
289bool AArch64RedundantCopyEliminationImpl::optimizeBlock(
302 if (CondBr == PredMBB->
end())
313 bool SeenFirstUse =
false;
321 if (!knownRegValInBlock(*Itr,
MBB, KnownRegs, FirstUse))
325 OptBBClobberedRegs.
clear();
326 OptBBUsedRegs.
clear();
330 for (
auto PredI = Itr;; --PredI) {
331 if (FirstUse == PredI)
334 if (PredI->isCopy()) {
335 MCPhysReg CopyDstReg = PredI->getOperand(0).getReg();
336 MCPhysReg CopySrcReg = PredI->getOperand(1).getReg();
337 for (
auto &KnownReg : KnownRegs) {
338 if (!OptBBClobberedRegs.
available(KnownReg.Reg))
342 if (CopySrcReg == KnownReg.Reg &&
343 OptBBClobberedRegs.
available(CopyDstReg)) {
344 KnownRegs.push_back(
RegImm(CopyDstReg, KnownReg.Imm));
351 if (CopyDstReg == KnownReg.Reg &&
352 OptBBClobberedRegs.
available(CopySrcReg)) {
353 KnownRegs.push_back(
RegImm(CopySrcReg, KnownReg.Imm));
362 if (PredI == PredMBB->
begin())
368 if (
all_of(KnownRegs, [&](RegImm KnownReg) {
369 return !OptBBClobberedRegs.
available(KnownReg.Reg);
375 }
while (Itr != PredMBB->
begin() && Itr->isTerminator());
378 if (KnownRegs.empty())
383 SmallSetVector<unsigned, 4> UsedKnownRegs;
387 MachineInstr *
MI = &*
I;
389 bool RemovedMI =
false;
390 bool IsCopy =
MI->isCopy();
391 bool IsMoveImm =
MI->isMoveImmediate();
392 if (IsCopy || IsMoveImm) {
395 int64_t SrcImm = IsMoveImm ?
MI->getOperand(1).getImm() : 0;
397 ((IsCopy && (SrcReg == AArch64::XZR || SrcReg == AArch64::WZR)) ||
399 for (RegImm &KnownReg : KnownRegs) {
400 if (KnownReg.Reg != DefReg &&
401 !
TRI->isSuperRegister(DefReg, KnownReg.Reg))
405 if (IsCopy && KnownReg.Imm != 0)
411 if (KnownReg.Imm != SrcImm)
417 if (
any_of(
MI->implicit_operands(), [CmpReg](MachineOperand &O) {
418 return !O.isDead() && O.isReg() && O.isDef() &&
419 O.getReg() != CmpReg;
425 if (
TRI->isSuperRegister(DefReg, KnownReg.Reg) && KnownReg.Imm < 0)
434 MI->eraseFromParent();
438 UsedKnownRegs.
insert(KnownReg.Reg);
450 for (
unsigned RI = 0; RI < KnownRegs.size();)
451 if (
MI->modifiesRegister(KnownRegs[RI].Reg,
TRI)) {
452 std::swap(KnownRegs[RI], KnownRegs[KnownRegs.size() - 1]);
453 KnownRegs.pop_back();
461 if (KnownRegs.empty())
476 LLVM_DEBUG(
dbgs() <<
"Clearing kill flags.\n\tFirstUse: " << *FirstUse
478 if (LastChange ==
MBB->
end())
dbgs() <<
"<end>\n";
479 else dbgs() << *LastChange);
480 for (MachineInstr &MMI :
make_range(FirstUse, PredMBB->
end()))
488bool AArch64RedundantCopyEliminationImpl::run(MachineFunction &MF) {
501 for (MachineBasicBlock &
MBB : MF) {
508bool AArch64RedundantCopyEliminationLegacy::runOnMachineFunction(
509 MachineFunction &MF) {
512 return AArch64RedundantCopyEliminationImpl().run(MF);
518 const bool Changed = AArch64RedundantCopyEliminationImpl().run(MF);
527 return new AArch64RedundantCopyEliminationLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT, const TargetTransformInfo &TTI, const DataLayout &DL, bool HasBranchDivergence, DomTreeUpdater *DTU)
This file implements a set that has insertion order iteration characteristics.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Represents analyses that only rely on functions' control flow.
FunctionPass class - This class is used to implement most global optimizations.
A set of register units used to track register liveness.
static void accumulateUsedDefed(const MachineInstr &MI, LiveRegUnits &ModifiedRegUnits, LiveRegUnits &UsedRegUnits, const TargetRegisterInfo *TRI)
For a machine instruction MI, adds all register units used in UsedRegUnits and defined or clobbered i...
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
void init(const TargetRegisterInfo &TRI)
Initialize and clear the set.
void clear()
Clears the set.
unsigned pred_size() const
unsigned succ_size() const
pred_iterator pred_begin()
LLVM_ABI iterator getLastNonDebugInstr(bool SkipPseudoOp=true)
Returns an iterator to the last non-debug instruction in the basic block, or end().
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
bool isReserved(MCRegister PhysReg) const
isReserved - Returns true when PhysReg is a reserved register.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
FunctionPass * createAArch64RedundantCopyEliminationPass()
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
bool optimizeTerminators(MachineBasicBlock *MBB, const TargetInstrInfo &TII)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.