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" 220b2bc69bSHeejin Ahn #include "Utils/WebAssemblyUtilities.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" 28*82f92e35SAndy 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" 34*82f92e35SAndy 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 44*82f92e35SAndy Wingo // In an ideal world, when objects are added to the MachineFrameInfo by 45*82f92e35SAndy Wingo // FunctionLoweringInfo::set, we could somehow hook into target-specific code to 46*82f92e35SAndy Wingo // ensure they are assigned the right stack ID. However there isn't a hook that 47*82f92e35SAndy Wingo // runs between then and DAG building time, though, so instead we hoist stack 48*82f92e35SAndy Wingo // objects lazily when they are first used, and comprehensively after the DAG is 49*82f92e35SAndy Wingo // built via the PreprocessISelDAG hook, called by the 50*82f92e35SAndy Wingo // SelectionDAGISel::runOnMachineFunction. We have to do it in two places 51*82f92e35SAndy Wingo // because we want to do it while building the selection DAG for uses of alloca, 52*82f92e35SAndy Wingo // but not all alloca instructions are used so we have to follow up afterwards. 53*82f92e35SAndy Wingo Optional<unsigned> 54*82f92e35SAndy Wingo WebAssemblyFrameLowering::getLocalForStackObject(MachineFunction &MF, 55*82f92e35SAndy Wingo int FrameIndex) { 56*82f92e35SAndy Wingo MachineFrameInfo &MFI = MF.getFrameInfo(); 57*82f92e35SAndy Wingo 58*82f92e35SAndy Wingo // If already hoisted to a local, done. 59*82f92e35SAndy Wingo if (MFI.getStackID(FrameIndex) == TargetStackID::WasmLocal) 60*82f92e35SAndy Wingo return static_cast<unsigned>(MFI.getObjectOffset(FrameIndex)); 61*82f92e35SAndy Wingo 62*82f92e35SAndy Wingo // If not allocated in the object address space, this object will be in 63*82f92e35SAndy Wingo // linear memory. 64*82f92e35SAndy Wingo const AllocaInst *AI = MFI.getObjectAllocation(FrameIndex); 65*82f92e35SAndy Wingo if (!AI || 66*82f92e35SAndy Wingo !WebAssembly::isWasmVarAddressSpace(AI->getType()->getAddressSpace())) 67*82f92e35SAndy Wingo return None; 68*82f92e35SAndy Wingo 69*82f92e35SAndy Wingo // Otherwise, allocate this object in the named value stack, outside of linear 70*82f92e35SAndy Wingo // memory. 71*82f92e35SAndy Wingo SmallVector<EVT, 4> ValueVTs; 72*82f92e35SAndy Wingo const WebAssemblyTargetLowering &TLI = 73*82f92e35SAndy Wingo *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 74*82f92e35SAndy Wingo WebAssemblyFunctionInfo *FuncInfo = MF.getInfo<WebAssemblyFunctionInfo>(); 75*82f92e35SAndy Wingo ComputeValueVTs(TLI, MF.getDataLayout(), AI->getAllocatedType(), ValueVTs); 76*82f92e35SAndy Wingo MFI.setStackID(FrameIndex, TargetStackID::WasmLocal); 77*82f92e35SAndy Wingo // Abuse SP offset to record the index of the first local in the object. 78*82f92e35SAndy Wingo unsigned Local = FuncInfo->getParams().size() + FuncInfo->getLocals().size(); 79*82f92e35SAndy Wingo MFI.setObjectOffset(FrameIndex, Local); 80*82f92e35SAndy Wingo // Allocate WebAssembly locals for each non-aggregate component of the 81*82f92e35SAndy Wingo // allocation. 82*82f92e35SAndy Wingo for (EVT ValueVT : ValueVTs) 83*82f92e35SAndy Wingo FuncInfo->addLocal(ValueVT.getSimpleVT()); 84*82f92e35SAndy Wingo // Abuse object size to record number of WebAssembly locals allocated to 85*82f92e35SAndy Wingo // this object. 86*82f92e35SAndy Wingo MFI.setObjectSize(FrameIndex, ValueVTs.size()); 87*82f92e35SAndy Wingo return static_cast<unsigned>(Local); 88*82f92e35SAndy Wingo } 89*82f92e35SAndy 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. 94f208f631SHeejin 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. 10210e730a2SDan 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. 12410e730a2SDan 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). 131972fc358SHeejin 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. 14078d19108SHeejin 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. 150bc6d8970SHeejin 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. 1584b3bb213SDerek 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 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 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 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 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 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 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 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 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 22578d19108SHeejin 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 239e1a2e90fSHans 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 2548bb5f292SDerek 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 3249769debfSDerek 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 365*82f92e35SAndy Wingo bool WebAssemblyFrameLowering::isSupportedStackID( 366*82f92e35SAndy Wingo TargetStackID::Value ID) const { 367*82f92e35SAndy Wingo // Use the Object stack for WebAssembly locals which can only be accessed 368*82f92e35SAndy Wingo // by name, not via an address in linear memory. 369*82f92e35SAndy Wingo if (ID == TargetStackID::WasmLocal) 370*82f92e35SAndy Wingo return true; 371*82f92e35SAndy Wingo 372*82f92e35SAndy Wingo return TargetFrameLowering::isSupportedStackID(ID); 373*82f92e35SAndy Wingo } 374*82f92e35SAndy Wingo 375ff171acfSDerek Schuff TargetFrameLowering::DwarfFrameBase 376ff171acfSDerek 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