63#define DEBUG_TYPE "aarch64-copyelim"
65STATISTIC(NumCopiesRemoved,
"Number of copies removed.");
89 bool knownRegValInBlock(MachineInstr &CondBr, MachineBasicBlock *
MBB,
90 SmallVectorImpl<RegImm> &KnownRegs,
93 bool runOnMachineFunction(MachineFunction &MF)
override;
94 MachineFunctionProperties getRequiredProperties()
const override {
95 return MachineFunctionProperties().setNoVRegs();
97 StringRef getPassName()
const override {
98 return "AArch64 Redundant Copy Elimination";
101char AArch64RedundantCopyElimination::ID = 0;
105 "AArch64 redundant copy elimination pass",
false,
false)
119bool AArch64RedundantCopyElimination::knownRegValInBlock(
122 unsigned Opc = CondBr.getOpcode();
126 if (((
Opc == AArch64::CBZW ||
Opc == AArch64::CBZX) &&
127 MBB == CondBr.getOperand(1).getMBB()) ||
128 ((
Opc == AArch64::CBNZW ||
Opc == AArch64::CBNZX) &&
129 MBB != CondBr.getOperand(1).getMBB())) {
131 KnownRegs.push_back(RegImm(CondBr.getOperand(0).getReg(), 0));
136 if (
Opc != AArch64::Bcc)
152 "Conditional branch not in predecessor block!");
153 if (CondBr == PredMBB->
begin())
158 DomBBClobberedRegs.clear();
159 DomBBUsedRegs.clear();
166 switch (PredI.getOpcode()) {
171 case AArch64::ADDSWri:
172 case AArch64::ADDSXri:
176 case AArch64::SUBSWri:
177 case AArch64::SUBSXri: {
179 if (!PredI.getOperand(1).isReg())
181 MCPhysReg DstReg = PredI.getOperand(0).getReg();
182 MCPhysReg SrcReg = PredI.getOperand(1).getReg();
189 if (PredI.getOperand(2).isImm() && DomBBClobberedRegs.available(SrcReg) &&
192 int32_t KnownImm = PredI.getOperand(2).getImm();
193 int32_t Shift = PredI.getOperand(3).getImm();
196 KnownImm = -KnownImm;
198 KnownRegs.push_back(RegImm(SrcReg, KnownImm));
204 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
209 if (!DomBBClobberedRegs.available(DstReg))
213 KnownRegs.push_back(RegImm(DstReg, 0));
219 case AArch64::ADCSWr:
220 case AArch64::ADCSXr:
221 case AArch64::ADDSWrr:
222 case AArch64::ADDSWrs:
223 case AArch64::ADDSWrx:
224 case AArch64::ADDSXrr:
225 case AArch64::ADDSXrs:
226 case AArch64::ADDSXrx:
227 case AArch64::ADDSXrx64:
228 case AArch64::ANDSWri:
229 case AArch64::ANDSWrr:
230 case AArch64::ANDSWrs:
231 case AArch64::ANDSXri:
232 case AArch64::ANDSXrr:
233 case AArch64::ANDSXrs:
234 case AArch64::BICSWrr:
235 case AArch64::BICSWrs:
236 case AArch64::BICSXrs:
237 case AArch64::BICSXrr:
238 case AArch64::SBCSWr:
239 case AArch64::SBCSXr:
240 case AArch64::SUBSWrr:
241 case AArch64::SUBSWrs:
242 case AArch64::SUBSWrx:
243 case AArch64::SUBSXrr:
244 case AArch64::SUBSXrs:
245 case AArch64::SUBSXrx:
246 case AArch64::SUBSXrx64: {
247 MCPhysReg DstReg = PredI.getOperand(0).getReg();
248 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
253 if (!DomBBClobberedRegs.available(DstReg))
258 KnownRegs.push_back(RegImm(DstReg, 0));
264 if (PredI.definesRegister(AArch64::NZCV,
nullptr))
286 if (CondBr == PredMBB->
end())
297 bool SeenFirstUse =
false;
305 if (!knownRegValInBlock(*Itr,
MBB, KnownRegs, FirstUse))
309 OptBBClobberedRegs.
clear();
310 OptBBUsedRegs.
clear();
314 for (
auto PredI = Itr;; --PredI) {
315 if (FirstUse == PredI)
318 if (PredI->isCopy()) {
319 MCPhysReg CopyDstReg = PredI->getOperand(0).getReg();
320 MCPhysReg CopySrcReg = PredI->getOperand(1).getReg();
321 for (
auto &KnownReg : KnownRegs) {
322 if (!OptBBClobberedRegs.
available(KnownReg.Reg))
326 if (CopySrcReg == KnownReg.Reg &&
327 OptBBClobberedRegs.
available(CopyDstReg)) {
328 KnownRegs.push_back(
RegImm(CopyDstReg, KnownReg.Imm));
335 if (CopyDstReg == KnownReg.Reg &&
336 OptBBClobberedRegs.
available(CopySrcReg)) {
337 KnownRegs.push_back(
RegImm(CopySrcReg, KnownReg.Imm));
346 if (PredI == PredMBB->
begin())
352 if (
all_of(KnownRegs, [&](RegImm KnownReg) {
353 return !OptBBClobberedRegs.
available(KnownReg.Reg);
359 }
while (Itr != PredMBB->
begin() && Itr->isTerminator());
362 if (KnownRegs.empty())
367 SmallSetVector<unsigned, 4> UsedKnownRegs;
371 MachineInstr *
MI = &*
I;
373 bool RemovedMI =
false;
374 bool IsCopy =
MI->isCopy();
375 bool IsMoveImm =
MI->isMoveImmediate();
376 if (IsCopy || IsMoveImm) {
379 int64_t SrcImm = IsMoveImm ?
MI->getOperand(1).getImm() : 0;
380 if (!
MRI->isReserved(DefReg) &&
381 ((IsCopy && (SrcReg == AArch64::XZR || SrcReg == AArch64::WZR)) ||
383 for (RegImm &KnownReg : KnownRegs) {
384 if (KnownReg.Reg != DefReg &&
385 !
TRI->isSuperRegister(DefReg, KnownReg.Reg))
389 if (IsCopy && KnownReg.Imm != 0)
395 if (KnownReg.Imm != SrcImm)
401 if (
any_of(
MI->implicit_operands(), [CmpReg](MachineOperand &O) {
402 return !O.isDead() && O.isReg() && O.isDef() &&
403 O.getReg() != CmpReg;
409 if (
TRI->isSuperRegister(DefReg, KnownReg.Reg) && KnownReg.Imm < 0)
418 MI->eraseFromParent();
422 UsedKnownRegs.
insert(KnownReg.Reg);
434 for (
unsigned RI = 0; RI < KnownRegs.size();)
435 if (
MI->modifiesRegister(KnownRegs[RI].Reg,
TRI)) {
436 std::swap(KnownRegs[RI], KnownRegs[KnownRegs.size() - 1]);
437 KnownRegs.pop_back();
445 if (KnownRegs.empty())
460 LLVM_DEBUG(
dbgs() <<
"Clearing kill flags.\n\tFirstUse: " << *FirstUse
462 if (LastChange ==
MBB->
end())
dbgs() <<
"<end>\n";
463 else dbgs() << *LastChange);
464 for (MachineInstr &MMI :
make_range(FirstUse, PredMBB->
end()))
472bool AArch64RedundantCopyElimination::runOnMachineFunction(
473 MachineFunction &MF) {
487 for (MachineBasicBlock &
MBB : MF)
493 return new AArch64RedundantCopyElimination();
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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)
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 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 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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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.
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...
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.