10b57cec5SDimitry Andric //===-- WebAssemblyFrameLowering.cpp - WebAssembly Frame Lowering ----------==// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file contains the WebAssembly implementation of 110b57cec5SDimitry Andric /// TargetFrameLowering class. 120b57cec5SDimitry Andric /// 130b57cec5SDimitry Andric /// On WebAssembly, there aren't a lot of things to do here. There are no 140b57cec5SDimitry Andric /// callee-saved registers to save, and no spill slots. 150b57cec5SDimitry Andric /// 160b57cec5SDimitry Andric /// The stack grows downward. 170b57cec5SDimitry Andric /// 180b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #include "WebAssemblyFrameLowering.h" 210b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 221fd87a68SDimitry Andric #include "Utils/WebAssemblyTypeUtilities.h" 235ffd83dbSDimitry Andric #include "WebAssembly.h" 240b57cec5SDimitry Andric #include "WebAssemblyInstrInfo.h" 250b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 260b57cec5SDimitry Andric #include "WebAssemblySubtarget.h" 270b57cec5SDimitry Andric #include "WebAssemblyTargetMachine.h" 28fe6060f1SDimitry Andric #include "llvm/CodeGen/Analysis.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h" 330b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 34fe6060f1SDimitry Andric #include "llvm/IR/Instructions.h" 350b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 360b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 370b57cec5SDimitry Andric using namespace llvm; 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-frame-info" 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric // TODO: wasm64 420b57cec5SDimitry Andric // TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions 430b57cec5SDimitry Andric 44fe6060f1SDimitry Andric // In an ideal world, when objects are added to the MachineFrameInfo by 45fe6060f1SDimitry Andric // FunctionLoweringInfo::set, we could somehow hook into target-specific code to 46fe6060f1SDimitry Andric // ensure they are assigned the right stack ID. However there isn't a hook that 47fe6060f1SDimitry Andric // runs between then and DAG building time, though, so instead we hoist stack 48fe6060f1SDimitry Andric // objects lazily when they are first used, and comprehensively after the DAG is 49fe6060f1SDimitry Andric // built via the PreprocessISelDAG hook, called by the 50fe6060f1SDimitry Andric // SelectionDAGISel::runOnMachineFunction. We have to do it in two places 51fe6060f1SDimitry Andric // because we want to do it while building the selection DAG for uses of alloca, 52fe6060f1SDimitry Andric // but not all alloca instructions are used so we have to follow up afterwards. 53bdd1243dSDimitry Andric std::optional<unsigned> 54fe6060f1SDimitry Andric WebAssemblyFrameLowering::getLocalForStackObject(MachineFunction &MF, 55fe6060f1SDimitry Andric int FrameIndex) { 56fe6060f1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 57fe6060f1SDimitry Andric 58fe6060f1SDimitry Andric // If already hoisted to a local, done. 59fe6060f1SDimitry Andric if (MFI.getStackID(FrameIndex) == TargetStackID::WasmLocal) 60fe6060f1SDimitry Andric return static_cast<unsigned>(MFI.getObjectOffset(FrameIndex)); 61fe6060f1SDimitry Andric 62fe6060f1SDimitry Andric // If not allocated in the object address space, this object will be in 63fe6060f1SDimitry Andric // linear memory. 64fe6060f1SDimitry Andric const AllocaInst *AI = MFI.getObjectAllocation(FrameIndex); 65bdd1243dSDimitry Andric if (!AI || !WebAssembly::isWasmVarAddressSpace(AI->getAddressSpace())) 66bdd1243dSDimitry Andric return std::nullopt; 67fe6060f1SDimitry Andric 68fe6060f1SDimitry Andric // Otherwise, allocate this object in the named value stack, outside of linear 69fe6060f1SDimitry Andric // memory. 70fe6060f1SDimitry Andric SmallVector<EVT, 4> ValueVTs; 71fe6060f1SDimitry Andric const WebAssemblyTargetLowering &TLI = 72fe6060f1SDimitry Andric *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 73fe6060f1SDimitry Andric WebAssemblyFunctionInfo *FuncInfo = MF.getInfo<WebAssemblyFunctionInfo>(); 74fe6060f1SDimitry Andric ComputeValueVTs(TLI, MF.getDataLayout(), AI->getAllocatedType(), ValueVTs); 75fe6060f1SDimitry Andric MFI.setStackID(FrameIndex, TargetStackID::WasmLocal); 76fe6060f1SDimitry Andric // Abuse SP offset to record the index of the first local in the object. 77fe6060f1SDimitry Andric unsigned Local = FuncInfo->getParams().size() + FuncInfo->getLocals().size(); 78fe6060f1SDimitry Andric MFI.setObjectOffset(FrameIndex, Local); 79fe6060f1SDimitry Andric // Allocate WebAssembly locals for each non-aggregate component of the 80fe6060f1SDimitry Andric // allocation. 81fe6060f1SDimitry Andric for (EVT ValueVT : ValueVTs) 82fe6060f1SDimitry Andric FuncInfo->addLocal(ValueVT.getSimpleVT()); 83fe6060f1SDimitry Andric // Abuse object size to record number of WebAssembly locals allocated to 84fe6060f1SDimitry Andric // this object. 85fe6060f1SDimitry Andric MFI.setObjectSize(FrameIndex, ValueVTs.size()); 86fe6060f1SDimitry Andric return static_cast<unsigned>(Local); 87fe6060f1SDimitry Andric } 88fe6060f1SDimitry Andric 890b57cec5SDimitry Andric /// We need a base pointer in the case of having items on the stack that 900b57cec5SDimitry Andric /// require stricter alignment than the stack pointer itself. Because we need 910b57cec5SDimitry Andric /// to shift the stack pointer by some unknown amount to force the alignment, 920b57cec5SDimitry Andric /// we need to record the value of the stack pointer on entry to the function. 930b57cec5SDimitry Andric bool WebAssemblyFrameLowering::hasBP(const MachineFunction &MF) const { 940b57cec5SDimitry Andric const auto *RegInfo = 950b57cec5SDimitry Andric MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 96fe6060f1SDimitry Andric return RegInfo->hasStackRealignment(MF); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric /// Return true if the specified function should have a dedicated frame pointer 1000b57cec5SDimitry Andric /// register. 1010b57cec5SDimitry Andric bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const { 1020b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // When we have var-sized objects, we move the stack pointer by an unknown 1050b57cec5SDimitry Andric // amount, and need to emit a frame pointer to restore the stack to where we 1060b57cec5SDimitry Andric // were on function entry. 1070b57cec5SDimitry Andric // If we already need a base pointer, we use that to fix up the stack pointer. 1080b57cec5SDimitry Andric // If there are no fixed-size objects, we would have no use of a frame 1090b57cec5SDimitry Andric // pointer, and thus should not emit one. 1100b57cec5SDimitry Andric bool HasFixedSizedObjects = MFI.getStackSize() > 0; 1110b57cec5SDimitry Andric bool NeedsFixedReference = !hasBP(MF) || HasFixedSizedObjects; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric return MFI.isFrameAddressTaken() || 1140b57cec5SDimitry Andric (MFI.hasVarSizedObjects() && NeedsFixedReference) || 1150b57cec5SDimitry Andric MFI.hasStackMap() || MFI.hasPatchPoint(); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric /// Under normal circumstances, when a frame pointer is not required, we reserve 1190b57cec5SDimitry Andric /// argument space for call sites in the function immediately on entry to the 1200b57cec5SDimitry Andric /// current function. This eliminates the need for add/sub sp brackets around 1210b57cec5SDimitry Andric /// call sites. Returns true if the call frame is included as part of the stack 1220b57cec5SDimitry Andric /// frame. 1230b57cec5SDimitry Andric bool WebAssemblyFrameLowering::hasReservedCallFrame( 1240b57cec5SDimitry Andric const MachineFunction &MF) const { 1250b57cec5SDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects(); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric // Returns true if this function needs a local user-space stack pointer for its 1290b57cec5SDimitry Andric // local frame (not for exception handling). 1300b57cec5SDimitry Andric bool WebAssemblyFrameLowering::needsSPForLocalFrame( 1310b57cec5SDimitry Andric const MachineFunction &MF) const { 1320b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 133*5f757f3fSDimitry Andric auto &MRI = MF.getRegInfo(); 134*5f757f3fSDimitry Andric // llvm.stacksave can explicitly read SP register and it can appear without 135*5f757f3fSDimitry Andric // dynamic alloca. 136*5f757f3fSDimitry Andric bool HasExplicitSPUse = 137*5f757f3fSDimitry Andric any_of(MRI.use_operands(getSPReg(MF)), 138*5f757f3fSDimitry Andric [](MachineOperand &MO) { return !MO.isImplicit(); }); 139*5f757f3fSDimitry Andric 140*5f757f3fSDimitry Andric return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF) || 141*5f757f3fSDimitry Andric HasExplicitSPUse; 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric // In function with EH pads, we need to make a copy of the value of 1455ffd83dbSDimitry Andric // __stack_pointer global in SP32/64 register, in order to use it when 1465ffd83dbSDimitry Andric // restoring __stack_pointer after an exception is caught. 1470b57cec5SDimitry Andric bool WebAssemblyFrameLowering::needsPrologForEH( 1480b57cec5SDimitry Andric const MachineFunction &MF) const { 1490b57cec5SDimitry Andric auto EHType = MF.getTarget().getMCAsmInfo()->getExceptionHandlingType(); 1500b57cec5SDimitry Andric return EHType == ExceptionHandling::Wasm && 1510b57cec5SDimitry Andric MF.getFunction().hasPersonalityFn() && MF.getFrameInfo().hasCalls(); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric /// Returns true if this function needs a local user-space stack pointer. 1550b57cec5SDimitry Andric /// Unlike a machine stack pointer, the wasm user stack pointer is a global 1560b57cec5SDimitry Andric /// variable, so it is loaded into a register in the prolog. 1570b57cec5SDimitry Andric bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF) const { 1580b57cec5SDimitry Andric return needsSPForLocalFrame(MF) || needsPrologForEH(MF); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric /// Returns true if the local user-space stack pointer needs to be written back 1620b57cec5SDimitry Andric /// to __stack_pointer global by this function (this is not meaningful if 1630b57cec5SDimitry Andric /// needsSP is false). If false, the stack red zone can be used and only a local 1640b57cec5SDimitry Andric /// SP is needed. 1650b57cec5SDimitry Andric bool WebAssemblyFrameLowering::needsSPWriteback( 1660b57cec5SDimitry Andric const MachineFunction &MF) const { 1670b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 1680b57cec5SDimitry Andric assert(needsSP(MF)); 1690b57cec5SDimitry Andric // When we don't need a local stack pointer for its local frame but only to 1700b57cec5SDimitry Andric // support EH, we don't need to write SP back in the epilog, because we don't 1710b57cec5SDimitry Andric // bump down the stack pointer in the prolog. We need to write SP back in the 1720b57cec5SDimitry Andric // epilog only if 1730b57cec5SDimitry Andric // 1. We need SP not only for EH support but also because we actually use 1740b57cec5SDimitry Andric // stack or we have a frame address taken. 1750b57cec5SDimitry Andric // 2. We cannot use the red zone. 1760b57cec5SDimitry Andric bool CanUseRedZone = MFI.getStackSize() <= RedZoneSize && !MFI.hasCalls() && 1770b57cec5SDimitry Andric !MF.getFunction().hasFnAttribute(Attribute::NoRedZone); 1780b57cec5SDimitry Andric return needsSPForLocalFrame(MF) && !CanUseRedZone; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1815ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getSPReg(const MachineFunction &MF) { 1825ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 1835ffd83dbSDimitry Andric ? WebAssembly::SP64 1845ffd83dbSDimitry Andric : WebAssembly::SP32; 1855ffd83dbSDimitry Andric } 1865ffd83dbSDimitry Andric 1875ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getFPReg(const MachineFunction &MF) { 1885ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 1895ffd83dbSDimitry Andric ? WebAssembly::FP64 1905ffd83dbSDimitry Andric : WebAssembly::FP32; 1915ffd83dbSDimitry Andric } 1925ffd83dbSDimitry Andric 1935ffd83dbSDimitry Andric unsigned 1945ffd83dbSDimitry Andric WebAssemblyFrameLowering::getOpcConst(const MachineFunction &MF) { 1955ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 1965ffd83dbSDimitry Andric ? WebAssembly::CONST_I64 1975ffd83dbSDimitry Andric : WebAssembly::CONST_I32; 1985ffd83dbSDimitry Andric } 1995ffd83dbSDimitry Andric 2005ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getOpcAdd(const MachineFunction &MF) { 2015ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 2025ffd83dbSDimitry Andric ? WebAssembly::ADD_I64 2035ffd83dbSDimitry Andric : WebAssembly::ADD_I32; 2045ffd83dbSDimitry Andric } 2055ffd83dbSDimitry Andric 2065ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getOpcSub(const MachineFunction &MF) { 2075ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 2085ffd83dbSDimitry Andric ? WebAssembly::SUB_I64 2095ffd83dbSDimitry Andric : WebAssembly::SUB_I32; 2105ffd83dbSDimitry Andric } 2115ffd83dbSDimitry Andric 2125ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getOpcAnd(const MachineFunction &MF) { 2135ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 2145ffd83dbSDimitry Andric ? WebAssembly::AND_I64 2155ffd83dbSDimitry Andric : WebAssembly::AND_I32; 2165ffd83dbSDimitry Andric } 2175ffd83dbSDimitry Andric 2185ffd83dbSDimitry Andric unsigned 2195ffd83dbSDimitry Andric WebAssemblyFrameLowering::getOpcGlobGet(const MachineFunction &MF) { 2205ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 2215ffd83dbSDimitry Andric ? WebAssembly::GLOBAL_GET_I64 2225ffd83dbSDimitry Andric : WebAssembly::GLOBAL_GET_I32; 2235ffd83dbSDimitry Andric } 2245ffd83dbSDimitry Andric 2255ffd83dbSDimitry Andric unsigned 2265ffd83dbSDimitry Andric WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) { 2275ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 2285ffd83dbSDimitry Andric ? WebAssembly::GLOBAL_SET_I64 2295ffd83dbSDimitry Andric : WebAssembly::GLOBAL_SET_I32; 2305ffd83dbSDimitry Andric } 2315ffd83dbSDimitry Andric 2320b57cec5SDimitry Andric void WebAssemblyFrameLowering::writeSPToGlobal( 2330b57cec5SDimitry Andric unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB, 2340b57cec5SDimitry Andric MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const { 2350b57cec5SDimitry Andric const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric const char *ES = "__stack_pointer"; 2380b57cec5SDimitry Andric auto *SPSymbol = MF.createExternalSymbolName(ES); 2395ffd83dbSDimitry Andric 2405ffd83dbSDimitry Andric BuildMI(MBB, InsertStore, DL, TII->get(getOpcGlobSet(MF))) 2410b57cec5SDimitry Andric .addExternalSymbol(SPSymbol) 2420b57cec5SDimitry Andric .addReg(SrcReg); 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric MachineBasicBlock::iterator 2460b57cec5SDimitry Andric WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( 2470b57cec5SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 2480b57cec5SDimitry Andric MachineBasicBlock::iterator I) const { 2490b57cec5SDimitry Andric assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) && 2500b57cec5SDimitry Andric "Call frame pseudos should only be used for dynamic stack adjustment"); 2515ffd83dbSDimitry Andric auto &ST = MF.getSubtarget<WebAssemblySubtarget>(); 2525ffd83dbSDimitry Andric const auto *TII = ST.getInstrInfo(); 2530b57cec5SDimitry Andric if (I->getOpcode() == TII->getCallFrameDestroyOpcode() && 2540b57cec5SDimitry Andric needsSPWriteback(MF)) { 2550b57cec5SDimitry Andric DebugLoc DL = I->getDebugLoc(); 2565ffd83dbSDimitry Andric writeSPToGlobal(getSPReg(MF), MF, MBB, I, DL); 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric return MBB.erase(I); 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, 2620b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 2630b57cec5SDimitry Andric // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions 2640b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 2650b57cec5SDimitry Andric assert(MFI.getCalleeSavedInfo().empty() && 2660b57cec5SDimitry Andric "WebAssembly should not have callee-saved registers"); 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric if (!needsSP(MF)) 2690b57cec5SDimitry Andric return; 2700b57cec5SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 2710b57cec5SDimitry Andric 2725ffd83dbSDimitry Andric auto &ST = MF.getSubtarget<WebAssemblySubtarget>(); 2735ffd83dbSDimitry Andric const auto *TII = ST.getInstrInfo(); 2740b57cec5SDimitry Andric auto &MRI = MF.getRegInfo(); 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric auto InsertPt = MBB.begin(); 2770b57cec5SDimitry Andric while (InsertPt != MBB.end() && 2780b57cec5SDimitry Andric WebAssembly::isArgument(InsertPt->getOpcode())) 2790b57cec5SDimitry Andric ++InsertPt; 2800b57cec5SDimitry Andric DebugLoc DL; 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric const TargetRegisterClass *PtrRC = 2830b57cec5SDimitry Andric MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 2845ffd83dbSDimitry Andric unsigned SPReg = getSPReg(MF); 2850b57cec5SDimitry Andric if (StackSize) 2860b57cec5SDimitry Andric SPReg = MRI.createVirtualRegister(PtrRC); 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric const char *ES = "__stack_pointer"; 2890b57cec5SDimitry Andric auto *SPSymbol = MF.createExternalSymbolName(ES); 2905ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcGlobGet(MF)), SPReg) 2910b57cec5SDimitry Andric .addExternalSymbol(SPSymbol); 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric bool HasBP = hasBP(MF); 2940b57cec5SDimitry Andric if (HasBP) { 2950b57cec5SDimitry Andric auto FI = MF.getInfo<WebAssemblyFunctionInfo>(); 2968bcb0991SDimitry Andric Register BasePtr = MRI.createVirtualRegister(PtrRC); 2970b57cec5SDimitry Andric FI->setBasePointerVreg(BasePtr); 2980b57cec5SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr) 2990b57cec5SDimitry Andric .addReg(SPReg); 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric if (StackSize) { 3020b57cec5SDimitry Andric // Subtract the frame size 3038bcb0991SDimitry Andric Register OffsetReg = MRI.createVirtualRegister(PtrRC); 3045ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), OffsetReg) 3050b57cec5SDimitry Andric .addImm(StackSize); 3065ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcSub(MF)), getSPReg(MF)) 3070b57cec5SDimitry Andric .addReg(SPReg) 3080b57cec5SDimitry Andric .addReg(OffsetReg); 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric if (HasBP) { 3118bcb0991SDimitry Andric Register BitmaskReg = MRI.createVirtualRegister(PtrRC); 3125ffd83dbSDimitry Andric Align Alignment = MFI.getMaxAlign(); 3135ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), BitmaskReg) 3145ffd83dbSDimitry Andric .addImm((int64_t) ~(Alignment.value() - 1)); 3155ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcAnd(MF)), getSPReg(MF)) 3165ffd83dbSDimitry Andric .addReg(getSPReg(MF)) 3170b57cec5SDimitry Andric .addReg(BitmaskReg); 3180b57cec5SDimitry Andric } 3190b57cec5SDimitry Andric if (hasFP(MF)) { 3200b57cec5SDimitry Andric // Unlike most conventional targets (where FP points to the saved FP), 3210b57cec5SDimitry Andric // FP points to the bottom of the fixed-size locals, so we can use positive 3220b57cec5SDimitry Andric // offsets in load/store instructions. 3235ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), getFPReg(MF)) 3245ffd83dbSDimitry Andric .addReg(getSPReg(MF)); 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric if (StackSize && needsSPWriteback(MF)) { 3275ffd83dbSDimitry Andric writeSPToGlobal(getSPReg(MF), MF, MBB, InsertPt, DL); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric } 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, 3320b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 3330b57cec5SDimitry Andric uint64_t StackSize = MF.getFrameInfo().getStackSize(); 3340b57cec5SDimitry Andric if (!needsSP(MF) || !needsSPWriteback(MF)) 3350b57cec5SDimitry Andric return; 3365ffd83dbSDimitry Andric auto &ST = MF.getSubtarget<WebAssemblySubtarget>(); 3375ffd83dbSDimitry Andric const auto *TII = ST.getInstrInfo(); 3380b57cec5SDimitry Andric auto &MRI = MF.getRegInfo(); 3390b57cec5SDimitry Andric auto InsertPt = MBB.getFirstTerminator(); 3400b57cec5SDimitry Andric DebugLoc DL; 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric if (InsertPt != MBB.end()) 3430b57cec5SDimitry Andric DL = InsertPt->getDebugLoc(); 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric // Restore the stack pointer. If we had fixed-size locals, add the offset 3460b57cec5SDimitry Andric // subtracted in the prolog. 3470b57cec5SDimitry Andric unsigned SPReg = 0; 3485ffd83dbSDimitry Andric unsigned SPFPReg = hasFP(MF) ? getFPReg(MF) : getSPReg(MF); 3490b57cec5SDimitry Andric if (hasBP(MF)) { 3500b57cec5SDimitry Andric auto FI = MF.getInfo<WebAssemblyFunctionInfo>(); 3510b57cec5SDimitry Andric SPReg = FI->getBasePointerVreg(); 3520b57cec5SDimitry Andric } else if (StackSize) { 3530b57cec5SDimitry Andric const TargetRegisterClass *PtrRC = 3540b57cec5SDimitry Andric MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 3558bcb0991SDimitry Andric Register OffsetReg = MRI.createVirtualRegister(PtrRC); 3565ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), OffsetReg) 3570b57cec5SDimitry Andric .addImm(StackSize); 3585ffd83dbSDimitry Andric // In the epilog we don't need to write the result back to the SP32/64 3595ffd83dbSDimitry Andric // physreg because it won't be used again. We can use a stackified register 3605ffd83dbSDimitry Andric // instead. 3610b57cec5SDimitry Andric SPReg = MRI.createVirtualRegister(PtrRC); 3625ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcAdd(MF)), SPReg) 3635ffd83dbSDimitry Andric .addReg(SPFPReg) 3640b57cec5SDimitry Andric .addReg(OffsetReg); 3650b57cec5SDimitry Andric } else { 3665ffd83dbSDimitry Andric SPReg = SPFPReg; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric writeSPToGlobal(SPReg, MF, MBB, InsertPt, DL); 3700b57cec5SDimitry Andric } 3715ffd83dbSDimitry Andric 372fe6060f1SDimitry Andric bool WebAssemblyFrameLowering::isSupportedStackID( 373fe6060f1SDimitry Andric TargetStackID::Value ID) const { 374fe6060f1SDimitry Andric // Use the Object stack for WebAssembly locals which can only be accessed 375fe6060f1SDimitry Andric // by name, not via an address in linear memory. 376fe6060f1SDimitry Andric if (ID == TargetStackID::WasmLocal) 377fe6060f1SDimitry Andric return true; 378fe6060f1SDimitry Andric 379fe6060f1SDimitry Andric return TargetFrameLowering::isSupportedStackID(ID); 380fe6060f1SDimitry Andric } 381fe6060f1SDimitry Andric 3825ffd83dbSDimitry Andric TargetFrameLowering::DwarfFrameBase 3835ffd83dbSDimitry Andric WebAssemblyFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const { 3845ffd83dbSDimitry Andric DwarfFrameBase Loc; 3855ffd83dbSDimitry Andric Loc.Kind = DwarfFrameBase::WasmFrameBase; 3865ffd83dbSDimitry Andric const WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 3875ffd83dbSDimitry Andric if (needsSP(MF) && MFI.isFrameBaseVirtual()) { 3885ffd83dbSDimitry Andric unsigned LocalNum = MFI.getFrameBaseLocal(); 3895ffd83dbSDimitry Andric Loc.Location.WasmLoc = {WebAssembly::TI_LOCAL, LocalNum}; 3905ffd83dbSDimitry Andric } else { 3915ffd83dbSDimitry Andric // TODO: This should work on a breakpoint at a function with no frame, 3925ffd83dbSDimitry Andric // but probably won't work for traversing up the stack. 3935ffd83dbSDimitry Andric Loc.Location.WasmLoc = {WebAssembly::TI_GLOBAL_RELOC, 0}; 3945ffd83dbSDimitry Andric } 3955ffd83dbSDimitry Andric return Loc; 3965ffd83dbSDimitry Andric } 397