64#define DEBUG_TYPE "aarch64-copyelim"
66STATISTIC(NumCopiesRemoved,
"Number of copies removed.");
69class AArch64RedundantCopyEliminationImpl {
90 bool knownRegValInBlock(MachineInstr &CondBr, MachineBasicBlock *
MBB,
91 SmallVectorImpl<RegImm> &KnownRegs,
99 AArch64RedundantCopyEliminationLegacy() : MachineFunctionPass(ID) {}
101 bool runOnMachineFunction(MachineFunction &MF)
override;
103 MachineFunctionProperties getRequiredProperties()
const override {
104 return MachineFunctionProperties().setNoVRegs();
106 StringRef getPassName()
const override {
107 return "AArch64 Redundant Copy Elimination";
110char AArch64RedundantCopyEliminationLegacy::ID = 0;
114 "AArch64 redundant copy elimination pass",
false,
false)
128bool AArch64RedundantCopyEliminationImpl::knownRegValInBlock(
131 unsigned Opc = CondBr.getOpcode();
135 if (((
Opc == AArch64::CBZW ||
Opc == AArch64::CBZX) &&
136 MBB == CondBr.getOperand(1).getMBB()) ||
137 ((
Opc == AArch64::CBNZW ||
Opc == AArch64::CBNZX) &&
138 MBB != CondBr.getOperand(1).getMBB())) {
140 KnownRegs.push_back(RegImm(CondBr.getOperand(0).getReg(), 0));
145 if (
Opc != AArch64::Bcc)
161 "Conditional branch not in predecessor block!");
162 if (CondBr == PredMBB->
begin())
167 DomBBClobberedRegs.clear();
168 DomBBUsedRegs.clear();
175 switch (PredI.getOpcode()) {
180 case AArch64::ADDSWri:
181 case AArch64::ADDSXri:
185 case AArch64::SUBSWri:
186 case AArch64::SUBSXri: {
188 if (!PredI.getOperand(1).isReg())
190 MCPhysReg DstReg = PredI.getOperand(0).getReg();
191 MCPhysReg SrcReg = PredI.getOperand(1).getReg();
198 if (PredI.getOperand(2).isImm() && DomBBClobberedRegs.available(SrcReg) &&
201 int32_t KnownImm = PredI.getOperand(2).getImm();
202 int32_t Shift = PredI.getOperand(3).getImm();
205 KnownImm = -KnownImm;
207 KnownRegs.push_back(RegImm(SrcReg, KnownImm));
213 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
218 if (!DomBBClobberedRegs.available(DstReg))
222 KnownRegs.push_back(RegImm(DstReg, 0));
228 case AArch64::ADCSWr:
229 case AArch64::ADCSXr:
230 case AArch64::ADDSWrr:
231 case AArch64::ADDSWrs:
232 case AArch64::ADDSWrx:
233 case AArch64::ADDSXrr:
234 case AArch64::ADDSXrs:
235 case AArch64::ADDSXrx:
236 case AArch64::ADDSXrx64:
237 case AArch64::ANDSWri:
238 case AArch64::ANDSWrr:
239 case AArch64::ANDSWrs:
240 case AArch64::ANDSXri:
241 case AArch64::ANDSXrr:
242 case AArch64::ANDSXrs:
243 case AArch64::BICSWrr:
244 case AArch64::BICSWrs:
245 case AArch64::BICSXrs:
246 case AArch64::BICSXrr:
247 case AArch64::SBCSWr:
248 case AArch64::SBCSXr:
249 case AArch64::SUBSWrr:
250 case AArch64::SUBSWrs:
251 case AArch64::SUBSWrx:
252 case AArch64::SUBSXrr:
253 case AArch64::SUBSXrs:
254 case AArch64::SUBSXrx:
255 case AArch64::SUBSXrx64: {
256 MCPhysReg DstReg = PredI.getOperand(0).getReg();
257 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
262 if (!DomBBClobberedRegs.available(DstReg))
267 KnownRegs.push_back(RegImm(DstReg, 0));
273 if (PredI.definesRegister(AArch64::NZCV,
nullptr))
283bool AArch64RedundantCopyEliminationImpl::optimizeBlock(
296 if (CondBr == PredMBB->
end())
307 bool SeenFirstUse =
false;
315 if (!knownRegValInBlock(*Itr,
MBB, KnownRegs, FirstUse))
319 OptBBClobberedRegs.
clear();
320 OptBBUsedRegs.
clear();
324 for (
auto PredI = Itr;; --PredI) {
325 if (FirstUse == PredI)
328 if (PredI->isCopy()) {
329 MCPhysReg CopyDstReg = PredI->getOperand(0).getReg();
330 MCPhysReg CopySrcReg = PredI->getOperand(1).getReg();
331 for (
auto &KnownReg : KnownRegs) {
332 if (!OptBBClobberedRegs.
available(KnownReg.Reg))
336 if (CopySrcReg == KnownReg.Reg &&
337 OptBBClobberedRegs.
available(CopyDstReg)) {
338 KnownRegs.push_back(
RegImm(CopyDstReg, KnownReg.Imm));
345 if (CopyDstReg == KnownReg.Reg &&
346 OptBBClobberedRegs.
available(CopySrcReg)) {
347 KnownRegs.push_back(
RegImm(CopySrcReg, KnownReg.Imm));
356 if (PredI == PredMBB->
begin())
362 if (
all_of(KnownRegs, [&](RegImm KnownReg) {
363 return !OptBBClobberedRegs.
available(KnownReg.Reg);
369 }
while (Itr != PredMBB->
begin() && Itr->isTerminator());
372 if (KnownRegs.empty())
377 SmallSetVector<unsigned, 4> UsedKnownRegs;
381 MachineInstr *
MI = &*
I;
383 bool RemovedMI =
false;
384 bool IsCopy =
MI->isCopy();
385 bool IsMoveImm =
MI->isMoveImmediate();
386 if (IsCopy || IsMoveImm) {
389 int64_t SrcImm = IsMoveImm ?
MI->getOperand(1).getImm() : 0;
391 ((IsCopy && (SrcReg == AArch64::XZR || SrcReg == AArch64::WZR)) ||
393 for (RegImm &KnownReg : KnownRegs) {
394 if (KnownReg.Reg != DefReg &&
395 !
TRI->isSuperRegister(DefReg, KnownReg.Reg))
399 if (IsCopy && KnownReg.Imm != 0)
405 if (KnownReg.Imm != SrcImm)
411 if (
any_of(
MI->implicit_operands(), [CmpReg](MachineOperand &O) {
412 return !O.isDead() && O.isReg() && O.isDef() &&
413 O.getReg() != CmpReg;
419 if (
TRI->isSuperRegister(DefReg, KnownReg.Reg) && KnownReg.Imm < 0)
428 MI->eraseFromParent();
432 UsedKnownRegs.
insert(KnownReg.Reg);
444 for (
unsigned RI = 0; RI < KnownRegs.size();)
445 if (
MI->modifiesRegister(KnownRegs[RI].Reg,
TRI)) {
446 std::swap(KnownRegs[RI], KnownRegs[KnownRegs.size() - 1]);
447 KnownRegs.pop_back();
455 if (KnownRegs.empty())
470 LLVM_DEBUG(
dbgs() <<
"Clearing kill flags.\n\tFirstUse: " << *FirstUse
472 if (LastChange ==
MBB->
end())
dbgs() <<
"<end>\n";
473 else dbgs() << *LastChange);
474 for (MachineInstr &MMI :
make_range(FirstUse, PredMBB->
end()))
482bool AArch64RedundantCopyEliminationImpl::run(MachineFunction &MF) {
495 for (MachineBasicBlock &
MBB : MF) {
502bool AArch64RedundantCopyEliminationLegacy::runOnMachineFunction(
503 MachineFunction &MF) {
506 return AArch64RedundantCopyEliminationImpl().run(MF);
512 const bool Changed = AArch64RedundantCopyEliminationImpl().run(MF);
521 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)
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...
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.