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