52#define DEBUG_TYPE "x86-cf-opt"
56 cl::desc(
"Avoid optimizing x86 call frames for size"),
65 bool runOnMachineFunction(MachineFunction &MF)
override;
72 CallContext() : FrameSetup(nullptr), ArgStoreVector(4, nullptr) {}
78 MachineInstr *Call =
nullptr;
81 MachineInstr *SPCopy =
nullptr;
84 int64_t ExpectedDist = 0;
87 SmallVector<MachineInstr *, 4> ArgStoreVector;
90 bool NoStackParams =
false;
96 typedef SmallVector<CallContext, 8> ContextVector;
98 bool isLegal(MachineFunction &MF);
100 bool isProfitable(MachineFunction &MF, ContextVector &CallSeqMap);
102 void collectCallInfo(MachineFunction &MF, MachineBasicBlock &
MBB,
105 void adjustCallSequence(MachineFunction &MF,
const CallContext &
Context);
110 enum InstClassification { Convert, Skip, Exit };
112 InstClassification classifyInstruction(MachineBasicBlock &
MBB,
114 const X86RegisterInfo &RegInfo,
115 const DenseSet<MCRegister> &UsedRegs);
117 StringRef getPassName()
const override {
return "X86 Optimize Call Frame"; }
119 const X86InstrInfo *TII =
nullptr;
120 const X86FrameLowering *TFL =
nullptr;
121 const X86Subtarget *STI =
nullptr;
122 MachineRegisterInfo *MRI =
nullptr;
123 unsigned SlotSize = 0;
124 unsigned Log2SlotSize = 0;
128char X86CallFrameOptimization::ID = 0;
130 "X86 Call Frame Optimization",
false,
false)
142 if (STI->isTargetDarwin() &&
143 (!MF.getLandingPads().empty() ||
144 (MF.getFunction().needsUnwindTableEntry() && !TFL->hasFP(MF))))
149 if (STI->isTargetWin64())
164 unsigned FrameSetupOpcode =
TII->getCallFrameSetupOpcode();
165 unsigned FrameDestroyOpcode =
TII->getCallFrameDestroyOpcode();
166 bool EmitStackProbeCall = STI->getTargetLowering()->hasStackProbeSymbol(MF);
167 unsigned StackProbeSize = STI->getTargetLowering()->getStackProbeSize(MF);
169 bool InsideFrameSequence =
false;
171 if (
MI.getOpcode() == FrameSetupOpcode) {
172 if (
TII->getFrameSize(
MI) >= StackProbeSize && EmitStackProbeCall)
174 if (InsideFrameSequence)
176 InsideFrameSequence =
true;
177 }
else if (
MI.getOpcode() == FrameDestroyOpcode) {
178 if (!InsideFrameSequence)
180 InsideFrameSequence =
false;
184 if (InsideFrameSequence)
194 ContextVector &CallSeqVector) {
199 if (CannotReserveFrame)
204 int64_t Advantage = 0;
205 for (
const auto &CC : CallSeqVector) {
209 if (CC.NoStackParams)
225 if (!
isAligned(StackAlign, CC.ExpectedDist))
229 Advantage += (CC.ExpectedDist >> Log2SlotSize) * 3;
233 return Advantage >= 0;
236bool X86CallFrameOptimization::runOnMachineFunction(MachineFunction &MF) {
245 Log2SlotSize =
Log2_32(SlotSize);
247 if (skipFunction(MF.
getFunction()) || !isLegal(MF))
250 unsigned FrameSetupOpcode =
TII->getCallFrameSetupOpcode();
254 ContextVector CallSeqVector;
258 if (
MI.getOpcode() == FrameSetupOpcode) {
261 CallSeqVector.push_back(
Context);
267 for (
const auto &CC : CallSeqVector) {
269 adjustCallSequence(MF, CC);
277X86CallFrameOptimization::InstClassification
278X86CallFrameOptimization::classifyInstruction(
280 const X86RegisterInfo &RegInfo,
const DenseSet<MCRegister> &UsedRegs) {
286 switch (
MI->getOpcode()) {
289 case X86::AND64mi32: {
291 return ImmOp.
getImm() == 0 ? Convert : Exit;
295 case X86::OR64mi32: {
297 return ImmOp.
getImm() == -1 ? Convert : Exit;
331 if (
MI->isCall() ||
MI->mayStore())
334 for (
const MachineOperand &MO :
MI->operands()) {
343 for (MCRegister U : UsedRegs)
344 if (RegInfo.regsOverlap(
Reg, U))
352void X86CallFrameOptimization::collectCallInfo(MachineFunction &MF,
353 MachineBasicBlock &
MBB,
361 assert(
I->getOpcode() ==
TII->getCallFrameSetupOpcode());
363 Context.FrameSetup = FrameSetup;
367 unsigned int MaxAdjust =
TII->getFrameSize(*FrameSetup) >> Log2SlotSize;
378 while (
I->getOpcode() == X86::LEA32r ||
I->isDebugInstr())
382 auto StackPtrCopyInst =
MBB.
end();
391 for (
auto J =
I; !J->isCall(); ++J)
392 if (J->isCopy() && J->getOperand(0).isReg() && J->getOperand(1).isReg() &&
393 J->getOperand(1).getReg() == StackPtr) {
394 StackPtrCopyInst = J;
405 Context.ArgStoreVector.resize(MaxAdjust,
nullptr);
407 DenseSet<MCRegister> UsedRegs;
409 for (InstClassification Classification = Skip; Classification != Exit; ++
I) {
411 if (
I == StackPtrCopyInst)
413 Classification = classifyInstruction(
MBB,
I, RegInfo, UsedRegs);
414 if (Classification != Convert)
436 "Negative stack displacement when passing parameters");
439 if (StackDisp & (SlotSize - 1))
441 StackDisp >>= Log2SlotSize;
444 "Function call has more parameters than the stack is adjusted for.");
447 if (
Context.ArgStoreVector[StackDisp] !=
nullptr)
449 Context.ArgStoreVector[StackDisp] = &*
I;
451 for (
const MachineOperand &MO :
I->uses()) {
474 for (; MMI != MME; ++MMI,
Context.ExpectedDist += SlotSize)
479 if (MMI ==
Context.ArgStoreVector.begin())
484 for (; MMI != MME; ++MMI)
491void X86CallFrameOptimization::adjustCallSequence(MachineFunction &MF,
497 MachineBasicBlock &
MBB = *(FrameSetup->getParent());
498 TII->setFrameAdjustment(*FrameSetup,
Context.ExpectedDist);
500 const DebugLoc &
DL = FrameSetup->getDebugLoc();
501 bool Is64Bit = STI->is64Bit();
505 for (
int Idx = (
Context.ExpectedDist >> Log2SlotSize) - 1; Idx >= 0; --Idx) {
510 switch (
Store->getOpcode()) {
521 PushOpcode = Is64Bit ? X86::PUSH64i32 : X86::PUSH32i;
523 Push->cloneMemRefs(MF, *Store);
531 if (Is64Bit &&
Store->getOpcode() == X86::MOV32mr) {
532 Register UndefReg =
MRI->createVirtualRegister(&X86::GR64RegClass);
533 Reg =
MRI->createVirtualRegister(&X86::GR64RegClass);
543 bool SlowPUSHrmm = STI->slowTwoMemOps();
547 MachineInstr *DefMov =
nullptr;
548 if (!SlowPUSHrmm && (DefMov = canFoldIntoRegPush(FrameSetup,
Reg))) {
549 PushOpcode = Is64Bit ? X86::PUSH64rmm : X86::PUSH32rmm;
555 Push->cloneMergedMemRefs(MF, {DefMov, &*
Store});
558 PushOpcode = Is64Bit ? X86::PUSH64r : X86::PUSH32r;
562 Push->cloneMemRefs(MF, *Store);
573 MBB, std::next(Push),
DL,
582 Context.SPCopy->eraseFromParent();
586 X86MachineFunctionInfo *FuncInfo = MF.
getInfo<X86MachineFunctionInfo>();
590MachineInstr *X86CallFrameOptimization::canFoldIntoRegPush(
606 if (!
MRI->hasOneNonDBGUse(
Reg))
613 if ((
DefMI.getOpcode() != X86::MOV32rm &&
614 DefMI.getOpcode() != X86::MOV64rm) ||
615 DefMI.getParent() != FrameSetup->getParent())
621 if (
I->isLoadFoldBarrier())
628 return new X86CallFrameOptimization();
unsigned const MachineRegisterInfo * MRI
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file defines the DenseSet and SmallDenseSet classes.
const HexagonInstrInfo * TII
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file defines the SmallVector class.
static bool isProfitable(const StableFunctionMap::StableFunctionEntries &SFS)
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
static cl::opt< bool > NoX86CFOpt("no-x86-call-frame-opt", cl::desc("Avoid optimizing x86 call frames for size"), cl::init(false), cl::Hidden)
FunctionPass class - This class is used to implement most global optimizations.
static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int64_t Adjustment, SMLoc Loc={})
.cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but Offset is a relative value that is added/subt...
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
MachineInstrBundleIterator< MachineInstr > iterator
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
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.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
Register getReg() const
getReg - Returns the register number.
MCRegister asMCReg() const
Utility to check-convert this value to a MCRegister.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
bool hasFP(const MachineFunction &MF) const
hasFP - Return true if the specified function should have a dedicated frame pointer register.
Align getStackAlign() const
getStackAlignment - This method returns the number of bytes to which the stack pointer must be aligne...
void BuildCFI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, const MCCFIInstruction &CFIInst, MachineInstr::MIFlag Flag=MachineInstr::NoFlags) const
Wraps up getting a CFI index and building a MachineInstr for it.
void setHasPushSequences(bool HasPush)
Register getStackRegister() const
unsigned getSlotSize() const
const X86InstrInfo * getInstrInfo() const override
const X86RegisterInfo * getRegisterInfo() const override
const X86FrameLowering * getFrameLowering() const override
std::pair< iterator, bool > insert(const ValueT &V)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool isAligned(Align Lhs, uint64_t SizeInBytes)
Checks that SizeInBytes is a multiple of the alignment.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
FunctionPass * createX86CallFrameOptimization()
Return a pass that optimizes the code-size of x86 call sequences.