110e730a2SDan Gohman //===-- WebAssemblyFrameLowering.cpp - WebAssembly Frame Lowering ----------==//
210e730a2SDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610e730a2SDan Gohman //
710e730a2SDan Gohman //===----------------------------------------------------------------------===//
810e730a2SDan Gohman ///
910e730a2SDan Gohman /// \file
105f8f34e4SAdrian Prantl /// This file contains the WebAssembly implementation of
1110e730a2SDan Gohman /// TargetFrameLowering class.
1210e730a2SDan Gohman ///
1310e730a2SDan Gohman /// On WebAssembly, there aren't a lot of things to do here. There are no
1410e730a2SDan Gohman /// callee-saved registers to save, and no spill slots.
1510e730a2SDan Gohman ///
1610e730a2SDan Gohman /// The stack grows downward.
1710e730a2SDan Gohman ///
1810e730a2SDan Gohman //===----------------------------------------------------------------------===//
1910e730a2SDan Gohman 
2010e730a2SDan Gohman #include "WebAssemblyFrameLowering.h"
2110e730a2SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
22*864767abSPaulo Matos #include "Utils/WebAssemblyTypeUtilities.h"
23ff171acfSDerek Schuff #include "WebAssembly.h"
2410e730a2SDan Gohman #include "WebAssemblyInstrInfo.h"
2510e730a2SDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
2610e730a2SDan Gohman #include "WebAssemblySubtarget.h"
2710e730a2SDan Gohman #include "WebAssemblyTargetMachine.h"
2882f92e35SAndy Wingo #include "llvm/CodeGen/Analysis.h"
2910e730a2SDan Gohman #include "llvm/CodeGen/MachineFrameInfo.h"
3010e730a2SDan Gohman #include "llvm/CodeGen/MachineFunction.h"
3110e730a2SDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h"
3282607f56SDan Gohman #include "llvm/CodeGen/MachineModuleInfoImpls.h"
3310e730a2SDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
3482f92e35SAndy Wingo #include "llvm/IR/Instructions.h"
3578d19108SHeejin Ahn #include "llvm/MC/MCAsmInfo.h"
3610e730a2SDan Gohman #include "llvm/Support/Debug.h"
3710e730a2SDan Gohman using namespace llvm;
3810e730a2SDan Gohman 
3903855df1SJF Bastien #define DEBUG_TYPE "wasm-frame-info"
4010e730a2SDan Gohman 
419769debfSDerek Schuff // TODO: wasm64
429769debfSDerek Schuff // TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
4310e730a2SDan Gohman 
4482f92e35SAndy Wingo // In an ideal world, when objects are added to the MachineFrameInfo by
4582f92e35SAndy Wingo // FunctionLoweringInfo::set, we could somehow hook into target-specific code to
4682f92e35SAndy Wingo // ensure they are assigned the right stack ID.  However there isn't a hook that
4782f92e35SAndy Wingo // runs between then and DAG building time, though, so instead we hoist stack
4882f92e35SAndy Wingo // objects lazily when they are first used, and comprehensively after the DAG is
4982f92e35SAndy Wingo // built via the PreprocessISelDAG hook, called by the
5082f92e35SAndy Wingo // SelectionDAGISel::runOnMachineFunction.  We have to do it in two places
5182f92e35SAndy Wingo // because we want to do it while building the selection DAG for uses of alloca,
5282f92e35SAndy Wingo // but not all alloca instructions are used so we have to follow up afterwards.
5382f92e35SAndy Wingo Optional<unsigned>
getLocalForStackObject(MachineFunction & MF,int FrameIndex)5482f92e35SAndy Wingo WebAssemblyFrameLowering::getLocalForStackObject(MachineFunction &MF,
5582f92e35SAndy Wingo                                                  int FrameIndex) {
5682f92e35SAndy Wingo   MachineFrameInfo &MFI = MF.getFrameInfo();
5782f92e35SAndy Wingo 
5882f92e35SAndy Wingo   // If already hoisted to a local, done.
5982f92e35SAndy Wingo   if (MFI.getStackID(FrameIndex) == TargetStackID::WasmLocal)
6082f92e35SAndy Wingo     return static_cast<unsigned>(MFI.getObjectOffset(FrameIndex));
6182f92e35SAndy Wingo 
6282f92e35SAndy Wingo   // If not allocated in the object address space, this object will be in
6382f92e35SAndy Wingo   // linear memory.
6482f92e35SAndy Wingo   const AllocaInst *AI = MFI.getObjectAllocation(FrameIndex);
6582f92e35SAndy Wingo   if (!AI ||
6682f92e35SAndy Wingo       !WebAssembly::isWasmVarAddressSpace(AI->getType()->getAddressSpace()))
6782f92e35SAndy Wingo     return None;
6882f92e35SAndy Wingo 
6982f92e35SAndy Wingo   // Otherwise, allocate this object in the named value stack, outside of linear
7082f92e35SAndy Wingo   // memory.
7182f92e35SAndy Wingo   SmallVector<EVT, 4> ValueVTs;
7282f92e35SAndy Wingo   const WebAssemblyTargetLowering &TLI =
7382f92e35SAndy Wingo       *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
7482f92e35SAndy Wingo   WebAssemblyFunctionInfo *FuncInfo = MF.getInfo<WebAssemblyFunctionInfo>();
7582f92e35SAndy Wingo   ComputeValueVTs(TLI, MF.getDataLayout(), AI->getAllocatedType(), ValueVTs);
7682f92e35SAndy Wingo   MFI.setStackID(FrameIndex, TargetStackID::WasmLocal);
7782f92e35SAndy Wingo   // Abuse SP offset to record the index of the first local in the object.
7882f92e35SAndy Wingo   unsigned Local = FuncInfo->getParams().size() + FuncInfo->getLocals().size();
7982f92e35SAndy Wingo   MFI.setObjectOffset(FrameIndex, Local);
8082f92e35SAndy Wingo   // Allocate WebAssembly locals for each non-aggregate component of the
8182f92e35SAndy Wingo   // allocation.
8282f92e35SAndy Wingo   for (EVT ValueVT : ValueVTs)
8382f92e35SAndy Wingo     FuncInfo->addLocal(ValueVT.getSimpleVT());
8482f92e35SAndy Wingo   // Abuse object size to record number of WebAssembly locals allocated to
8582f92e35SAndy Wingo   // this object.
8682f92e35SAndy Wingo   MFI.setObjectSize(FrameIndex, ValueVTs.size());
8782f92e35SAndy Wingo   return static_cast<unsigned>(Local);
8882f92e35SAndy Wingo }
8982f92e35SAndy Wingo 
900d41b7b3SDerek Schuff /// We need a base pointer in the case of having items on the stack that
910d41b7b3SDerek Schuff /// require stricter alignment than the stack pointer itself.  Because we need
920d41b7b3SDerek Schuff /// to shift the stack pointer by some unknown amount to force the alignment,
930d41b7b3SDerek Schuff /// we need to record the value of the stack pointer on entry to the function.
hasBP(const MachineFunction & MF) const94f208f631SHeejin Ahn bool WebAssemblyFrameLowering::hasBP(const MachineFunction &MF) const {
950d41b7b3SDerek Schuff   const auto *RegInfo =
960d41b7b3SDerek Schuff       MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
97a9968c0aSTomas Matheson   return RegInfo->hasStackRealignment(MF);
980d41b7b3SDerek Schuff }
990d41b7b3SDerek Schuff 
10010e730a2SDan Gohman /// Return true if the specified function should have a dedicated frame pointer
10110e730a2SDan Gohman /// register.
hasFP(const MachineFunction & MF) const10210e730a2SDan Gohman bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
103941a705bSMatthias Braun   const MachineFrameInfo &MFI = MF.getFrameInfo();
1040d41b7b3SDerek Schuff 
1050d41b7b3SDerek Schuff   // When we have var-sized objects, we move the stack pointer by an unknown
1060d41b7b3SDerek Schuff   // amount, and need to emit a frame pointer to restore the stack to where we
1070d41b7b3SDerek Schuff   // were on function entry.
1080d41b7b3SDerek Schuff   // If we already need a base pointer, we use that to fix up the stack pointer.
1090d41b7b3SDerek Schuff   // If there are no fixed-size objects, we would have no use of a frame
1100d41b7b3SDerek Schuff   // pointer, and thus should not emit one.
1110d41b7b3SDerek Schuff   bool HasFixedSizedObjects = MFI.getStackSize() > 0;
1120d41b7b3SDerek Schuff   bool NeedsFixedReference = !hasBP(MF) || HasFixedSizedObjects;
1130d41b7b3SDerek Schuff 
1140d41b7b3SDerek Schuff   return MFI.isFrameAddressTaken() ||
1150d41b7b3SDerek Schuff          (MFI.hasVarSizedObjects() && NeedsFixedReference) ||
1160d41b7b3SDerek Schuff          MFI.hasStackMap() || MFI.hasPatchPoint();
11710e730a2SDan Gohman }
11810e730a2SDan Gohman 
11910e730a2SDan Gohman /// Under normal circumstances, when a frame pointer is not required, we reserve
12010e730a2SDan Gohman /// argument space for call sites in the function immediately on entry to the
12110e730a2SDan Gohman /// current function. This eliminates the need for add/sub sp brackets around
12210e730a2SDan Gohman /// call sites. Returns true if the call frame is included as part of the stack
12310e730a2SDan Gohman /// frame.
hasReservedCallFrame(const MachineFunction & MF) const12410e730a2SDan Gohman bool WebAssemblyFrameLowering::hasReservedCallFrame(
12510e730a2SDan Gohman     const MachineFunction &MF) const {
126941a705bSMatthias Braun   return !MF.getFrameInfo().hasVarSizedObjects();
12710e730a2SDan Gohman }
12810e730a2SDan Gohman 
129972fc358SHeejin Ahn // Returns true if this function needs a local user-space stack pointer for its
130972fc358SHeejin Ahn // local frame (not for exception handling).
needsSPForLocalFrame(const MachineFunction & MF) const131972fc358SHeejin Ahn bool WebAssemblyFrameLowering::needsSPForLocalFrame(
132972fc358SHeejin Ahn     const MachineFunction &MF) const {
133972fc358SHeejin Ahn   auto &MFI = MF.getFrameInfo();
134972fc358SHeejin Ahn   return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF);
135972fc358SHeejin Ahn }
136972fc358SHeejin Ahn 
13778d19108SHeejin Ahn // In function with EH pads, we need to make a copy of the value of
138b9a539c0SWouter van Oortmerssen // __stack_pointer global in SP32/64 register, in order to use it when
139b9a539c0SWouter van Oortmerssen // restoring __stack_pointer after an exception is caught.
needsPrologForEH(const MachineFunction & MF) const14078d19108SHeejin Ahn bool WebAssemblyFrameLowering::needsPrologForEH(
14178d19108SHeejin Ahn     const MachineFunction &MF) const {
14278d19108SHeejin Ahn   auto EHType = MF.getTarget().getMCAsmInfo()->getExceptionHandlingType();
14378d19108SHeejin Ahn   return EHType == ExceptionHandling::Wasm &&
14478d19108SHeejin Ahn          MF.getFunction().hasPersonalityFn() && MF.getFrameInfo().hasCalls();
14578d19108SHeejin Ahn }
1464b3bb213SDerek Schuff 
1474b3bb213SDerek Schuff /// Returns true if this function needs a local user-space stack pointer.
1484b3bb213SDerek Schuff /// Unlike a machine stack pointer, the wasm user stack pointer is a global
1494b3bb213SDerek Schuff /// variable, so it is loaded into a register in the prolog.
needsSP(const MachineFunction & MF) const150bc6d8970SHeejin Ahn bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF) const {
151972fc358SHeejin Ahn   return needsSPForLocalFrame(MF) || needsPrologForEH(MF);
1524b3bb213SDerek Schuff }
1534b3bb213SDerek Schuff 
1544b3bb213SDerek Schuff /// Returns true if the local user-space stack pointer needs to be written back
155c4df1d18SHeejin Ahn /// to __stack_pointer global by this function (this is not meaningful if
156c4df1d18SHeejin Ahn /// needsSP is false). If false, the stack red zone can be used and only a local
157c4df1d18SHeejin Ahn /// SP is needed.
needsSPWriteback(const MachineFunction & MF) const1584b3bb213SDerek Schuff bool WebAssemblyFrameLowering::needsSPWriteback(
159bc6d8970SHeejin Ahn     const MachineFunction &MF) const {
160bc6d8970SHeejin Ahn   auto &MFI = MF.getFrameInfo();
161bc6d8970SHeejin Ahn   assert(needsSP(MF));
162972fc358SHeejin Ahn   // When we don't need a local stack pointer for its local frame but only to
163972fc358SHeejin Ahn   // support EH, we don't need to write SP back in the epilog, because we don't
164972fc358SHeejin Ahn   // bump down the stack pointer in the prolog. We need to write SP back in the
165972fc358SHeejin Ahn   // epilog only if
166972fc358SHeejin Ahn   // 1. We need SP not only for EH support but also because we actually use
167972fc358SHeejin Ahn   // stack or we have a frame address taken.
168972fc358SHeejin Ahn   // 2. We cannot use the red zone.
169972fc358SHeejin Ahn   bool CanUseRedZone = MFI.getStackSize() <= RedZoneSize && !MFI.hasCalls() &&
170972fc358SHeejin Ahn                        !MF.getFunction().hasFnAttribute(Attribute::NoRedZone);
171972fc358SHeejin Ahn   return needsSPForLocalFrame(MF) && !CanUseRedZone;
1724b3bb213SDerek Schuff }
1734b3bb213SDerek Schuff 
getSPReg(const MachineFunction & MF)174b9a539c0SWouter van Oortmerssen unsigned WebAssemblyFrameLowering::getSPReg(const MachineFunction &MF) {
175b9a539c0SWouter van Oortmerssen   return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()
176b9a539c0SWouter van Oortmerssen              ? WebAssembly::SP64
177b9a539c0SWouter van Oortmerssen              : WebAssembly::SP32;
178b9a539c0SWouter van Oortmerssen }
179b9a539c0SWouter van Oortmerssen 
getFPReg(const MachineFunction & MF)180b9a539c0SWouter van Oortmerssen unsigned WebAssemblyFrameLowering::getFPReg(const MachineFunction &MF) {
181b9a539c0SWouter van Oortmerssen   return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()
182b9a539c0SWouter van Oortmerssen              ? WebAssembly::FP64
183b9a539c0SWouter van Oortmerssen              : WebAssembly::FP32;
184b9a539c0SWouter van Oortmerssen }
185b9a539c0SWouter van Oortmerssen 
186b9a539c0SWouter van Oortmerssen unsigned
getOpcConst(const MachineFunction & MF)187b9a539c0SWouter van Oortmerssen WebAssemblyFrameLowering::getOpcConst(const MachineFunction &MF) {
188b9a539c0SWouter van Oortmerssen   return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()
189b9a539c0SWouter van Oortmerssen              ? WebAssembly::CONST_I64
190b9a539c0SWouter van Oortmerssen              : WebAssembly::CONST_I32;
191b9a539c0SWouter van Oortmerssen }
192b9a539c0SWouter van Oortmerssen 
getOpcAdd(const MachineFunction & MF)193b9a539c0SWouter van Oortmerssen unsigned WebAssemblyFrameLowering::getOpcAdd(const MachineFunction &MF) {
194b9a539c0SWouter van Oortmerssen   return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()
195b9a539c0SWouter van Oortmerssen              ? WebAssembly::ADD_I64
196b9a539c0SWouter van Oortmerssen              : WebAssembly::ADD_I32;
197b9a539c0SWouter van Oortmerssen }
198b9a539c0SWouter van Oortmerssen 
getOpcSub(const MachineFunction & MF)199b9a539c0SWouter van Oortmerssen unsigned WebAssemblyFrameLowering::getOpcSub(const MachineFunction &MF) {
200b9a539c0SWouter van Oortmerssen   return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()
201b9a539c0SWouter van Oortmerssen              ? WebAssembly::SUB_I64
202b9a539c0SWouter van Oortmerssen              : WebAssembly::SUB_I32;
203b9a539c0SWouter van Oortmerssen }
204b9a539c0SWouter van Oortmerssen 
getOpcAnd(const MachineFunction & MF)205b9a539c0SWouter van Oortmerssen unsigned WebAssemblyFrameLowering::getOpcAnd(const MachineFunction &MF) {
206b9a539c0SWouter van Oortmerssen   return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()
207b9a539c0SWouter van Oortmerssen              ? WebAssembly::AND_I64
208b9a539c0SWouter van Oortmerssen              : WebAssembly::AND_I32;
209b9a539c0SWouter van Oortmerssen }
210b9a539c0SWouter van Oortmerssen 
211b9a539c0SWouter van Oortmerssen unsigned
getOpcGlobGet(const MachineFunction & MF)212b9a539c0SWouter van Oortmerssen WebAssemblyFrameLowering::getOpcGlobGet(const MachineFunction &MF) {
213b9a539c0SWouter van Oortmerssen   return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()
214b9a539c0SWouter van Oortmerssen              ? WebAssembly::GLOBAL_GET_I64
215b9a539c0SWouter van Oortmerssen              : WebAssembly::GLOBAL_GET_I32;
216b9a539c0SWouter van Oortmerssen }
217b9a539c0SWouter van Oortmerssen 
218b9a539c0SWouter van Oortmerssen unsigned
getOpcGlobSet(const MachineFunction & MF)219b9a539c0SWouter van Oortmerssen WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) {
220b9a539c0SWouter van Oortmerssen   return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()
221b9a539c0SWouter van Oortmerssen              ? WebAssembly::GLOBAL_SET_I64
222b9a539c0SWouter van Oortmerssen              : WebAssembly::GLOBAL_SET_I32;
223b9a539c0SWouter van Oortmerssen }
224b9a539c0SWouter van Oortmerssen 
writeSPToGlobal(unsigned SrcReg,MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator & InsertStore,const DebugLoc & DL) const22578d19108SHeejin Ahn void WebAssemblyFrameLowering::writeSPToGlobal(
22678d19108SHeejin Ahn     unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB,
22778d19108SHeejin Ahn     MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const {
22882607f56SDan Gohman   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
22982607f56SDan Gohman 
230d08cd15fSDan Gohman   const char *ES = "__stack_pointer";
231d08cd15fSDan Gohman   auto *SPSymbol = MF.createExternalSymbolName(ES);
232b9a539c0SWouter van Oortmerssen 
233b9a539c0SWouter van Oortmerssen   BuildMI(MBB, InsertStore, DL, TII->get(getOpcGlobSet(MF)))
234ef4c66c1SSam Clegg       .addExternalSymbol(SPSymbol)
23582607f56SDan Gohman       .addReg(SrcReg);
23682607f56SDan Gohman }
23727e3b8a6SDerek Schuff 
238e1a2e90fSHans Wennborg MachineBasicBlock::iterator
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const239e1a2e90fSHans Wennborg WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
2408bb5f292SDerek Schuff     MachineFunction &MF, MachineBasicBlock &MBB,
2418bb5f292SDerek Schuff     MachineBasicBlock::iterator I) const {
2420d41b7b3SDerek Schuff   assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) &&
24327e3b8a6SDerek Schuff          "Call frame pseudos should only be used for dynamic stack adjustment");
244b9a539c0SWouter van Oortmerssen   auto &ST = MF.getSubtarget<WebAssemblySubtarget>();
245b9a539c0SWouter van Oortmerssen   const auto *TII = ST.getInstrInfo();
2464b3bb213SDerek Schuff   if (I->getOpcode() == TII->getCallFrameDestroyOpcode() &&
247bc6d8970SHeejin Ahn       needsSPWriteback(MF)) {
24827e3b8a6SDerek Schuff     DebugLoc DL = I->getDebugLoc();
249b9a539c0SWouter van Oortmerssen     writeSPToGlobal(getSPReg(MF), MF, MBB, I, DL);
25027e3b8a6SDerek Schuff   }
251e1a2e90fSHans Wennborg   return MBB.erase(I);
2528bb5f292SDerek Schuff }
2538bb5f292SDerek Schuff 
emitPrologue(MachineFunction & MF,MachineBasicBlock & MBB) const2548bb5f292SDerek Schuff void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
2558bb5f292SDerek Schuff                                             MachineBasicBlock &MBB) const {
2568bb5f292SDerek Schuff   // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
257941a705bSMatthias Braun   auto &MFI = MF.getFrameInfo();
258941a705bSMatthias Braun   assert(MFI.getCalleeSavedInfo().empty() &&
2598bb5f292SDerek Schuff          "WebAssembly should not have callee-saved registers");
2606ea637afSDerek Schuff 
261f208f631SHeejin Ahn   if (!needsSP(MF))
262f208f631SHeejin Ahn     return;
263941a705bSMatthias Braun   uint64_t StackSize = MFI.getStackSize();
2648bb5f292SDerek Schuff 
265b9a539c0SWouter van Oortmerssen   auto &ST = MF.getSubtarget<WebAssemblySubtarget>();
266b9a539c0SWouter van Oortmerssen   const auto *TII = ST.getInstrInfo();
2676ea637afSDerek Schuff   auto &MRI = MF.getRegInfo();
2688bb5f292SDerek Schuff 
2698bb5f292SDerek Schuff   auto InsertPt = MBB.begin();
270d8ddf839SWouter van Oortmerssen   while (InsertPt != MBB.end() &&
271d8ddf839SWouter van Oortmerssen          WebAssembly::isArgument(InsertPt->getOpcode()))
272d934cb88SDan Gohman     ++InsertPt;
2738bb5f292SDerek Schuff   DebugLoc DL;
2748bb5f292SDerek Schuff 
2750cfb5f85SDan Gohman   const TargetRegisterClass *PtrRC =
2760cfb5f85SDan Gohman       MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
277b9a539c0SWouter van Oortmerssen   unsigned SPReg = getSPReg(MF);
2780d41b7b3SDerek Schuff   if (StackSize)
2790d41b7b3SDerek Schuff     SPReg = MRI.createVirtualRegister(PtrRC);
2809d24fb7fSSam Clegg 
281d08cd15fSDan Gohman   const char *ES = "__stack_pointer";
282d08cd15fSDan Gohman   auto *SPSymbol = MF.createExternalSymbolName(ES);
283b9a539c0SWouter van Oortmerssen   BuildMI(MBB, InsertPt, DL, TII->get(getOpcGlobGet(MF)), SPReg)
284ef4c66c1SSam Clegg       .addExternalSymbol(SPSymbol);
2856ea637afSDerek Schuff 
2860d41b7b3SDerek Schuff   bool HasBP = hasBP(MF);
2870d41b7b3SDerek Schuff   if (HasBP) {
2880d41b7b3SDerek Schuff     auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
28905c145d6SDaniel Sanders     Register BasePtr = MRI.createVirtualRegister(PtrRC);
2900d41b7b3SDerek Schuff     FI->setBasePointerVreg(BasePtr);
2910d41b7b3SDerek Schuff     BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr)
2920d41b7b3SDerek Schuff         .addReg(SPReg);
2930d41b7b3SDerek Schuff   }
2946ea637afSDerek Schuff   if (StackSize) {
2956ea637afSDerek Schuff     // Subtract the frame size
29605c145d6SDaniel Sanders     Register OffsetReg = MRI.createVirtualRegister(PtrRC);
297b9a539c0SWouter van Oortmerssen     BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), OffsetReg)
2986ea637afSDerek Schuff         .addImm(StackSize);
299b9a539c0SWouter van Oortmerssen     BuildMI(MBB, InsertPt, DL, TII->get(getOpcSub(MF)), getSPReg(MF))
3006ea637afSDerek Schuff         .addReg(SPReg)
3016ea637afSDerek Schuff         .addReg(OffsetReg);
3026ea637afSDerek Schuff   }
3030d41b7b3SDerek Schuff   if (HasBP) {
30405c145d6SDaniel Sanders     Register BitmaskReg = MRI.createVirtualRegister(PtrRC);
305d000655aSGuillaume Chatelet     Align Alignment = MFI.getMaxAlign();
306b9a539c0SWouter van Oortmerssen     BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), BitmaskReg)
307b9a539c0SWouter van Oortmerssen         .addImm((int64_t) ~(Alignment.value() - 1));
308b9a539c0SWouter van Oortmerssen     BuildMI(MBB, InsertPt, DL, TII->get(getOpcAnd(MF)), getSPReg(MF))
309b9a539c0SWouter van Oortmerssen         .addReg(getSPReg(MF))
3100d41b7b3SDerek Schuff         .addReg(BitmaskReg);
3110d41b7b3SDerek Schuff   }
3126ea637afSDerek Schuff   if (hasFP(MF)) {
3136ea637afSDerek Schuff     // Unlike most conventional targets (where FP points to the saved FP),
3146ea637afSDerek Schuff     // FP points to the bottom of the fixed-size locals, so we can use positive
3156ea637afSDerek Schuff     // offsets in load/store instructions.
316b9a539c0SWouter van Oortmerssen     BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), getFPReg(MF))
317b9a539c0SWouter van Oortmerssen         .addReg(getSPReg(MF));
3186ea637afSDerek Schuff   }
319bc6d8970SHeejin Ahn   if (StackSize && needsSPWriteback(MF)) {
320b9a539c0SWouter van Oortmerssen     writeSPToGlobal(getSPReg(MF), MF, MBB, InsertPt, DL);
3216ea637afSDerek Schuff   }
3228bb5f292SDerek Schuff }
3238bb5f292SDerek Schuff 
emitEpilogue(MachineFunction & MF,MachineBasicBlock & MBB) const3249769debfSDerek Schuff void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF,
3259769debfSDerek Schuff                                             MachineBasicBlock &MBB) const {
326bc6d8970SHeejin Ahn   uint64_t StackSize = MF.getFrameInfo().getStackSize();
327f208f631SHeejin Ahn   if (!needsSP(MF) || !needsSPWriteback(MF))
328f208f631SHeejin Ahn     return;
329b9a539c0SWouter van Oortmerssen   auto &ST = MF.getSubtarget<WebAssemblySubtarget>();
330b9a539c0SWouter van Oortmerssen   const auto *TII = ST.getInstrInfo();
3319769debfSDerek Schuff   auto &MRI = MF.getRegInfo();
3329769debfSDerek Schuff   auto InsertPt = MBB.getFirstTerminator();
3339769debfSDerek Schuff   DebugLoc DL;
3349769debfSDerek Schuff 
3350cfb5f85SDan Gohman   if (InsertPt != MBB.end())
3369769debfSDerek Schuff     DL = InsertPt->getDebugLoc();
337450a8075SDan Gohman 
3386ea637afSDerek Schuff   // Restore the stack pointer. If we had fixed-size locals, add the offset
3396ea637afSDerek Schuff   // subtracted in the prolog.
340d4207ba0SDerek Schuff   unsigned SPReg = 0;
341b9a539c0SWouter van Oortmerssen   unsigned SPFPReg = hasFP(MF) ? getFPReg(MF) : getSPReg(MF);
3420d41b7b3SDerek Schuff   if (hasBP(MF)) {
3430d41b7b3SDerek Schuff     auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
3440d41b7b3SDerek Schuff     SPReg = FI->getBasePointerVreg();
3450d41b7b3SDerek Schuff   } else if (StackSize) {
3460cfb5f85SDan Gohman     const TargetRegisterClass *PtrRC =
3470cfb5f85SDan Gohman         MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
34805c145d6SDaniel Sanders     Register OffsetReg = MRI.createVirtualRegister(PtrRC);
349b9a539c0SWouter van Oortmerssen     BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), OffsetReg)
3509769debfSDerek Schuff         .addImm(StackSize);
351b9a539c0SWouter van Oortmerssen     // In the epilog we don't need to write the result back to the SP32/64
352b9a539c0SWouter van Oortmerssen     // physreg because it won't be used again. We can use a stackified register
353b9a539c0SWouter van Oortmerssen     // instead.
3540cfb5f85SDan Gohman     SPReg = MRI.createVirtualRegister(PtrRC);
355b9a539c0SWouter van Oortmerssen     BuildMI(MBB, InsertPt, DL, TII->get(getOpcAdd(MF)), SPReg)
356b9a539c0SWouter van Oortmerssen         .addReg(SPFPReg)
3579769debfSDerek Schuff         .addReg(OffsetReg);
358d4207ba0SDerek Schuff   } else {
359b9a539c0SWouter van Oortmerssen     SPReg = SPFPReg;
3606ea637afSDerek Schuff   }
3616ea637afSDerek Schuff 
36220c9c443SHeejin Ahn   writeSPToGlobal(SPReg, MF, MBB, InsertPt, DL);
36310e730a2SDan Gohman }
364ff171acfSDerek Schuff 
isSupportedStackID(TargetStackID::Value ID) const36582f92e35SAndy Wingo bool WebAssemblyFrameLowering::isSupportedStackID(
36682f92e35SAndy Wingo     TargetStackID::Value ID) const {
36782f92e35SAndy Wingo   // Use the Object stack for WebAssembly locals which can only be accessed
36882f92e35SAndy Wingo   // by name, not via an address in linear memory.
36982f92e35SAndy Wingo   if (ID == TargetStackID::WasmLocal)
37082f92e35SAndy Wingo     return true;
37182f92e35SAndy Wingo 
37282f92e35SAndy Wingo   return TargetFrameLowering::isSupportedStackID(ID);
37382f92e35SAndy Wingo }
37482f92e35SAndy Wingo 
375ff171acfSDerek Schuff TargetFrameLowering::DwarfFrameBase
getDwarfFrameBase(const MachineFunction & MF) const376ff171acfSDerek Schuff WebAssemblyFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const {
377ff171acfSDerek Schuff   DwarfFrameBase Loc;
378ff171acfSDerek Schuff   Loc.Kind = DwarfFrameBase::WasmFrameBase;
379ff171acfSDerek Schuff   const WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
380d966bf83SDerek Schuff   if (needsSP(MF) && MFI.isFrameBaseVirtual()) {
381ff171acfSDerek Schuff     unsigned LocalNum = MFI.getFrameBaseLocal();
38248139ebcSWouter van Oortmerssen     Loc.Location.WasmLoc = {WebAssembly::TI_LOCAL, LocalNum};
383ff171acfSDerek Schuff   } else {
384ff171acfSDerek Schuff     // TODO: This should work on a breakpoint at a function with no frame,
385ff171acfSDerek Schuff     // but probably won't work for traversing up the stack.
38648139ebcSWouter van Oortmerssen     Loc.Location.WasmLoc = {WebAssembly::TI_GLOBAL_RELOC, 0};
387ff171acfSDerek Schuff   }
388ff171acfSDerek Schuff   return Loc;
389ff171acfSDerek Schuff }
390