| //===-- X86FixupLEAs.cpp - use or replace LEA instructions -----------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the pass that finds instructions that can be |
| // re-written as LEA instructions in order to reduce pipeline delays. |
| // It replaces LEAs with ADD/INC/DEC when that is better for size/speed. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "X86.h" |
| #include "X86InstrInfo.h" |
| #include "X86Subtarget.h" |
| #include "llvm/ADT/Statistic.h" |
| #include "llvm/CodeGen/MachineFunctionPass.h" |
| #include "llvm/CodeGen/MachineInstrBuilder.h" |
| #include "llvm/CodeGen/Passes.h" |
| #include "llvm/CodeGen/TargetSchedule.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/raw_ostream.h" |
| using namespace llvm; |
| |
| #define FIXUPLEA_DESC "X86 LEA Fixup" |
| #define FIXUPLEA_NAME "x86-fixup-LEAs" |
| |
| #define DEBUG_TYPE FIXUPLEA_NAME |
| |
| STATISTIC(NumLEAs, "Number of LEA instructions created"); |
| |
| namespace { |
| class FixupLEAPass : public MachineFunctionPass { |
| enum RegUsageState { RU_NotUsed, RU_Write, RU_Read }; |
| |
| /// Given a machine register, look for the instruction |
| /// which writes it in the current basic block. If found, |
| /// try to replace it with an equivalent LEA instruction. |
| /// If replacement succeeds, then also process the newly created |
| /// instruction. |
| void seekLEAFixup(MachineOperand &p, MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB); |
| |
| /// Given a memory access or LEA instruction |
| /// whose address mode uses a base and/or index register, look for |
| /// an opportunity to replace the instruction which sets the base or index |
| /// register with an equivalent LEA instruction. |
| void processInstruction(MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB); |
| |
| /// Given a LEA instruction which is unprofitable |
| /// on SlowLEA targets try to replace it with an equivalent ADD instruction. |
| void processInstructionForSlowLEA(MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB); |
| |
| /// Given a LEA instruction which is unprofitable |
| /// on SNB+ try to replace it with other instructions. |
| /// According to Intel's Optimization Reference Manual: |
| /// " For LEA instructions with three source operands and some specific |
| /// situations, instruction latency has increased to 3 cycles, and must |
| /// dispatch via port 1: |
| /// - LEA that has all three source operands: base, index, and offset |
| /// - LEA that uses base and index registers where the base is EBP, RBP, |
| /// or R13 |
| /// - LEA that uses RIP relative addressing mode |
| /// - LEA that uses 16-bit addressing mode " |
| /// This function currently handles the first 2 cases only. |
| void processInstrForSlow3OpLEA(MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB, bool OptIncDec); |
| |
| /// Look for LEAs that are really two address LEAs that we might be able to |
| /// turn into regular ADD instructions. |
| bool optTwoAddrLEA(MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB, bool OptIncDec, |
| bool UseLEAForSP) const; |
| |
| /// Determine if an instruction references a machine register |
| /// and, if so, whether it reads or writes the register. |
| RegUsageState usesRegister(MachineOperand &p, MachineBasicBlock::iterator I); |
| |
| /// Step backwards through a basic block, looking |
| /// for an instruction which writes a register within |
| /// a maximum of INSTR_DISTANCE_THRESHOLD instruction latency cycles. |
| MachineBasicBlock::iterator searchBackwards(MachineOperand &p, |
| MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB); |
| |
| /// if an instruction can be converted to an |
| /// equivalent LEA, insert the new instruction into the basic block |
| /// and return a pointer to it. Otherwise, return zero. |
| MachineInstr *postRAConvertToLEA(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator &MBBI) const; |
| |
| public: |
| static char ID; |
| |
| StringRef getPassName() const override { return FIXUPLEA_DESC; } |
| |
| FixupLEAPass() : MachineFunctionPass(ID) { } |
| |
| /// Loop over all of the basic blocks, |
| /// replacing instructions by equivalent LEA instructions |
| /// if needed and when possible. |
| bool runOnMachineFunction(MachineFunction &MF) override; |
| |
| // This pass runs after regalloc and doesn't support VReg operands. |
| MachineFunctionProperties getRequiredProperties() const override { |
| return MachineFunctionProperties().set( |
| MachineFunctionProperties::Property::NoVRegs); |
| } |
| |
| private: |
| TargetSchedModel TSM; |
| const X86InstrInfo *TII = nullptr; |
| const X86RegisterInfo *TRI = nullptr; |
| }; |
| } |
| |
| char FixupLEAPass::ID = 0; |
| |
| INITIALIZE_PASS(FixupLEAPass, FIXUPLEA_NAME, FIXUPLEA_DESC, false, false) |
| |
| MachineInstr * |
| FixupLEAPass::postRAConvertToLEA(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator &MBBI) const { |
| MachineInstr &MI = *MBBI; |
| switch (MI.getOpcode()) { |
| case X86::MOV32rr: |
| case X86::MOV64rr: { |
| const MachineOperand &Src = MI.getOperand(1); |
| const MachineOperand &Dest = MI.getOperand(0); |
| MachineInstr *NewMI = |
| BuildMI(MBB, MBBI, MI.getDebugLoc(), |
| TII->get(MI.getOpcode() == X86::MOV32rr ? X86::LEA32r |
| : X86::LEA64r)) |
| .add(Dest) |
| .add(Src) |
| .addImm(1) |
| .addReg(0) |
| .addImm(0) |
| .addReg(0); |
| return NewMI; |
| } |
| } |
| |
| if (!MI.isConvertibleTo3Addr()) |
| return nullptr; |
| |
| switch (MI.getOpcode()) { |
| default: |
| // Only convert instructions that we've verified are safe. |
| return nullptr; |
| case X86::ADD64ri32: |
| case X86::ADD64ri8: |
| case X86::ADD64ri32_DB: |
| case X86::ADD64ri8_DB: |
| case X86::ADD32ri: |
| case X86::ADD32ri8: |
| case X86::ADD32ri_DB: |
| case X86::ADD32ri8_DB: |
| if (!MI.getOperand(2).isImm()) { |
| // convertToThreeAddress will call getImm() |
| // which requires isImm() to be true |
| return nullptr; |
| } |
| break; |
| case X86::SHL64ri: |
| case X86::SHL32ri: |
| case X86::INC64r: |
| case X86::INC32r: |
| case X86::DEC64r: |
| case X86::DEC32r: |
| case X86::ADD64rr: |
| case X86::ADD64rr_DB: |
| case X86::ADD32rr: |
| case X86::ADD32rr_DB: |
| // These instructions are all fine to convert. |
| break; |
| } |
| MachineFunction::iterator MFI = MBB.getIterator(); |
| return TII->convertToThreeAddress(MFI, MI, nullptr); |
| } |
| |
| FunctionPass *llvm::createX86FixupLEAs() { return new FixupLEAPass(); } |
| |
| static bool isLEA(unsigned Opcode) { |
| return Opcode == X86::LEA32r || Opcode == X86::LEA64r || |
| Opcode == X86::LEA64_32r; |
| } |
| |
| bool FixupLEAPass::runOnMachineFunction(MachineFunction &MF) { |
| if (skipFunction(MF.getFunction())) |
| return false; |
| |
| const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>(); |
| bool IsSlowLEA = ST.slowLEA(); |
| bool IsSlow3OpsLEA = ST.slow3OpsLEA(); |
| bool LEAUsesAG = ST.LEAusesAG(); |
| |
| bool OptIncDec = !ST.slowIncDec() || MF.getFunction().hasOptSize(); |
| bool UseLEAForSP = ST.useLeaForSP(); |
| |
| TSM.init(&ST); |
| TII = ST.getInstrInfo(); |
| TRI = ST.getRegisterInfo(); |
| |
| LLVM_DEBUG(dbgs() << "Start X86FixupLEAs\n";); |
| for (MachineBasicBlock &MBB : MF) { |
| // First pass. Try to remove or optimize existing LEAs. |
| for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { |
| if (!isLEA(I->getOpcode())) |
| continue; |
| |
| if (optTwoAddrLEA(I, MBB, OptIncDec, UseLEAForSP)) |
| continue; |
| |
| if (IsSlowLEA) |
| processInstructionForSlowLEA(I, MBB); |
| else if (IsSlow3OpsLEA) |
| processInstrForSlow3OpLEA(I, MBB, OptIncDec); |
| } |
| |
| // Second pass for creating LEAs. This may reverse some of the |
| // transformations above. |
| if (LEAUsesAG) { |
| for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) |
| processInstruction(I, MBB); |
| } |
| } |
| |
| LLVM_DEBUG(dbgs() << "End X86FixupLEAs\n";); |
| |
| return true; |
| } |
| |
| FixupLEAPass::RegUsageState |
| FixupLEAPass::usesRegister(MachineOperand &p, MachineBasicBlock::iterator I) { |
| RegUsageState RegUsage = RU_NotUsed; |
| MachineInstr &MI = *I; |
| |
| for (unsigned i = 0; i < MI.getNumOperands(); ++i) { |
| MachineOperand &opnd = MI.getOperand(i); |
| if (opnd.isReg() && opnd.getReg() == p.getReg()) { |
| if (opnd.isDef()) |
| return RU_Write; |
| RegUsage = RU_Read; |
| } |
| } |
| return RegUsage; |
| } |
| |
| /// getPreviousInstr - Given a reference to an instruction in a basic |
| /// block, return a reference to the previous instruction in the block, |
| /// wrapping around to the last instruction of the block if the block |
| /// branches to itself. |
| static inline bool getPreviousInstr(MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB) { |
| if (I == MBB.begin()) { |
| if (MBB.isPredecessor(&MBB)) { |
| I = --MBB.end(); |
| return true; |
| } else |
| return false; |
| } |
| --I; |
| return true; |
| } |
| |
| MachineBasicBlock::iterator |
| FixupLEAPass::searchBackwards(MachineOperand &p, MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB) { |
| int InstrDistance = 1; |
| MachineBasicBlock::iterator CurInst; |
| static const int INSTR_DISTANCE_THRESHOLD = 5; |
| |
| CurInst = I; |
| bool Found; |
| Found = getPreviousInstr(CurInst, MBB); |
| while (Found && I != CurInst) { |
| if (CurInst->isCall() || CurInst->isInlineAsm()) |
| break; |
| if (InstrDistance > INSTR_DISTANCE_THRESHOLD) |
| break; // too far back to make a difference |
| if (usesRegister(p, CurInst) == RU_Write) { |
| return CurInst; |
| } |
| InstrDistance += TSM.computeInstrLatency(&*CurInst); |
| Found = getPreviousInstr(CurInst, MBB); |
| } |
| return MachineBasicBlock::iterator(); |
| } |
| |
| static inline bool isInefficientLEAReg(unsigned Reg) { |
| return Reg == X86::EBP || Reg == X86::RBP || |
| Reg == X86::R13D || Reg == X86::R13; |
| } |
| |
| /// Returns true if this LEA uses base an index registers, and the base register |
| /// is known to be inefficient for the subtarget. |
| // TODO: use a variant scheduling class to model the latency profile |
| // of LEA instructions, and implement this logic as a scheduling predicate. |
| static inline bool hasInefficientLEABaseReg(const MachineOperand &Base, |
| const MachineOperand &Index) { |
| return Base.isReg() && isInefficientLEAReg(Base.getReg()) && Index.isReg() && |
| Index.getReg() != X86::NoRegister; |
| } |
| |
| static inline bool hasLEAOffset(const MachineOperand &Offset) { |
| return (Offset.isImm() && Offset.getImm() != 0) || Offset.isGlobal(); |
| } |
| |
| static inline unsigned getADDrrFromLEA(unsigned LEAOpcode) { |
| switch (LEAOpcode) { |
| default: |
| llvm_unreachable("Unexpected LEA instruction"); |
| case X86::LEA32r: |
| case X86::LEA64_32r: |
| return X86::ADD32rr; |
| case X86::LEA64r: |
| return X86::ADD64rr; |
| } |
| } |
| |
| static inline unsigned getADDriFromLEA(unsigned LEAOpcode, |
| const MachineOperand &Offset) { |
| bool IsInt8 = Offset.isImm() && isInt<8>(Offset.getImm()); |
| switch (LEAOpcode) { |
| default: |
| llvm_unreachable("Unexpected LEA instruction"); |
| case X86::LEA32r: |
| case X86::LEA64_32r: |
| return IsInt8 ? X86::ADD32ri8 : X86::ADD32ri; |
| case X86::LEA64r: |
| return IsInt8 ? X86::ADD64ri8 : X86::ADD64ri32; |
| } |
| } |
| |
| static inline unsigned getINCDECFromLEA(unsigned LEAOpcode, bool IsINC) { |
| switch (LEAOpcode) { |
| default: |
| llvm_unreachable("Unexpected LEA instruction"); |
| case X86::LEA32r: |
| case X86::LEA64_32r: |
| return IsINC ? X86::INC32r : X86::DEC32r; |
| case X86::LEA64r: |
| return IsINC ? X86::INC64r : X86::DEC64r; |
| } |
| } |
| |
| bool FixupLEAPass::optTwoAddrLEA(MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB, bool OptIncDec, |
| bool UseLEAForSP) const { |
| MachineInstr &MI = *I; |
| |
| const MachineOperand &Base = MI.getOperand(1 + X86::AddrBaseReg); |
| const MachineOperand &Scale = MI.getOperand(1 + X86::AddrScaleAmt); |
| const MachineOperand &Index = MI.getOperand(1 + X86::AddrIndexReg); |
| const MachineOperand &Disp = MI.getOperand(1 + X86::AddrDisp); |
| const MachineOperand &Segment = MI.getOperand(1 + X86::AddrSegmentReg); |
| |
| if (Segment.getReg() != 0 || !Disp.isImm() || Scale.getImm() > 1 || |
| !TII->isSafeToClobberEFLAGS(MBB, I)) |
| return false; |
| |
| Register DestReg = MI.getOperand(0).getReg(); |
| Register BaseReg = Base.getReg(); |
| Register IndexReg = Index.getReg(); |
| |
| // Don't change stack adjustment LEAs. |
| if (UseLEAForSP && (DestReg == X86::ESP || DestReg == X86::RSP)) |
| return false; |
| |
| // LEA64_32 has 64-bit operands but 32-bit result. |
| if (MI.getOpcode() == X86::LEA64_32r) { |
| if (BaseReg != 0) |
| BaseReg = TRI->getSubReg(BaseReg, X86::sub_32bit); |
| if (IndexReg != 0) |
| IndexReg = TRI->getSubReg(IndexReg, X86::sub_32bit); |
| } |
| |
| MachineInstr *NewMI = nullptr; |
| |
| // Look for lea(%reg1, %reg2), %reg1 or lea(%reg2, %reg1), %reg1 |
| // which can be turned into add %reg2, %reg1 |
| if (BaseReg != 0 && IndexReg != 0 && Disp.getImm() == 0 && |
| (DestReg == BaseReg || DestReg == IndexReg)) { |
| unsigned NewOpcode = getADDrrFromLEA(MI.getOpcode()); |
| if (DestReg != BaseReg) |
| std::swap(BaseReg, IndexReg); |
| |
| if (MI.getOpcode() == X86::LEA64_32r) { |
| // TODO: Do we need the super register implicit use? |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpcode), DestReg) |
| .addReg(BaseReg).addReg(IndexReg) |
| .addReg(Base.getReg(), RegState::Implicit) |
| .addReg(Index.getReg(), RegState::Implicit); |
| } else { |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpcode), DestReg) |
| .addReg(BaseReg).addReg(IndexReg); |
| } |
| } else if (DestReg == BaseReg && IndexReg == 0) { |
| // This is an LEA with only a base register and a displacement, |
| // We can use ADDri or INC/DEC. |
| |
| // Does this LEA have one these forms: |
| // lea %reg, 1(%reg) |
| // lea %reg, -1(%reg) |
| if (OptIncDec && (Disp.getImm() == 1 || Disp.getImm() == -1)) { |
| bool IsINC = Disp.getImm() == 1; |
| unsigned NewOpcode = getINCDECFromLEA(MI.getOpcode(), IsINC); |
| |
| if (MI.getOpcode() == X86::LEA64_32r) { |
| // TODO: Do we need the super register implicit use? |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpcode), DestReg) |
| .addReg(BaseReg).addReg(Base.getReg(), RegState::Implicit); |
| } else { |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpcode), DestReg) |
| .addReg(BaseReg); |
| } |
| } else { |
| unsigned NewOpcode = getADDriFromLEA(MI.getOpcode(), Disp); |
| if (MI.getOpcode() == X86::LEA64_32r) { |
| // TODO: Do we need the super register implicit use? |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpcode), DestReg) |
| .addReg(BaseReg).addImm(Disp.getImm()) |
| .addReg(Base.getReg(), RegState::Implicit); |
| } else { |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpcode), DestReg) |
| .addReg(BaseReg).addImm(Disp.getImm()); |
| } |
| } |
| } else |
| return false; |
| |
| MBB.erase(I); |
| I = NewMI; |
| return true; |
| } |
| |
| void FixupLEAPass::processInstruction(MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB) { |
| // Process a load, store, or LEA instruction. |
| MachineInstr &MI = *I; |
| const MCInstrDesc &Desc = MI.getDesc(); |
| int AddrOffset = X86II::getMemoryOperandNo(Desc.TSFlags); |
| if (AddrOffset >= 0) { |
| AddrOffset += X86II::getOperandBias(Desc); |
| MachineOperand &p = MI.getOperand(AddrOffset + X86::AddrBaseReg); |
| if (p.isReg() && p.getReg() != X86::ESP) { |
| seekLEAFixup(p, I, MBB); |
| } |
| MachineOperand &q = MI.getOperand(AddrOffset + X86::AddrIndexReg); |
| if (q.isReg() && q.getReg() != X86::ESP) { |
| seekLEAFixup(q, I, MBB); |
| } |
| } |
| } |
| |
| void FixupLEAPass::seekLEAFixup(MachineOperand &p, |
| MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB) { |
| MachineBasicBlock::iterator MBI = searchBackwards(p, I, MBB); |
| if (MBI != MachineBasicBlock::iterator()) { |
| MachineInstr *NewMI = postRAConvertToLEA(MBB, MBI); |
| if (NewMI) { |
| ++NumLEAs; |
| LLVM_DEBUG(dbgs() << "FixLEA: Candidate to replace:"; MBI->dump();); |
| // now to replace with an equivalent LEA... |
| LLVM_DEBUG(dbgs() << "FixLEA: Replaced by: "; NewMI->dump();); |
| MBB.erase(MBI); |
| MachineBasicBlock::iterator J = |
| static_cast<MachineBasicBlock::iterator>(NewMI); |
| processInstruction(J, MBB); |
| } |
| } |
| } |
| |
| void FixupLEAPass::processInstructionForSlowLEA(MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB) { |
| MachineInstr &MI = *I; |
| const unsigned Opcode = MI.getOpcode(); |
| |
| const MachineOperand &Dst = MI.getOperand(0); |
| const MachineOperand &Base = MI.getOperand(1 + X86::AddrBaseReg); |
| const MachineOperand &Scale = MI.getOperand(1 + X86::AddrScaleAmt); |
| const MachineOperand &Index = MI.getOperand(1 + X86::AddrIndexReg); |
| const MachineOperand &Offset = MI.getOperand(1 + X86::AddrDisp); |
| const MachineOperand &Segment = MI.getOperand(1 + X86::AddrSegmentReg); |
| |
| if (Segment.getReg() != 0 || !Offset.isImm() || |
| !TII->isSafeToClobberEFLAGS(MBB, I)) |
| return; |
| const Register DstR = Dst.getReg(); |
| const Register SrcR1 = Base.getReg(); |
| const Register SrcR2 = Index.getReg(); |
| if ((SrcR1 == 0 || SrcR1 != DstR) && (SrcR2 == 0 || SrcR2 != DstR)) |
| return; |
| if (Scale.getImm() > 1) |
| return; |
| LLVM_DEBUG(dbgs() << "FixLEA: Candidate to replace:"; I->dump();); |
| LLVM_DEBUG(dbgs() << "FixLEA: Replaced by: ";); |
| MachineInstr *NewMI = nullptr; |
| // Make ADD instruction for two registers writing to LEA's destination |
| if (SrcR1 != 0 && SrcR2 != 0) { |
| const MCInstrDesc &ADDrr = TII->get(getADDrrFromLEA(Opcode)); |
| const MachineOperand &Src = SrcR1 == DstR ? Index : Base; |
| NewMI = |
| BuildMI(MBB, I, MI.getDebugLoc(), ADDrr, DstR).addReg(DstR).add(Src); |
| LLVM_DEBUG(NewMI->dump();); |
| } |
| // Make ADD instruction for immediate |
| if (Offset.getImm() != 0) { |
| const MCInstrDesc &ADDri = |
| TII->get(getADDriFromLEA(Opcode, Offset)); |
| const MachineOperand &SrcR = SrcR1 == DstR ? Base : Index; |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), ADDri, DstR) |
| .add(SrcR) |
| .addImm(Offset.getImm()); |
| LLVM_DEBUG(NewMI->dump();); |
| } |
| if (NewMI) { |
| MBB.erase(I); |
| I = NewMI; |
| } |
| } |
| |
| void FixupLEAPass::processInstrForSlow3OpLEA(MachineBasicBlock::iterator &I, |
| MachineBasicBlock &MBB, |
| bool OptIncDec) { |
| MachineInstr &MI = *I; |
| const unsigned LEAOpcode = MI.getOpcode(); |
| |
| const MachineOperand &Dest = MI.getOperand(0); |
| const MachineOperand &Base = MI.getOperand(1 + X86::AddrBaseReg); |
| const MachineOperand &Scale = MI.getOperand(1 + X86::AddrScaleAmt); |
| const MachineOperand &Index = MI.getOperand(1 + X86::AddrIndexReg); |
| const MachineOperand &Offset = MI.getOperand(1 + X86::AddrDisp); |
| const MachineOperand &Segment = MI.getOperand(1 + X86::AddrSegmentReg); |
| |
| if (!(TII->isThreeOperandsLEA(MI) || hasInefficientLEABaseReg(Base, Index)) || |
| !TII->isSafeToClobberEFLAGS(MBB, MI) || |
| Segment.getReg() != X86::NoRegister) |
| return; |
| |
| Register DestReg = Dest.getReg(); |
| Register BaseReg = Base.getReg(); |
| Register IndexReg = Index.getReg(); |
| |
| if (MI.getOpcode() == X86::LEA64_32r) { |
| if (BaseReg != 0) |
| BaseReg = TRI->getSubReg(BaseReg, X86::sub_32bit); |
| if (IndexReg != 0) |
| IndexReg = TRI->getSubReg(IndexReg, X86::sub_32bit); |
| } |
| |
| bool IsScale1 = Scale.getImm() == 1; |
| bool IsInefficientBase = isInefficientLEAReg(BaseReg); |
| bool IsInefficientIndex = isInefficientLEAReg(IndexReg); |
| |
| // Skip these cases since it takes more than 2 instructions |
| // to replace the LEA instruction. |
| if (IsInefficientBase && DestReg == BaseReg && !IsScale1) |
| return; |
| |
| LLVM_DEBUG(dbgs() << "FixLEA: Candidate to replace:"; MI.dump();); |
| LLVM_DEBUG(dbgs() << "FixLEA: Replaced by: ";); |
| |
| MachineInstr *NewMI = nullptr; |
| |
| // First try to replace LEA with one or two (for the 3-op LEA case) |
| // add instructions: |
| // 1.lea (%base,%index,1), %base => add %index,%base |
| // 2.lea (%base,%index,1), %index => add %base,%index |
| if (IsScale1 && (DestReg == BaseReg || DestReg == IndexReg)) { |
| unsigned NewOpc = getADDrrFromLEA(MI.getOpcode()); |
| if (DestReg != BaseReg) |
| std::swap(BaseReg, IndexReg); |
| |
| if (MI.getOpcode() == X86::LEA64_32r) { |
| // TODO: Do we need the super register implicit use? |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpc), DestReg) |
| .addReg(BaseReg) |
| .addReg(IndexReg) |
| .addReg(Base.getReg(), RegState::Implicit) |
| .addReg(Index.getReg(), RegState::Implicit); |
| } else { |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpc), DestReg) |
| .addReg(BaseReg) |
| .addReg(IndexReg); |
| } |
| } else if (!IsInefficientBase || (!IsInefficientIndex && IsScale1)) { |
| // If the base is inefficient try switching the index and base operands, |
| // otherwise just break the 3-Ops LEA inst into 2-Ops LEA + ADD instruction: |
| // lea offset(%base,%index,scale),%dst => |
| // lea (%base,%index,scale); add offset,%dst |
| NewMI = BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(LEAOpcode)) |
| .add(Dest) |
| .add(IsInefficientBase ? Index : Base) |
| .add(Scale) |
| .add(IsInefficientBase ? Base : Index) |
| .addImm(0) |
| .add(Segment); |
| LLVM_DEBUG(NewMI->dump();); |
| } |
| |
| // If either replacement succeeded above, add the offset if needed, then |
| // replace the instruction. |
| if (NewMI) { |
| // Create ADD instruction for the Offset in case of 3-Ops LEA. |
| if (hasLEAOffset(Offset)) { |
| if (OptIncDec && Offset.isImm() && |
| (Offset.getImm() == 1 || Offset.getImm() == -1)) { |
| unsigned NewOpc = |
| getINCDECFromLEA(MI.getOpcode(), Offset.getImm() == 1); |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpc), DestReg) |
| .addReg(DestReg); |
| LLVM_DEBUG(NewMI->dump();); |
| } else { |
| unsigned NewOpc = getADDriFromLEA(MI.getOpcode(), Offset); |
| NewMI = BuildMI(MBB, I, MI.getDebugLoc(), TII->get(NewOpc), DestReg) |
| .addReg(DestReg) |
| .add(Offset); |
| LLVM_DEBUG(NewMI->dump();); |
| } |
| } |
| |
| MBB.erase(I); |
| I = NewMI; |
| return; |
| } |
| |
| // Handle the rest of the cases with inefficient base register: |
| assert(DestReg != BaseReg && "DestReg == BaseReg should be handled already!"); |
| assert(IsInefficientBase && "efficient base should be handled already!"); |
| |
| // FIXME: Handle LEA64_32r. |
| if (LEAOpcode == X86::LEA64_32r) |
| return; |
| |
| // lea (%base,%index,1), %dst => mov %base,%dst; add %index,%dst |
| if (IsScale1 && !hasLEAOffset(Offset)) { |
| bool BIK = Base.isKill() && BaseReg != IndexReg; |
| TII->copyPhysReg(MBB, MI, MI.getDebugLoc(), DestReg, BaseReg, BIK); |
| LLVM_DEBUG(MI.getPrevNode()->dump();); |
| |
| unsigned NewOpc = getADDrrFromLEA(MI.getOpcode()); |
| NewMI = BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(NewOpc), DestReg) |
| .addReg(DestReg) |
| .add(Index); |
| LLVM_DEBUG(NewMI->dump();); |
| |
| MBB.erase(I); |
| I = NewMI; |
| return; |
| } |
| |
| // lea offset(%base,%index,scale), %dst => |
| // lea offset( ,%index,scale), %dst; add %base,%dst |
| NewMI = BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(LEAOpcode)) |
| .add(Dest) |
| .addReg(0) |
| .add(Scale) |
| .add(Index) |
| .add(Offset) |
| .add(Segment); |
| LLVM_DEBUG(NewMI->dump();); |
| |
| unsigned NewOpc = getADDrrFromLEA(MI.getOpcode()); |
| NewMI = BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(NewOpc), DestReg) |
| .addReg(DestReg) |
| .add(Base); |
| LLVM_DEBUG(NewMI->dump();); |
| |
| MBB.erase(I); |
| I = NewMI; |
| } |