LLVM  6.0.0svn
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"
27 #include "WebAssemblyUtilities.h"
33 #include "llvm/Support/Debug.h"
34 using namespace llvm;
35 
36 #define DEBUG_TYPE "wasm-frame-info"
37 
38 // TODO: wasm64
39 // TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
40 
41 /// We need a base pointer in the case of having items on the stack that
42 /// require stricter alignment than the stack pointer itself. Because we need
43 /// to shift the stack pointer by some unknown amount to force the alignment,
44 /// we need to record the value of the stack pointer on entry to the function.
45 bool WebAssemblyFrameLowering::hasBP(
46  const MachineFunction &MF) const {
47  const auto *RegInfo =
48  MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
49  return RegInfo->needsStackRealignment(MF);
50 }
51 
52 /// Return true if the specified function should have a dedicated frame pointer
53 /// register.
55  const MachineFrameInfo &MFI = MF.getFrameInfo();
56 
57  // When we have var-sized objects, we move the stack pointer by an unknown
58  // amount, and need to emit a frame pointer to restore the stack to where we
59  // were on function entry.
60  // If we already need a base pointer, we use that to fix up the stack pointer.
61  // If there are no fixed-size objects, we would have no use of a frame
62  // pointer, and thus should not emit one.
63  bool HasFixedSizedObjects = MFI.getStackSize() > 0;
64  bool NeedsFixedReference = !hasBP(MF) || HasFixedSizedObjects;
65 
66  return MFI.isFrameAddressTaken() ||
67  (MFI.hasVarSizedObjects() && NeedsFixedReference) ||
68  MFI.hasStackMap() || MFI.hasPatchPoint();
69 }
70 
71 /// Under normal circumstances, when a frame pointer is not required, we reserve
72 /// argument space for call sites in the function immediately on entry to the
73 /// current function. This eliminates the need for add/sub sp brackets around
74 /// call sites. Returns true if the call frame is included as part of the stack
75 /// frame.
77  const MachineFunction &MF) const {
78  return !MF.getFrameInfo().hasVarSizedObjects();
79 }
80 
81 
82 /// Returns true if this function needs a local user-space stack pointer.
83 /// Unlike a machine stack pointer, the wasm user stack pointer is a global
84 /// variable, so it is loaded into a register in the prolog.
85 bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF,
86  const MachineFrameInfo &MFI) const {
87  return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF);
88 }
89 
90 /// Returns true if the local user-space stack pointer needs to be written back
91 /// to memory by this function (this is not meaningful if needsSP is false). If
92 /// false, the stack red zone can be used and only a local SP is needed.
93 bool WebAssemblyFrameLowering::needsSPWriteback(
94  const MachineFunction &MF, const MachineFrameInfo &MFI) const {
95  assert(needsSP(MF, MFI));
96  return MFI.getStackSize() > RedZoneSize || MFI.hasCalls() ||
97  MF.getFunction()->hasFnAttribute(Attribute::NoRedZone);
98 }
99 
100 static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF,
101  MachineBasicBlock &MBB,
102  MachineBasicBlock::iterator &InsertAddr,
103  MachineBasicBlock::iterator &InsertStore,
104  const DebugLoc &DL) {
105  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
106 
107  const char *ES = "__stack_pointer";
108  auto *SPSymbol = MF.createExternalSymbolName(ES);
112  const TargetRegisterClass *PtrRC =
114  unsigned Zero = MRI.createVirtualRegister(PtrRC);
115 
116  BuildMI(MBB, InsertAddr, DL, TII->get(WebAssembly::CONST_I32), Zero)
117  .addImm(0);
121  BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::STORE_I32))
122  .addImm(2) // p2align
123  .addExternalSymbol(SPSymbol)
124  .addReg(Zero)
125  .addReg(SrcReg)
126  .addMemOperand(MMO);
127  } else {
128  BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::SET_GLOBAL_I32))
129  .addExternalSymbol(SPSymbol)
130  .addReg(SrcReg);
131  }
132 }
133 
138  assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) &&
139  "Call frame pseudos should only be used for dynamic stack adjustment");
140  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
141  if (I->getOpcode() == TII->getCallFrameDestroyOpcode() &&
142  needsSPWriteback(MF, MF.getFrameInfo())) {
143  DebugLoc DL = I->getDebugLoc();
144  writeSPToMemory(WebAssembly::SP32, MF, MBB, I, I, DL);
145  }
146  return MBB.erase(I);
147 }
148 
150  MachineBasicBlock &MBB) const {
151  // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
152  auto &MFI = MF.getFrameInfo();
153  assert(MFI.getCalleeSavedInfo().empty() &&
154  "WebAssembly should not have callee-saved registers");
155 
156  if (!needsSP(MF, MFI)) return;
157  uint64_t StackSize = MFI.getStackSize();
158 
159  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
160  auto &MRI = MF.getRegInfo();
161 
162  auto InsertPt = MBB.begin();
163  while (InsertPt != MBB.end() && WebAssembly::isArgument(*InsertPt))
164  ++InsertPt;
165  DebugLoc DL;
166 
167  const TargetRegisterClass *PtrRC =
168  MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
169  unsigned SPReg = WebAssembly::SP32;
170  if (StackSize)
171  SPReg = MRI.createVirtualRegister(PtrRC);
172 
173  const char *ES = "__stack_pointer";
174  auto *SPSymbol = MF.createExternalSymbolName(ES);
177  unsigned Zero = MRI.createVirtualRegister(PtrRC);
178 
179  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero)
180  .addImm(0);
184  // Load the SP value.
185  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg)
186  .addImm(2) // p2align
187  .addExternalSymbol(SPSymbol)
188  .addReg(Zero) // addr
189  .addMemOperand(LoadMMO);
190  } else {
191  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::GET_GLOBAL_I32), SPReg)
192  .addExternalSymbol(SPSymbol);
193  }
194 
195  bool HasBP = hasBP(MF);
196  if (HasBP) {
197  auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
198  unsigned BasePtr = MRI.createVirtualRegister(PtrRC);
199  FI->setBasePointerVreg(BasePtr);
200  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr)
201  .addReg(SPReg);
202  }
203  if (StackSize) {
204  // Subtract the frame size
205  unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
206  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
207  .addImm(StackSize);
208  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32),
209  WebAssembly::SP32)
210  .addReg(SPReg)
211  .addReg(OffsetReg);
212  }
213  if (HasBP) {
214  unsigned BitmaskReg = MRI.createVirtualRegister(PtrRC);
215  unsigned Alignment = MFI.getMaxAlignment();
216  assert((1u << countTrailingZeros(Alignment)) == Alignment &&
217  "Alignment must be a power of 2");
218  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), BitmaskReg)
219  .addImm((int)~(Alignment - 1));
220  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::AND_I32),
221  WebAssembly::SP32)
222  .addReg(WebAssembly::SP32)
223  .addReg(BitmaskReg);
224  }
225  if (hasFP(MF)) {
226  // Unlike most conventional targets (where FP points to the saved FP),
227  // FP points to the bottom of the fixed-size locals, so we can use positive
228  // offsets in load/store instructions.
229  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY),
230  WebAssembly::FP32)
231  .addReg(WebAssembly::SP32);
232  }
233  if (StackSize && needsSPWriteback(MF, MFI)) {
234  writeSPToMemory(WebAssembly::SP32, MF, MBB, InsertPt, InsertPt, DL);
235  }
236 }
237 
239  MachineBasicBlock &MBB) const {
240  auto &MFI = MF.getFrameInfo();
241  uint64_t StackSize = MFI.getStackSize();
242  if (!needsSP(MF, MFI) || !needsSPWriteback(MF, MFI)) return;
243  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
244  auto &MRI = MF.getRegInfo();
245  auto InsertPt = MBB.getFirstTerminator();
246  DebugLoc DL;
247 
248  if (InsertPt != MBB.end())
249  DL = InsertPt->getDebugLoc();
250 
251  // Restore the stack pointer. If we had fixed-size locals, add the offset
252  // subtracted in the prolog.
253  unsigned SPReg = 0;
254  MachineBasicBlock::iterator InsertAddr = InsertPt;
255  if (hasBP(MF)) {
256  auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
257  SPReg = FI->getBasePointerVreg();
258  } else if (StackSize) {
259  const TargetRegisterClass *PtrRC =
260  MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
261  unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
262  InsertAddr =
263  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
264  .addImm(StackSize);
265  // In the epilog we don't need to write the result back to the SP32 physreg
266  // because it won't be used again. We can use a stackified register instead.
267  SPReg = MRI.createVirtualRegister(PtrRC);
268  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), SPReg)
269  .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32)
270  .addReg(OffsetReg);
271  } else {
272  SPReg = hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32;
273  }
274 
275  writeSPToMemory(SPReg, MF, MBB, InsertAddr, InsertPt, DL);
276 }
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override
These methods insert prolog and epilog code into the function.
bool hasStackMap() const
This method may be called any time after instruction selection is complete to determine if there is a...
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
bool isOSBinFormatELF() const
Tests whether the OS uses the ELF binary format.
Definition: Triple.h:588
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 hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition: Function.h:262
A debug info location.
Definition: DebugLoc.h:34
bool adjustsStack() const
Return true if this function adjusts the stack – e.g., when calling another function.
bool hasFP(const MachineFunction &MF) const override
Return true if the specified function should have a dedicated frame pointer register.
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...
bool isFrameAddressTaken() const
This method may be called any time after instruction selection is complete to determine if there is a...
A description of a memory reference used in the backend.
instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
const HexagonInstrInfo * TII
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted...
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, uint64_t s, unsigned base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
This file declares the WebAssembly-specific subclass of TargetMachine.
PseudoSourceValueManager & getPSVManager() const
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override
This file contains the declaration of the WebAssembly-specific utility functions. ...
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
const TargetRegisterInfo * getTargetRegisterInfo() const
unsigned const MachineRegisterInfo * MRI
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB=ZB_Width)
Count number of 0&#39;s from the least significant bit to the most stopping at the first 1...
Definition: MathExtras.h:112
const PseudoSourceValue * getExternalSymbolCallEntry(const char *ES)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const Triple & getTargetTriple() const
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)
unsigned getMaxAlignment() const
Return the alignment in bytes that this function must be aligned to, which is greater than the defaul...
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.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
bool isArgument(const MachineInstr &MI)
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
This file contains the WebAssembly implementation of the TargetInstrInfo class.
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 ...
This class implements WebAssembly-specific bits of TargetFrameLowering class.
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 std::vector< CalleeSavedInfo > & getCalleeSavedInfo() const
Returns a reference to call saved info vector for the current function.
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned char TargetFlags=0) const
#define I(x, y, z)
Definition: MD5.cpp:58
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.
const MachineInstrBuilder & addReg(unsigned RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const Function * getFunction() const
getFunction - Return the LLVM function that this machine code represents
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool hasPatchPoint() const
This method may be called any time after instruction selection is complete to determine if there is a...
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects...
virtual const TargetRegisterClass * getPointerRegClass(const MachineFunction &MF, unsigned Kind=0) const
Returns a TargetRegisterClass used for pointer values.
bool hasCalls() const
Return true if the current function has any function calls.