xref: /freebsd/contrib/llvm-project/llvm/lib/Target/X86/X86ArgumentStackSlotRebase.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===---- X86ArgumentStackSlotRebase.cpp - rebase argument stack slot -----===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric //
9*06c3fb27SDimitry Andric // This pass replace the frame register with a GPR virtual register and set
10*06c3fb27SDimitry Andric // the stack offset for each instruction which reference argument from stack.
11*06c3fb27SDimitry Andric //
12*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
13*06c3fb27SDimitry Andric 
14*06c3fb27SDimitry Andric #include "X86.h"
15*06c3fb27SDimitry Andric #include "X86InstrBuilder.h"
16*06c3fb27SDimitry Andric #include "X86MachineFunctionInfo.h"
17*06c3fb27SDimitry Andric #include "X86RegisterInfo.h"
18*06c3fb27SDimitry Andric #include "X86Subtarget.h"
19*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
20*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
21*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
22*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
23*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
24*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
25*06c3fb27SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
26*06c3fb27SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
27*06c3fb27SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
28*06c3fb27SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
29*06c3fb27SDimitry Andric #include "llvm/IR/Attributes.h"
30*06c3fb27SDimitry Andric #include "llvm/IR/Function.h"
31*06c3fb27SDimitry Andric #include "llvm/InitializePasses.h"
32*06c3fb27SDimitry Andric #include "llvm/Pass.h"
33*06c3fb27SDimitry Andric 
34*06c3fb27SDimitry Andric using namespace llvm;
35*06c3fb27SDimitry Andric 
36*06c3fb27SDimitry Andric #define DEBUG_TYPE "x86argumentstackrebase"
37*06c3fb27SDimitry Andric 
38*06c3fb27SDimitry Andric namespace {
39*06c3fb27SDimitry Andric 
40*06c3fb27SDimitry Andric class X86ArgumentStackSlotPass : public MachineFunctionPass {
41*06c3fb27SDimitry Andric 
42*06c3fb27SDimitry Andric public:
43*06c3fb27SDimitry Andric   static char ID; // Pass identification, replacement for typeid
44*06c3fb27SDimitry Andric 
X86ArgumentStackSlotPass()45*06c3fb27SDimitry Andric   explicit X86ArgumentStackSlotPass() : MachineFunctionPass(ID) {
46*06c3fb27SDimitry Andric     initializeX86ArgumentStackSlotPassPass(*PassRegistry::getPassRegistry());
47*06c3fb27SDimitry Andric   }
48*06c3fb27SDimitry Andric 
49*06c3fb27SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
50*06c3fb27SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const51*06c3fb27SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
52*06c3fb27SDimitry Andric     AU.setPreservesCFG();
53*06c3fb27SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
54*06c3fb27SDimitry Andric   }
55*06c3fb27SDimitry Andric };
56*06c3fb27SDimitry Andric 
57*06c3fb27SDimitry Andric } // end anonymous namespace
58*06c3fb27SDimitry Andric 
59*06c3fb27SDimitry Andric char X86ArgumentStackSlotPass::ID = 0;
60*06c3fb27SDimitry Andric 
61*06c3fb27SDimitry Andric INITIALIZE_PASS(X86ArgumentStackSlotPass, DEBUG_TYPE, "Argument Stack Rebase",
62*06c3fb27SDimitry Andric                 false, false)
63*06c3fb27SDimitry Andric 
createX86ArgumentStackSlotPass()64*06c3fb27SDimitry Andric FunctionPass *llvm::createX86ArgumentStackSlotPass() {
65*06c3fb27SDimitry Andric   return new X86ArgumentStackSlotPass();
66*06c3fb27SDimitry Andric }
67*06c3fb27SDimitry Andric 
getArgBaseReg(MachineFunction & MF)68*06c3fb27SDimitry Andric static Register getArgBaseReg(MachineFunction &MF) {
69*06c3fb27SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
70*06c3fb27SDimitry Andric   const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
71*06c3fb27SDimitry Andric   const Function &F = MF.getFunction();
72*06c3fb27SDimitry Andric   CallingConv::ID CC = F.getCallingConv();
73*06c3fb27SDimitry Andric   Register NoReg;
74*06c3fb27SDimitry Andric   const TargetRegisterClass *RC = nullptr;
75*06c3fb27SDimitry Andric   switch (CC) {
76*06c3fb27SDimitry Andric   // We need a virtual register in case there is inline assembly
77*06c3fb27SDimitry Andric   // clobber argument base register.
78*06c3fb27SDimitry Andric   case CallingConv::C:
79*06c3fb27SDimitry Andric     RC = STI.is64Bit() ? &X86::GR64_ArgRefRegClass : &X86::GR32_ArgRefRegClass;
80*06c3fb27SDimitry Andric     break;
81*06c3fb27SDimitry Andric   case CallingConv::X86_RegCall:
82*06c3fb27SDimitry Andric     // FIXME: For regcall there is no scratch register on 32-bit target.
83*06c3fb27SDimitry Andric     // We may use a callee saved register as argument base register and
84*06c3fb27SDimitry Andric     // save it before being changed as base pointer. We need DW_CFA to
85*06c3fb27SDimitry Andric     // indicate where the callee saved register is saved, so that it can
86*06c3fb27SDimitry Andric     // be correctly unwind.
87*06c3fb27SDimitry Andric     // push      ebx
88*06c3fb27SDimitry Andric     // mov       ebx, esp
89*06c3fb27SDimitry Andric     // and       esp, -128
90*06c3fb27SDimitry Andric     // ...
91*06c3fb27SDimitry Andric     // pop       ebx
92*06c3fb27SDimitry Andric     // ret
93*06c3fb27SDimitry Andric     RC = STI.is64Bit() ? &X86::GR64_ArgRefRegClass : nullptr;
94*06c3fb27SDimitry Andric     break;
95*06c3fb27SDimitry Andric   // TODO: Refine register class for each calling convention.
96*06c3fb27SDimitry Andric   default:
97*06c3fb27SDimitry Andric     break;
98*06c3fb27SDimitry Andric   }
99*06c3fb27SDimitry Andric   if (RC)
100*06c3fb27SDimitry Andric     return MRI.createVirtualRegister(RC);
101*06c3fb27SDimitry Andric   else
102*06c3fb27SDimitry Andric     return NoReg;
103*06c3fb27SDimitry Andric }
104*06c3fb27SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)105*06c3fb27SDimitry Andric bool X86ArgumentStackSlotPass::runOnMachineFunction(MachineFunction &MF) {
106*06c3fb27SDimitry Andric   const Function &F = MF.getFunction();
107*06c3fb27SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
108*06c3fb27SDimitry Andric   const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
109*06c3fb27SDimitry Andric   const X86RegisterInfo *TRI = STI.getRegisterInfo();
110*06c3fb27SDimitry Andric   const X86InstrInfo *TII = STI.getInstrInfo();
111*06c3fb27SDimitry Andric   X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
112*06c3fb27SDimitry Andric   bool Changed = false;
113*06c3fb27SDimitry Andric 
114*06c3fb27SDimitry Andric   if (F.hasFnAttribute(Attribute::Naked))
115*06c3fb27SDimitry Andric     return false;
116*06c3fb27SDimitry Andric   // Only support Linux and ELF.
117*06c3fb27SDimitry Andric   if (!STI.isTargetLinux() && !STI.isTargetELF())
118*06c3fb27SDimitry Andric     return false;
119*06c3fb27SDimitry Andric   if (!TRI->hasBasePointer(MF))
120*06c3fb27SDimitry Andric     return false;
121*06c3fb27SDimitry Andric   // Don't support X32
122*06c3fb27SDimitry Andric   if (STI.isTarget64BitILP32())
123*06c3fb27SDimitry Andric     return false;
124*06c3fb27SDimitry Andric 
125*06c3fb27SDimitry Andric   Register BasePtr = TRI->getBaseRegister();
126*06c3fb27SDimitry Andric   auto IsBaseRegisterClobbered = [&]() {
127*06c3fb27SDimitry Andric     for (MachineBasicBlock &MBB : MF) {
128*06c3fb27SDimitry Andric       for (MachineInstr &MI : MBB) {
129*06c3fb27SDimitry Andric         if (!MI.isInlineAsm())
130*06c3fb27SDimitry Andric           continue;
131*06c3fb27SDimitry Andric         for (MachineOperand &MO : MI.operands()) {
132*06c3fb27SDimitry Andric           if (!MO.isReg())
133*06c3fb27SDimitry Andric             continue;
134*06c3fb27SDimitry Andric           Register Reg = MO.getReg();
135*06c3fb27SDimitry Andric           if (!Register::isPhysicalRegister(Reg))
136*06c3fb27SDimitry Andric             continue;
137*06c3fb27SDimitry Andric           if (TRI->isSuperOrSubRegisterEq(BasePtr, Reg))
138*06c3fb27SDimitry Andric             return true;
139*06c3fb27SDimitry Andric         }
140*06c3fb27SDimitry Andric       }
141*06c3fb27SDimitry Andric     }
142*06c3fb27SDimitry Andric     return false;
143*06c3fb27SDimitry Andric   };
144*06c3fb27SDimitry Andric   if (!IsBaseRegisterClobbered())
145*06c3fb27SDimitry Andric     return false;
146*06c3fb27SDimitry Andric 
147*06c3fb27SDimitry Andric   Register ArgBaseReg = getArgBaseReg(MF);
148*06c3fb27SDimitry Andric   if (!ArgBaseReg.isValid())
149*06c3fb27SDimitry Andric     return false;
150*06c3fb27SDimitry Andric   // leal    4(%esp), %reg
151*06c3fb27SDimitry Andric   MachineBasicBlock &MBB = MF.front();
152*06c3fb27SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
153*06c3fb27SDimitry Andric   DebugLoc DL;
154*06c3fb27SDimitry Andric   // Emit instruction to copy get stack pointer to a virtual register
155*06c3fb27SDimitry Andric   // and save the instruction to x86 machine functon info. We can get
156*06c3fb27SDimitry Andric   // physical register of ArgBaseReg after register allocation. The
157*06c3fb27SDimitry Andric   // stack slot is used to save/restore argument base pointer. We can
158*06c3fb27SDimitry Andric   // get the index from the instruction.
159*06c3fb27SDimitry Andric   unsigned SlotSize = TRI->getSlotSize();
160*06c3fb27SDimitry Andric   int FI = MFI.CreateSpillStackObject(SlotSize, Align(SlotSize));
161*06c3fb27SDimitry Andric   // Use pseudo LEA to prevent the instruction from being eliminated.
162*06c3fb27SDimitry Andric   // TODO: if it is duplicated we can expand it to lea.
163*06c3fb27SDimitry Andric   MachineInstr *LEA =
164*06c3fb27SDimitry Andric       BuildMI(MBB, MBBI, DL,
165*06c3fb27SDimitry Andric               TII->get(STI.is64Bit() ? X86::PLEA64r : X86::PLEA32r), ArgBaseReg)
166*06c3fb27SDimitry Andric           .addFrameIndex(FI)
167*06c3fb27SDimitry Andric           .addImm(1)
168*06c3fb27SDimitry Andric           .addUse(X86::NoRegister)
169*06c3fb27SDimitry Andric           .addImm(SlotSize)
170*06c3fb27SDimitry Andric           .addUse(X86::NoRegister)
171*06c3fb27SDimitry Andric           .setMIFlag(MachineInstr::FrameSetup);
172*06c3fb27SDimitry Andric   X86FI->setStackPtrSaveMI(LEA);
173*06c3fb27SDimitry Andric 
174*06c3fb27SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
175*06c3fb27SDimitry Andric     for (MachineInstr &MI : MBB) {
176*06c3fb27SDimitry Andric       int I = 0;
177*06c3fb27SDimitry Andric       for (MachineOperand &MO : MI.operands()) {
178*06c3fb27SDimitry Andric         if (MO.isFI()) {
179*06c3fb27SDimitry Andric           int Idx = MO.getIndex();
180*06c3fb27SDimitry Andric           if (!MFI.isFixedObjectIndex(Idx))
181*06c3fb27SDimitry Andric             continue;
182*06c3fb27SDimitry Andric           int64_t Offset = MFI.getObjectOffset(Idx);
183*06c3fb27SDimitry Andric           if (Offset < 0)
184*06c3fb27SDimitry Andric             continue;
185*06c3fb27SDimitry Andric           // TODO replace register for debug instruction
186*06c3fb27SDimitry Andric           if (MI.isDebugInstr())
187*06c3fb27SDimitry Andric             continue;
188*06c3fb27SDimitry Andric           // Replace frame register with argument base pointer and its offset.
189*06c3fb27SDimitry Andric           TRI->eliminateFrameIndex(MI.getIterator(), I, ArgBaseReg, Offset);
190*06c3fb27SDimitry Andric           Changed = true;
191*06c3fb27SDimitry Andric         }
192*06c3fb27SDimitry Andric         ++I;
193*06c3fb27SDimitry Andric       }
194*06c3fb27SDimitry Andric     }
195*06c3fb27SDimitry Andric   }
196*06c3fb27SDimitry Andric 
197*06c3fb27SDimitry Andric   return Changed;
198*06c3fb27SDimitry Andric }
199