38 #define DEBUG_TYPE "x86-cf-opt"
42 cl::desc(
"Avoid optimizing x86 call frames for size"),
56 :
Call(nullptr), SPCopy(nullptr), ExpectedDist(0),
57 MovVector(4, nullptr), NoStackParams(
false), UsePush(
false){};
88 const CallContext &Context);
93 enum InstClassification { Convert, Skip, Exit };
100 const char *getPassName()
const override {
return "X86 Optimize Call Frame"; }
112 return new X86CallFrameOptimization();
138 unsigned FrameSetupOpcode =
TII->getCallFrameSetupOpcode();
139 unsigned FrameDestroyOpcode =
TII->getCallFrameDestroyOpcode();
141 bool InsideFrameSequence =
false;
143 if (
MI.getOpcode() == FrameSetupOpcode) {
144 if (InsideFrameSequence)
146 InsideFrameSequence =
true;
147 }
else if (
MI.getOpcode() == FrameDestroyOpcode) {
148 if (!InsideFrameSequence)
150 InsideFrameSequence =
false;
154 if (InsideFrameSequence)
164 ContextMap &CallSeqMap) {
169 if (CannotReserveFrame)
180 unsigned StackAlign = TFL->getStackAlignment();
182 int64_t Advantage = 0;
183 for (
auto CC : CallSeqMap) {
187 if (CC.second.NoStackParams)
190 if (!CC.second.UsePush) {
203 if (CC.second.ExpectedDist % StackAlign)
207 Advantage += (CC.second.ExpectedDist / 4) * 3;
211 return (Advantage >= 0);
214 bool X86CallFrameOptimization::runOnMachineFunction(
MachineFunction &MF) {
222 unsigned FrameSetupOpcode =
TII->getCallFrameSetupOpcode();
224 bool Changed =
false;
226 ContextMap CallSeqMap;
230 if (
I->getOpcode() == FrameSetupOpcode) {
231 CallContext &Context = CallSeqMap[
I];
232 collectCallInfo(MF, *BB,
I, Context);
235 if (!isProfitable(MF, CallSeqMap))
238 for (
auto CC : CallSeqMap)
239 if (CC.second.UsePush)
240 Changed |= adjustCallSequence(MF, CC.first, CC.second);
245 X86CallFrameOptimization::InstClassification
246 X86CallFrameOptimization::classifyInstruction(
253 int Opcode = MI->getOpcode();
254 if (Opcode == X86::MOV32mi || Opcode == X86::MOV32mr)
282 if (MI->isCall() || MI->mayStore())
288 unsigned int Reg = MO.getReg();
289 if (!RegInfo.isPhysicalRegister(Reg))
294 for (
unsigned int U : UsedRegs)
295 if (RegInfo.regsOverlap(Reg, U))
306 CallContext &Context) {
312 unsigned FrameDestroyOpcode =
TII->getCallFrameDestroyOpcode();
315 assert(I->getOpcode() ==
TII->getCallFrameSetupOpcode());
320 unsigned int MaxAdjust = FrameSetup->getOperand(0).getImm() / 4;
324 Context.NoStackParams =
true;
331 while (I->getOpcode() == X86::LEA32r)
338 if (!I->isCopy() || !I->getOperand(0).isReg())
340 Context.SPCopy = I++;
341 StackPtr = Context.SPCopy->getOperand(0).getReg();
348 Context.MovVector.resize(MaxAdjust,
nullptr);
350 InstClassification Classification;
353 while ((Classification = classifyInstruction(MBB, I, RegInfo, UsedRegs)) !=
355 if (Classification == Skip) {
379 assert(StackDisp >= 0 &&
380 "Negative stack displacement when passing parameters");
387 assert((
size_t)StackDisp < Context.MovVector.size() &&
388 "Function call has more parameters than the stack is adjusted for.");
391 if (Context.MovVector[StackDisp] !=
nullptr)
393 Context.MovVector[StackDisp] =
I;
398 unsigned int Reg = MO.getReg();
399 if (RegInfo.isPhysicalRegister(Reg))
408 if (I == MBB.
end() || !I->isCall())
412 if ((++I)->getOpcode() != FrameDestroyOpcode)
417 auto MMI = Context.MovVector.begin(), MME = Context.MovVector.end();
418 for (; MMI != MME; ++MMI, Context.ExpectedDist += 4)
423 if (MMI == Context.MovVector.begin())
428 for (; MMI != MME; ++MMI)
432 Context.UsePush =
true;
438 const CallContext &Context) {
444 FrameSetup->getOperand(1).setImm(Context.ExpectedDist);
450 for (
int Idx = (Context.ExpectedDist / 4) - 1; Idx >= 0; --Idx) {
453 if (MOV->getOpcode() == X86::MOV32mi) {
454 unsigned PushOpcode = X86::PUSHi32;
459 if (PushOp.
isImm()) {
460 int64_t Val = PushOp.
getImm();
462 PushOpcode = X86::PUSH32i8;
464 BuildMI(MBB, Context.Call, DL,
TII->get(PushOpcode)).addOperand(PushOp);
466 unsigned int Reg = PushOp.
getReg();
476 if (!SlowPUSHrmm && (DefMov = canFoldIntoRegPush(FrameSetup, Reg))) {
478 BuildMI(MBB, Context.Call, DL,
TII->get(X86::PUSH32rmm));
486 BuildMI(MBB, Context.Call, DL,
TII->get(X86::PUSH32r))
497 if (MRI->use_empty(Context.SPCopy->getOperand(0).getReg()))
498 Context.SPCopy->eraseFromParent();
508 MachineInstr *X86CallFrameOptimization::canFoldIntoRegPush(
524 if (!MRI->hasOneNonDBGUse(Reg))
531 if (DefMI->getOpcode() != X86::MOV32rm ||
532 DefMI->getParent() != FrameSetup->getParent())
540 for (
auto I = DefMI; I != FrameSetup; ++
I)
541 if (I->getOpcode() != X86::MOV32rm)
AddrSegmentReg - The operand # of the segment in the memory operand.
DenseSet - This implements a dense probed hash-table based set.
static bool isVirtualRegister(unsigned Reg)
isVirtualRegister - Return true if the specified register number is in the virtual register namespace...
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
FunctionPass * createX86CallFrameOptimization()
createX86CallFrameOptimization - Return a pass that optimizes the code-size of x86 call sequences...
const Function * getFunction() const
getFunction - Return the LLVM function that this machine code represents
X86MachineFunctionInfo - This class is derived from MachineFunction and contains private X86 target-s...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool isInt< 8 >(int64_t x)
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
Reg
All possible values of the reg field in the ModR/M byte.
AddrNumOperands - Total number of operands in a memory reference.
bool is64Bit() const
Is this x86_64? (disregarding specific ABI / programming model)
void setHasPushSequences(bool HasPush)
TargetInstrInfo - Interface to description of machine instruction set.
bundle_iterator< MachineInstr, instr_iterator > iterator
initializer< Ty > init(const Ty &Val)
const MachineOperand & getOperand(unsigned i) const
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
FunctionPass class - This class is used to implement most global optimizations.
MachineInstrBuilder BuildMI(MachineFunction &MF, DebugLoc DL, const MCInstrDesc &MCID)
BuildMI - Builder interface.
unsigned getStackRegister() const
virtual const TargetFrameLowering * getFrameLowering() const
std::pair< iterator, bool > insert(const ValueT &V)
void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
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...
Information about stack frame layout on the target.
MachineFrameInfo * getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
static cl::opt< bool > NoX86CFOpt("no-x86-call-frame-opt", cl::desc("Avoid optimizing x86 call frames for size"), cl::init(false), cl::Hidden)
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
Representation of each machine instruction.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
unsigned getReg() const
getReg - Returns the register number.
virtual const TargetInstrInfo * getInstrInfo() const
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
BasicBlockListType::iterator iterator
virtual const TargetRegisterInfo * getRegisterInfo() const
getRegisterInfo - If register information is available, return it.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly. ...
Function must be optimized for size first.