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