65 #define DEBUG_TYPE "aarch64-copyelim" 67 STATISTIC(NumCopiesRemoved,
"Number of copies removed.");
91 RegImm(
MCPhysReg Reg, int32_t Imm) : Reg(Reg), Imm(Imm) {}
104 return "AArch64 Redundant Copy Elimination";
111 "AArch64 redundant copy elimination pass",
false,
false)
125 bool AArch64RedundantCopyElimination::knownRegValInBlock(
128 unsigned Opc = CondBr.getOpcode();
132 if (((Opc == AArch64::CBZW || Opc == AArch64::CBZX) &&
133 MBB == CondBr.getOperand(1).getMBB()) ||
134 ((Opc == AArch64::CBNZW || Opc == AArch64::CBNZX) &&
135 MBB != CondBr.getOperand(1).getMBB())) {
137 KnownRegs.push_back(RegImm(CondBr.getOperand(0).getReg(), 0));
142 if (Opc != AArch64::Bcc)
158 "Conditional branch not in predecessor block!");
159 if (CondBr == PredMBB->
begin())
164 DomBBClobberedRegs.
clear();
165 DomBBUsedRegs.
clear();
172 switch (PredI.getOpcode()) {
177 case AArch64::ADDSWri:
178 case AArch64::ADDSXri:
182 case AArch64::SUBSWri:
183 case AArch64::SUBSXri: {
185 if (!PredI.getOperand(1).isReg())
187 MCPhysReg DstReg = PredI.getOperand(0).getReg();
188 MCPhysReg SrcReg = PredI.getOperand(1).getReg();
195 if (PredI.getOperand(2).isImm() && DomBBClobberedRegs.
available(SrcReg) &&
198 int32_t KnownImm = PredI.getOperand(2).getImm();
199 int32_t Shift = PredI.getOperand(3).getImm();
202 KnownImm = -KnownImm;
204 KnownRegs.push_back(RegImm(SrcReg, KnownImm));
210 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
215 if (!DomBBClobberedRegs.
available(DstReg))
219 KnownRegs.push_back(RegImm(DstReg, 0));
225 case AArch64::ADCSWr:
226 case AArch64::ADCSXr:
227 case AArch64::ADDSWrr:
228 case AArch64::ADDSWrs:
229 case AArch64::ADDSWrx:
230 case AArch64::ADDSXrr:
231 case AArch64::ADDSXrs:
232 case AArch64::ADDSXrx:
233 case AArch64::ADDSXrx64:
234 case AArch64::ANDSWri:
235 case AArch64::ANDSWrr:
236 case AArch64::ANDSWrs:
237 case AArch64::ANDSXri:
238 case AArch64::ANDSXrr:
239 case AArch64::ANDSXrs:
240 case AArch64::BICSWrr:
241 case AArch64::BICSWrs:
242 case AArch64::BICSXrs:
243 case AArch64::BICSXrr:
244 case AArch64::SBCSWr:
245 case AArch64::SBCSXr:
246 case AArch64::SUBSWrr:
247 case AArch64::SUBSWrs:
248 case AArch64::SUBSWrx:
249 case AArch64::SUBSXrr:
250 case AArch64::SUBSXrs:
251 case AArch64::SUBSXrx:
252 case AArch64::SUBSXrx64: {
253 MCPhysReg DstReg = PredI.getOperand(0).getReg();
254 if (DstReg == AArch64::WZR || DstReg == AArch64::XZR)
259 if (!DomBBClobberedRegs.
available(DstReg))
264 KnownRegs.push_back(RegImm(DstReg, 0));
270 if (PredI.definesRegister(AArch64::NZCV))
292 if (CondBr == PredMBB->
end())
303 bool SeenFirstUse =
false;
311 if (!knownRegValInBlock(*Itr, MBB, KnownRegs, FirstUse))
315 OptBBClobberedRegs.
clear();
316 OptBBUsedRegs.
clear();
320 for (
auto PredI = Itr;; --PredI) {
321 if (FirstUse == PredI)
324 if (PredI->isCopy()) {
325 MCPhysReg CopyDstReg = PredI->getOperand(0).getReg();
326 MCPhysReg CopySrcReg = PredI->getOperand(1).getReg();
327 for (
auto &KnownReg : KnownRegs) {
328 if (!OptBBClobberedRegs.
available(KnownReg.Reg))
332 if (CopySrcReg == KnownReg.Reg &&
333 OptBBClobberedRegs.
available(CopyDstReg)) {
334 KnownRegs.push_back(RegImm(CopyDstReg, KnownReg.Imm));
341 if (CopyDstReg == KnownReg.Reg &&
342 OptBBClobberedRegs.
available(CopySrcReg)) {
343 KnownRegs.push_back(RegImm(CopySrcReg, KnownReg.Imm));
352 if (PredI == PredMBB->
begin())
358 if (
all_of(KnownRegs, [&](RegImm KnownReg) {
359 return !OptBBClobberedRegs.
available(KnownReg.Reg);
365 }
while (Itr != PredMBB->
begin() && Itr->isTerminator());
368 if (KnownRegs.
empty())
371 bool Changed =
false;
379 bool RemovedMI =
false;
380 bool IsCopy = MI->
isCopy();
382 if (IsCopy || IsMoveImm) {
387 ((IsCopy && (SrcReg == AArch64::XZR || SrcReg == AArch64::WZR)) ||
389 for (RegImm &KnownReg : KnownRegs) {
390 if (KnownReg.Reg != DefReg &&
395 if (IsCopy && KnownReg.Imm != 0)
401 if (KnownReg.Imm != SrcImm)
408 return !
O.isDead() &&
O.isReg() &&
O.isDef() &&
409 O.getReg() != CmpReg;
423 UsedKnownRegs.
insert(KnownReg.Reg);
435 for (
unsigned RI = 0; RI < KnownRegs.
size();)
446 if (KnownRegs.
empty())
461 LLVM_DEBUG(
dbgs() <<
"Clearing kill flags.\n\tFirstUse: " << *FirstUse
462 <<
"\tLastChange: " << *LastChange);
471 bool AArch64RedundantCopyElimination::runOnMachineFunction(
480 DomBBClobberedRegs.
init(*TRI);
481 DomBBUsedRegs.
init(*TRI);
482 OptBBClobberedRegs.
init(*TRI);
483 OptBBUsedRegs.
init(*TRI);
485 bool Changed =
false;
487 Changed |= optimizeBlock(&MBB);
492 return new AArch64RedundantCopyElimination();
bool modifiesRegister(unsigned Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr modifies (fully define or partially define) the specified register...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
This class represents lattice values for constants.
INITIALIZE_PASS(AArch64RedundantCopyElimination, "aarch64-copyelim", "AArch64 redundant copy elimination pass", false, false) bool AArch64RedundantCopyElimination
It's possible to determine the value of a register based on a dominating condition.
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...
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 getReg() const
getReg - Returns the register number.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly...
STATISTIC(NumFunctions, "Total number of functions")
unsigned const TargetRegisterInfo * TRI
void initializeAArch64RedundantCopyEliminationPass(PassRegistry &)
bool isMoveImmediate(QueryType Type=IgnoreBundle) const
Return true if this instruction is a move immediate (including conditional moves) instruction...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
FunctionPass * createAArch64RedundantCopyEliminationPass()
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool available(MCPhysReg Reg) const
Returns true if no part of physical register Reg is live.
iterator getLastNonDebugInstr()
Returns an iterator to the last non-debug instruction in the basic block, or end().
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
bool isSuperRegister(unsigned RegA, unsigned RegB) const
Returns true if RegB is a super-register of RegA.
void addLiveIn(MCPhysReg PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
void init(const TargetRegisterInfo &TRI)
Initialize and clear the set.
unsigned const MachineRegisterInfo * MRI
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly...
FunctionPass class - This class is used to implement most global optimizations.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
pred_iterator pred_begin()
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
A SetVector that performs no allocations if smaller than a certain size.
MachineOperand class - Representation of each machine instruction operand.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
unsigned pred_size() const
const Function & getFunction() const
Return the LLVM function that this machine code represents.
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.
bool isLiveIn(MCPhysReg Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
iterator_range< mop_iterator > implicit_operands()
unsigned succ_size() const
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
MachineFunctionProperties & set(Property P)
Representation of each machine instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
LLVM_NODISCARD bool empty() const
void clear()
Clears the set.
A set of register units used to track register liveness.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
StringRef - Represent a constant reference to a string, i.e.
const MachineOperand & getOperand(unsigned i) const
Properties which a MachineFunction may have at a given point in time.
bool isReserved(unsigned PhysReg) const
isReserved - Returns true when PhysReg is a reserved register.