Skip to content

Commit e4ceb5a

Browse files
committed
[X86] Create extra prolog/epilog for stack realignment
Fix some bugs and reland e4c1dfe and 614c63b. 1. Run argument stack rebase pass before the reserved physical register is finalized. 2. Add LEA pseudo instruction to prevent the instruction being eliminated. 3. Don't support X32.
1 parent f225272 commit e4ceb5a

16 files changed

+507
-57
lines changed

llvm/lib/Target/X86/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ endif()
2626
add_public_tablegen_target(X86CommonTableGen)
2727

2828
set(sources
29+
X86ArgumentStackSlotRebase.cpp
2930
X86AsmPrinter.cpp
3031
X86AvoidTrailingCall.cpp
3132
X86CallFrameOptimization.cpp

llvm/lib/Target/X86/X86.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,13 @@ FunctionPass *createX86LoadValueInjectionLoadHardeningPass();
166166
FunctionPass *createX86LoadValueInjectionRetHardeningPass();
167167
FunctionPass *createX86SpeculativeLoadHardeningPass();
168168
FunctionPass *createX86SpeculativeExecutionSideEffectSuppression();
169+
FunctionPass *createX86ArgumentStackSlotPass();
169170

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

0 commit comments

Comments
 (0)