LLVM  4.0.0
WebAssemblyFrameLowering.cpp
Go to the documentation of this file.
1 //===-- WebAssemblyFrameLowering.cpp - WebAssembly Frame Lowering ----------==//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file contains the WebAssembly implementation of
12 /// TargetFrameLowering class.
13 ///
14 /// On WebAssembly, there aren't a lot of things to do here. There are no
15 /// callee-saved registers to save, and no spill slots.
16 ///
17 /// The stack grows downward.
18 ///
19 //===----------------------------------------------------------------------===//
20 
23 #include "WebAssemblyInstrInfo.h"
25 #include "WebAssemblySubtarget.h"
32 #include "llvm/Support/Debug.h"
33 using namespace llvm;
34 
35 #define DEBUG_TYPE "wasm-frame-info"
36 
37 // TODO: wasm64
38 // TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
39 
40 /// We need a base pointer in the case of having items on the stack that
41 /// require stricter alignment than the stack pointer itself. Because we need
42 /// to shift the stack pointer by some unknown amount to force the alignment,
43 /// we need to record the value of the stack pointer on entry to the function.
44 bool WebAssemblyFrameLowering::hasBP(
45  const MachineFunction &MF) const {
46  const auto *RegInfo =
47  MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
48  return RegInfo->needsStackRealignment(MF);
49 }
50 
51 /// Return true if the specified function should have a dedicated frame pointer
52 /// register.
54  const MachineFrameInfo &MFI = MF.getFrameInfo();
55 
56  // When we have var-sized objects, we move the stack pointer by an unknown
57  // amount, and need to emit a frame pointer to restore the stack to where we
58  // were on function entry.
59  // If we already need a base pointer, we use that to fix up the stack pointer.
60  // If there are no fixed-size objects, we would have no use of a frame
61  // pointer, and thus should not emit one.
62  bool HasFixedSizedObjects = MFI.getStackSize() > 0;
63  bool NeedsFixedReference = !hasBP(MF) || HasFixedSizedObjects;
64 
65  return MFI.isFrameAddressTaken() ||
66  (MFI.hasVarSizedObjects() && NeedsFixedReference) ||
67  MFI.hasStackMap() || MFI.hasPatchPoint();
68 }
69 
70 /// Under normal circumstances, when a frame pointer is not required, we reserve
71 /// argument space for call sites in the function immediately on entry to the
72 /// current function. This eliminates the need for add/sub sp brackets around
73 /// call sites. Returns true if the call frame is included as part of the stack
74 /// frame.
76  const MachineFunction &MF) const {
77  return !MF.getFrameInfo().hasVarSizedObjects();
78 }
79 
80 
81 /// Returns true if this function needs a local user-space stack pointer.
82 /// Unlike a machine stack pointer, the wasm user stack pointer is a global
83 /// variable, so it is loaded into a register in the prolog.
84 bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF,
85  const MachineFrameInfo &MFI) const {
86  return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF);
87 }
88 
89 /// Returns true if the local user-space stack pointer needs to be written back
90 /// to memory by this function (this is not meaningful if needsSP is false). If
91 /// false, the stack red zone can be used and only a local SP is needed.
92 bool WebAssemblyFrameLowering::needsSPWriteback(
93  const MachineFunction &MF, const MachineFrameInfo &MFI) const {
94  assert(needsSP(MF, MFI));
95  return MFI.getStackSize() > RedZoneSize || MFI.hasCalls() ||
96  MF.getFunction()->hasFnAttribute(Attribute::NoRedZone);
97 }
98 
99 static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF,
101  MachineBasicBlock::iterator &InsertAddr,
102  MachineBasicBlock::iterator &InsertStore,
103  const DebugLoc &DL) {
104  const char *ES = "__stack_pointer";
105  auto *SPSymbol = MF.createExternalSymbolName(ES);
107  const TargetRegisterClass *PtrRC =
109  unsigned Zero = MRI.createVirtualRegister(PtrRC);
110  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
111 
112  BuildMI(MBB, InsertAddr, DL, TII->get(WebAssembly::CONST_I32), Zero)
113  .addImm(0);
117  BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::STORE_I32))
118  .addImm(2) // p2align
119  .addExternalSymbol(SPSymbol)
120  .addReg(Zero)
121  .addReg(SrcReg)
122  .addMemOperand(MMO);
123 }
124 
129  assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) &&
130  "Call frame pseudos should only be used for dynamic stack adjustment");
131  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
132  if (I->getOpcode() == TII->getCallFrameDestroyOpcode() &&
133  needsSPWriteback(MF, MF.getFrameInfo())) {
134  DebugLoc DL = I->getDebugLoc();
135  writeSPToMemory(WebAssembly::SP32, MF, MBB, I, I, DL);
136  }
137  return MBB.erase(I);
138 }
139 
141  MachineBasicBlock &MBB) const {
142  // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
143  auto &MFI = MF.getFrameInfo();
144  assert(MFI.getCalleeSavedInfo().empty() &&
145  "WebAssembly should not have callee-saved registers");
146 
147  if (!needsSP(MF, MFI)) return;
148  uint64_t StackSize = MFI.getStackSize();
149 
150  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
151  auto &MRI = MF.getRegInfo();
152 
153  auto InsertPt = MBB.begin();
154  DebugLoc DL;
155 
156  const TargetRegisterClass *PtrRC =
157  MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
158  unsigned Zero = MRI.createVirtualRegister(PtrRC);
159  unsigned SPReg = WebAssembly::SP32;
160  if (StackSize)
161  SPReg = MRI.createVirtualRegister(PtrRC);
162  const char *ES = "__stack_pointer";
163  auto *SPSymbol = MF.createExternalSymbolName(ES);
164  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero)
165  .addImm(0);
169  // Load the SP value.
170  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg)
171  .addImm(2) // p2align
172  .addExternalSymbol(SPSymbol)
173  .addReg(Zero) // addr
174  .addMemOperand(LoadMMO);
175 
176  bool HasBP = hasBP(MF);
177  if (HasBP) {
178  auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
179  unsigned BasePtr = MRI.createVirtualRegister(PtrRC);
180  FI->setBasePointerVreg(BasePtr);
181  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr)
182  .addReg(SPReg);
183  }
184  if (StackSize) {
185  // Subtract the frame size
186  unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
187  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
188  .addImm(StackSize);
189  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32),
190  WebAssembly::SP32)
191  .addReg(SPReg)
192  .addReg(OffsetReg);
193  }
194  if (HasBP) {
195  unsigned BitmaskReg = MRI.createVirtualRegister(PtrRC);
196  unsigned Alignment = MFI.getMaxAlignment();
197  assert((1u << countTrailingZeros(Alignment)) == Alignment &&
198  "Alignment must be a power of 2");
199  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), BitmaskReg)
200  .addImm((int)~(Alignment - 1));
201  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::AND_I32),
202  WebAssembly::SP32)
203  .addReg(WebAssembly::SP32)
204  .addReg(BitmaskReg);
205  }
206  if (hasFP(MF)) {
207  // Unlike most conventional targets (where FP points to the saved FP),
208  // FP points to the bottom of the fixed-size locals, so we can use positive
209  // offsets in load/store instructions.
210  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY),
211  WebAssembly::FP32)
212  .addReg(WebAssembly::SP32);
213  }
214  if (StackSize && needsSPWriteback(MF, MFI)) {
215  writeSPToMemory(WebAssembly::SP32, MF, MBB, InsertPt, InsertPt, DL);
216  }
217 }
218 
220  MachineBasicBlock &MBB) const {
221  auto &MFI = MF.getFrameInfo();
222  uint64_t StackSize = MFI.getStackSize();
223  if (!needsSP(MF, MFI) || !needsSPWriteback(MF, MFI)) return;
224  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
225  auto &MRI = MF.getRegInfo();
226  auto InsertPt = MBB.getFirstTerminator();
227  DebugLoc DL;
228 
229  if (InsertPt != MBB.end())
230  DL = InsertPt->getDebugLoc();
231 
232  // Restore the stack pointer. If we had fixed-size locals, add the offset
233  // subtracted in the prolog.
234  unsigned SPReg = 0;
235  MachineBasicBlock::iterator InsertAddr = InsertPt;
236  if (hasBP(MF)) {
237  auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
238  SPReg = FI->getBasePointerVreg();
239  } else if (StackSize) {
240  const TargetRegisterClass *PtrRC =
241  MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
242  unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
243  InsertAddr =
244  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
245  .addImm(StackSize);
246  // In the epilog we don't need to write the result back to the SP32 physreg
247  // because it won't be used again. We can use a stackified register instead.
248  SPReg = MRI.createVirtualRegister(PtrRC);
249  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), SPReg)
250  .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32)
251  .addReg(OffsetReg);
252  } else {
253  SPReg = hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32;
254  }
255 
256  writeSPToMemory(SPReg, MF, MBB, InsertAddr, InsertPt, DL);
257 }
instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override
These methods insert prolog and epilog code into the function.
unsigned createVirtualRegister(const TargetRegisterClass *RegClass)
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
bool adjustsStack() const
Return true if this function adjusts the stack – e.g., when calling another function.
A debug info location.
Definition: DebugLoc.h:34
const Function * getFunction() const
getFunction - Return the LLVM function that this machine code represents
bool hasFP(const MachineFunction &MF) const override
Return true if the specified function should have a dedicated frame pointer register.
unsigned getMaxAlignment() const
Return the alignment in bytes that this function must be aligned to, which is greater than the defaul...
const std::vector< CalleeSavedInfo > & getCalleeSavedInfo() const
Returns a reference to call saved info vector for the current function.
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects...
MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override
This method is called during prolog/epilog code insertion to eliminate call frame setup and destroy p...
A description of a memory reference used in the backend.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const HexagonInstrInfo * TII
const TargetRegisterInfo * getTargetRegisterInfo() const
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted...
bool isFrameAddressTaken() const
This method may be called any time after instruction selection is complete to determine if there is a...
This file declares the WebAssembly-specific subclass of TargetMachine.
MachineBasicBlock * MBB
PseudoSourceValueManager & getPSVManager() const
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool hasStackMap() const
This method may be called any time after instruction selection is complete to determine if there is a...
unsigned const MachineRegisterInfo * MRI
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB=ZB_Width)
Count number of 0's from the least significant bit to the most stopping at the first 1...
Definition: MathExtras.h:111
const PseudoSourceValue * getExternalSymbolCallEntry(const char *ES)
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
This file provides WebAssembly-specific target descriptions.
static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator &InsertAddr, MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL)
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
This class contains a discriminated union of information about pointers in memory operands...
const char * createExternalSymbolName(StringRef Name)
Allocate a string and populate it with the given external symbol name.
The memory access writes data.
bool hasCalls() const
Return true if the current function has any function calls.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the WebAssembly implementation of the TargetInstrInfo class.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, uint64_t s, unsigned base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SynchronizationScope SynchScope=CrossThread, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
The memory access reads data.
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
bool hasPatchPoint() const
This method may be called any time after instruction selection is complete to determine if there is a...
This class implements WebAssembly-specific bits of TargetFrameLowering class.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition: Function.h:226
static const size_t RedZoneSize
Size of the red zone for the user stack (leaf functions can use this much space below the stack point...
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
#define I(x, y, z)
Definition: MD5.cpp:54
bool hasReservedCallFrame(const MachineFunction &MF) const override
Under normal circumstances, when a frame pointer is not required, we reserve argument space for call ...
This file declares WebAssembly-specific per-machine-function information.
static volatile int Zero
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const MachineInstrBuilder & addReg(unsigned RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
virtual const TargetRegisterClass * getPointerRegClass(const MachineFunction &MF, unsigned Kind=0) const
Returns a TargetRegisterClass used for pointer values.