63#define DEBUG_TYPE "aarch64-copyelim"
65STATISTIC(NumCopiesRemoved,
"Number of copies removed.");
99 MachineFunctionProperties::Property::NoVRegs);
102 return "AArch64 Redundant Copy Elimination";
105char AArch64RedundantCopyElimination::ID = 0;
109 "AArch64 redundant copy elimination pass",
false,
false)
123bool AArch64RedundantCopyElimination::knownRegValInBlock(
126 unsigned Opc = CondBr.getOpcode();
130 if (((Opc == AArch64::CBZW || Opc == AArch64::CBZX) &&
131 MBB == CondBr.getOperand(1).getMBB()) ||
132 ((Opc == AArch64::CBNZW || Opc == AArch64::CBNZX) &&
133 MBB != CondBr.getOperand(1).getMBB())) {
135 KnownRegs.push_back(RegImm(CondBr.getOperand(0).getReg(), 0));
140 if (Opc != AArch64::Bcc)
156 "Conditional branch not in predecessor block!");
157 if (CondBr == PredMBB->
begin())
162 DomBBClobberedRegs.
clear();
163 DomBBUsedRegs.
clear();
170 switch (PredI.getOpcode()) {
175 case AArch64::ADDSWri:
176 case AArch64::ADDSXri:
180 case AArch64::SUBSWri:
181 case AArch64::SUBSXri: {
183 if (!PredI.getOperand(1).isReg())
185 MCPhysReg DstReg = PredI.getOperand(0).getReg();
186 MCPhysReg SrcReg = PredI.getOperand(1).getReg();
193 if (PredI.getOperand(2).isImm() && DomBBClobberedRegs.
available(SrcReg) &&
196 int32_t KnownImm = PredI.getOperand(2).getImm();
197 int32_t Shift = PredI.getOperand(3).getImm();
200 KnownImm = -KnownImm;
202 KnownRegs.push_back(RegImm(SrcReg, KnownImm));
208 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
213 if (!DomBBClobberedRegs.
available(DstReg))
217 KnownRegs.push_back(RegImm(DstReg, 0));
223 case AArch64::ADCSWr:
224 case AArch64::ADCSXr:
225 case AArch64::ADDSWrr:
226 case AArch64::ADDSWrs:
227 case AArch64::ADDSWrx:
228 case AArch64::ADDSXrr:
229 case AArch64::ADDSXrs:
230 case AArch64::ADDSXrx:
231 case AArch64::ADDSXrx64:
232 case AArch64::ANDSWri:
233 case AArch64::ANDSWrr:
234 case AArch64::ANDSWrs:
235 case AArch64::ANDSXri:
236 case AArch64::ANDSXrr:
237 case AArch64::ANDSXrs:
238 case AArch64::BICSWrr:
239 case AArch64::BICSWrs:
240 case AArch64::BICSXrs:
241 case AArch64::BICSXrr:
242 case AArch64::SBCSWr:
243 case AArch64::SBCSXr:
244 case AArch64::SUBSWrr:
245 case AArch64::SUBSWrs:
246 case AArch64::SUBSWrx:
247 case AArch64::SUBSXrr:
248 case AArch64::SUBSXrs:
249 case AArch64::SUBSXrx:
250 case AArch64::SUBSXrx64: {
251 MCPhysReg DstReg = PredI.getOperand(0).getReg();
252 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
257 if (!DomBBClobberedRegs.
available(DstReg))
262 KnownRegs.push_back(RegImm(DstReg, 0));
268 if (PredI.definesRegister(AArch64::NZCV,
nullptr))
290 if (CondBr == PredMBB->
end())
301 bool SeenFirstUse =
false;
309 if (!knownRegValInBlock(*Itr,
MBB, KnownRegs, FirstUse))
313 OptBBClobberedRegs.
clear();
314 OptBBUsedRegs.
clear();
318 for (
auto PredI = Itr;; --PredI) {
319 if (FirstUse == PredI)
322 if (PredI->isCopy()) {
323 MCPhysReg CopyDstReg = PredI->getOperand(0).getReg();
324 MCPhysReg CopySrcReg = PredI->getOperand(1).getReg();
325 for (
auto &KnownReg : KnownRegs) {
326 if (!OptBBClobberedRegs.
available(KnownReg.Reg))
330 if (CopySrcReg == KnownReg.Reg &&
331 OptBBClobberedRegs.
available(CopyDstReg)) {
332 KnownRegs.push_back(
RegImm(CopyDstReg, KnownReg.Imm));
339 if (CopyDstReg == KnownReg.Reg &&
340 OptBBClobberedRegs.
available(CopySrcReg)) {
341 KnownRegs.push_back(
RegImm(CopySrcReg, KnownReg.Imm));
350 if (PredI == PredMBB->
begin())
356 if (
all_of(KnownRegs, [&](RegImm KnownReg) {
357 return !OptBBClobberedRegs.
available(KnownReg.Reg);
363 }
while (Itr != PredMBB->
begin() && Itr->isTerminator());
366 if (KnownRegs.empty())
369 bool Changed =
false;
377 bool RemovedMI =
false;
378 bool IsCopy =
MI->isCopy();
379 bool IsMoveImm =
MI->isMoveImmediate();
380 if (IsCopy || IsMoveImm) {
383 int64_t SrcImm = IsMoveImm ?
MI->getOperand(1).getImm() : 0;
384 if (!
MRI->isReserved(DefReg) &&
385 ((IsCopy && (SrcReg == AArch64::XZR || SrcReg == AArch64::WZR)) ||
387 for (RegImm &KnownReg : KnownRegs) {
388 if (KnownReg.Reg != DefReg &&
389 !
TRI->isSuperRegister(DefReg, KnownReg.Reg))
393 if (IsCopy && KnownReg.Imm != 0)
399 if (KnownReg.Imm != SrcImm)
406 return !O.isDead() && O.isReg() && O.isDef() &&
407 O.getReg() != CmpReg;
413 if (
TRI->isSuperRegister(DefReg, KnownReg.Reg) && KnownReg.Imm < 0)
422 MI->eraseFromParent();
426 UsedKnownRegs.
insert(KnownReg.Reg);
438 for (
unsigned RI = 0; RI < KnownRegs.size();)
439 if (
MI->modifiesRegister(KnownRegs[RI].Reg,
TRI)) {
440 std::swap(KnownRegs[RI], KnownRegs[KnownRegs.size() - 1]);
441 KnownRegs.pop_back();
449 if (KnownRegs.empty())
464 LLVM_DEBUG(
dbgs() <<
"Clearing kill flags.\n\tFirstUse: " << *FirstUse
466 if (LastChange ==
MBB->
end())
dbgs() <<
"<end>\n";
467 else dbgs() << *LastChange);
476bool AArch64RedundantCopyElimination::runOnMachineFunction(
490 bool Changed =
false;
497 return new AArch64RedundantCopyElimination();
unsigned const MachineRegisterInfo * MRI
unsigned const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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(MCPhysReg 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()
iterator getLastNonDebugInstr(bool SkipPseudoOp=true)
Returns an iterator to the last non-debug instruction in the basic block, or end().
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.
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...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
virtual MachineFunctionProperties getRequiredProperties() const
Properties which a MachineFunction may have at a given point in time.
MachineFunctionProperties & set(Property P)
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.
MachineOperand class - Representation of each machine instruction operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
bool insert(const value_type &X)
Insert a new element into the SetVector.
A SetVector that performs no allocations if smaller than a certain size.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
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.
Reg
All possible values of the reg field in the ModR/M byte.
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.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void initializeAArch64RedundantCopyEliminationPass(PassRegistry &)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.