63#define DEBUG_TYPE "aarch64-copyelim"
65STATISTIC(NumCopiesRemoved,
"Number of copies removed.");
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())
365 bool Changed =
false;
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)
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);
472bool AArch64RedundantCopyElimination::runOnMachineFunction(
481 DomBBClobberedRegs.init(*
TRI);
482 DomBBUsedRegs.init(*
TRI);
483 OptBBClobberedRegs.init(*
TRI);
484 OptBBUsedRegs.init(*
TRI);
486 bool Changed =
false;
493 return new AArch64RedundantCopyElimination();
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Register const TargetRegisterInfo * TRI
#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...
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().
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.
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...
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.
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,...
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 =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.
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.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.