LLVM  10.0.0svn
WebAssemblyFrameLowering.cpp
Go to the documentation of this file.
1 //===-- WebAssemblyFrameLowering.cpp - WebAssembly Frame Lowering ----------==//
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 /// \file
10 /// This file contains the WebAssembly implementation of
11 /// TargetFrameLowering class.
12 ///
13 /// On WebAssembly, there aren't a lot of things to do here. There are no
14 /// callee-saved registers to save, and no spill slots.
15 ///
16 /// The stack grows downward.
17 ///
18 //===----------------------------------------------------------------------===//
19 
22 #include "WebAssemblyInstrInfo.h"
24 #include "WebAssemblySubtarget.h"
26 #include "WebAssemblyUtilities.h"
32 #include "llvm/MC/MCAsmInfo.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(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 // Returns true if this function needs a local user-space stack pointer for its
81 // local frame (not for exception handling).
82 bool WebAssemblyFrameLowering::needsSPForLocalFrame(
83  const MachineFunction &MF) const {
84  auto &MFI = MF.getFrameInfo();
85  return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF);
86 }
87 
88 // In function with EH pads, we need to make a copy of the value of
89 // __stack_pointer global in SP32 register, in order to use it when restoring
90 // __stack_pointer after an exception is caught.
92  const MachineFunction &MF) const {
93  auto EHType = MF.getTarget().getMCAsmInfo()->getExceptionHandlingType();
94  return EHType == ExceptionHandling::Wasm &&
96 }
97 
98 /// Returns true if this function needs a local user-space stack pointer.
99 /// Unlike a machine stack pointer, the wasm user stack pointer is a global
100 /// variable, so it is loaded into a register in the prolog.
101 bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF) const {
102  return needsSPForLocalFrame(MF) || needsPrologForEH(MF);
103 }
104 
105 /// Returns true if the local user-space stack pointer needs to be written back
106 /// to __stack_pointer global by this function (this is not meaningful if
107 /// needsSP is false). If false, the stack red zone can be used and only a local
108 /// SP is needed.
109 bool WebAssemblyFrameLowering::needsSPWriteback(
110  const MachineFunction &MF) const {
111  auto &MFI = MF.getFrameInfo();
112  assert(needsSP(MF));
113  // When we don't need a local stack pointer for its local frame but only to
114  // support EH, we don't need to write SP back in the epilog, because we don't
115  // bump down the stack pointer in the prolog. We need to write SP back in the
116  // epilog only if
117  // 1. We need SP not only for EH support but also because we actually use
118  // stack or we have a frame address taken.
119  // 2. We cannot use the red zone.
120  bool CanUseRedZone = MFI.getStackSize() <= RedZoneSize && !MFI.hasCalls() &&
121  !MF.getFunction().hasFnAttribute(Attribute::NoRedZone);
122  return needsSPForLocalFrame(MF) && !CanUseRedZone;
123 }
124 
126  unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB,
127  MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const {
128  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
129 
130  const char *ES = "__stack_pointer";
131  auto *SPSymbol = MF.createExternalSymbolName(ES);
132  BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::GLOBAL_SET_I32))
133  .addExternalSymbol(SPSymbol)
134  .addReg(SrcReg);
135 }
136 
141  assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) &&
142  "Call frame pseudos should only be used for dynamic stack adjustment");
143  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
144  if (I->getOpcode() == TII->getCallFrameDestroyOpcode() &&
145  needsSPWriteback(MF)) {
146  DebugLoc DL = I->getDebugLoc();
147  writeSPToGlobal(WebAssembly::SP32, MF, MBB, I, DL);
148  }
149  return MBB.erase(I);
150 }
151 
153  MachineBasicBlock &MBB) const {
154  // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
155  auto &MFI = MF.getFrameInfo();
156  assert(MFI.getCalleeSavedInfo().empty() &&
157  "WebAssembly should not have callee-saved registers");
158 
159  if (!needsSP(MF))
160  return;
161  uint64_t StackSize = MFI.getStackSize();
162 
163  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
164  auto &MRI = MF.getRegInfo();
165 
166  auto InsertPt = MBB.begin();
167  while (InsertPt != MBB.end() &&
168  WebAssembly::isArgument(InsertPt->getOpcode()))
169  ++InsertPt;
170  DebugLoc DL;
171 
172  const TargetRegisterClass *PtrRC =
173  MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
174  unsigned SPReg = WebAssembly::SP32;
175  if (StackSize)
176  SPReg = MRI.createVirtualRegister(PtrRC);
177 
178  const char *ES = "__stack_pointer";
179  auto *SPSymbol = MF.createExternalSymbolName(ES);
180  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::GLOBAL_GET_I32), SPReg)
181  .addExternalSymbol(SPSymbol);
182 
183  bool HasBP = hasBP(MF);
184  if (HasBP) {
185  auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
186  Register BasePtr = MRI.createVirtualRegister(PtrRC);
187  FI->setBasePointerVreg(BasePtr);
188  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr)
189  .addReg(SPReg);
190  }
191  if (StackSize) {
192  // Subtract the frame size
193  Register OffsetReg = MRI.createVirtualRegister(PtrRC);
194  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
195  .addImm(StackSize);
196  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32),
197  WebAssembly::SP32)
198  .addReg(SPReg)
199  .addReg(OffsetReg);
200  }
201  if (HasBP) {
202  Register BitmaskReg = MRI.createVirtualRegister(PtrRC);
203  unsigned Alignment = MFI.getMaxAlignment();
204  assert((1u << countTrailingZeros(Alignment)) == Alignment &&
205  "Alignment must be a power of 2");
206  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), BitmaskReg)
207  .addImm((int)~(Alignment - 1));
208  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::AND_I32),
209  WebAssembly::SP32)
210  .addReg(WebAssembly::SP32)
211  .addReg(BitmaskReg);
212  }
213  if (hasFP(MF)) {
214  // Unlike most conventional targets (where FP points to the saved FP),
215  // FP points to the bottom of the fixed-size locals, so we can use positive
216  // offsets in load/store instructions.
217  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), WebAssembly::FP32)
218  .addReg(WebAssembly::SP32);
219  }
220  if (StackSize && needsSPWriteback(MF)) {
221  writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPt, DL);
222  }
223 }
224 
226  MachineBasicBlock &MBB) const {
227  uint64_t StackSize = MF.getFrameInfo().getStackSize();
228  if (!needsSP(MF) || !needsSPWriteback(MF))
229  return;
230  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
231  auto &MRI = MF.getRegInfo();
232  auto InsertPt = MBB.getFirstTerminator();
233  DebugLoc DL;
234 
235  if (InsertPt != MBB.end())
236  DL = InsertPt->getDebugLoc();
237 
238  // Restore the stack pointer. If we had fixed-size locals, add the offset
239  // subtracted in the prolog.
240  unsigned SPReg = 0;
241  if (hasBP(MF)) {
242  auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
243  SPReg = FI->getBasePointerVreg();
244  } else if (StackSize) {
245  const TargetRegisterClass *PtrRC =
246  MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
247  Register OffsetReg = MRI.createVirtualRegister(PtrRC);
248  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
249  .addImm(StackSize);
250  // In the epilog we don't need to write the result back to the SP32 physreg
251  // because it won't be used again. We can use a stackified register instead.
252  SPReg = MRI.createVirtualRegister(PtrRC);
253  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), SPReg)
254  .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32)
255  .addReg(OffsetReg);
256  } else {
257  SPReg = hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32;
258  }
259 
260  writeSPToGlobal(SPReg, MF, MBB, InsertPt, DL);
261 }
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...
bool isArgument(unsigned Opc)
This class represents lattice values for constants.
Definition: AllocatorList.h:23
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:323
A debug info location.
Definition: DebugLoc.h:33
bool hasFP(const MachineFunction &MF) const override
Return true if the specified function should have a dedicated frame pointer register.
unsigned 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:119
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...
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 ...
bool needsPrologForEH(const MachineFunction &MF) const
This file declares the WebAssembly-specific subclass of TargetMachine.
bool hasPersonalityFn() const
Check whether this function has a personality function.
Definition: Function.h:732
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override
WebAssembly Exception Handling.
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.
unsigned const MachineRegisterInfo * MRI
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
This file provides WebAssembly-specific target descriptions.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
void writeSPToGlobal(unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const
Write SP back to __stack_pointer global.
const char * createExternalSymbolName(StringRef Name)
Allocate a string and populate it with the given external symbol name.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the WebAssembly implementation of the TargetInstrInfo class.
const Function & getFunction() const
Return the LLVM function that this machine code represents.
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.
#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 LLVMTargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ExceptionHandling getExceptionHandlingType() const
Definition: MCAsmInfo.h:584
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...
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
bool hasCalls() const
Return true if the current function has any function calls.