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" 22*fe6060f1SDimitry Andric #include "Utils/WebAssemblyUtilities.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" 28*fe6060f1SDimitry 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" 34*fe6060f1SDimitry 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 44*fe6060f1SDimitry Andric // In an ideal world, when objects are added to the MachineFrameInfo by 45*fe6060f1SDimitry Andric // FunctionLoweringInfo::set, we could somehow hook into target-specific code to 46*fe6060f1SDimitry Andric // ensure they are assigned the right stack ID. However there isn't a hook that 47*fe6060f1SDimitry Andric // runs between then and DAG building time, though, so instead we hoist stack 48*fe6060f1SDimitry Andric // objects lazily when they are first used, and comprehensively after the DAG is 49*fe6060f1SDimitry Andric // built via the PreprocessISelDAG hook, called by the 50*fe6060f1SDimitry Andric // SelectionDAGISel::runOnMachineFunction. We have to do it in two places 51*fe6060f1SDimitry Andric // because we want to do it while building the selection DAG for uses of alloca, 52*fe6060f1SDimitry Andric // but not all alloca instructions are used so we have to follow up afterwards. 53*fe6060f1SDimitry Andric Optional<unsigned> 54*fe6060f1SDimitry Andric WebAssemblyFrameLowering::getLocalForStackObject(MachineFunction &MF, 55*fe6060f1SDimitry Andric int FrameIndex) { 56*fe6060f1SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 57*fe6060f1SDimitry Andric 58*fe6060f1SDimitry Andric // If already hoisted to a local, done. 59*fe6060f1SDimitry Andric if (MFI.getStackID(FrameIndex) == TargetStackID::WasmLocal) 60*fe6060f1SDimitry Andric return static_cast<unsigned>(MFI.getObjectOffset(FrameIndex)); 61*fe6060f1SDimitry Andric 62*fe6060f1SDimitry Andric // If not allocated in the object address space, this object will be in 63*fe6060f1SDimitry Andric // linear memory. 64*fe6060f1SDimitry Andric const AllocaInst *AI = MFI.getObjectAllocation(FrameIndex); 65*fe6060f1SDimitry Andric if (!AI || 66*fe6060f1SDimitry Andric !WebAssembly::isWasmVarAddressSpace(AI->getType()->getAddressSpace())) 67*fe6060f1SDimitry Andric return None; 68*fe6060f1SDimitry Andric 69*fe6060f1SDimitry Andric // Otherwise, allocate this object in the named value stack, outside of linear 70*fe6060f1SDimitry Andric // memory. 71*fe6060f1SDimitry Andric SmallVector<EVT, 4> ValueVTs; 72*fe6060f1SDimitry Andric const WebAssemblyTargetLowering &TLI = 73*fe6060f1SDimitry Andric *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 74*fe6060f1SDimitry Andric WebAssemblyFunctionInfo *FuncInfo = MF.getInfo<WebAssemblyFunctionInfo>(); 75*fe6060f1SDimitry Andric ComputeValueVTs(TLI, MF.getDataLayout(), AI->getAllocatedType(), ValueVTs); 76*fe6060f1SDimitry Andric MFI.setStackID(FrameIndex, TargetStackID::WasmLocal); 77*fe6060f1SDimitry Andric // Abuse SP offset to record the index of the first local in the object. 78*fe6060f1SDimitry Andric unsigned Local = FuncInfo->getParams().size() + FuncInfo->getLocals().size(); 79*fe6060f1SDimitry Andric MFI.setObjectOffset(FrameIndex, Local); 80*fe6060f1SDimitry Andric // Allocate WebAssembly locals for each non-aggregate component of the 81*fe6060f1SDimitry Andric // allocation. 82*fe6060f1SDimitry Andric for (EVT ValueVT : ValueVTs) 83*fe6060f1SDimitry Andric FuncInfo->addLocal(ValueVT.getSimpleVT()); 84*fe6060f1SDimitry Andric // Abuse object size to record number of WebAssembly locals allocated to 85*fe6060f1SDimitry Andric // this object. 86*fe6060f1SDimitry Andric MFI.setObjectSize(FrameIndex, ValueVTs.size()); 87*fe6060f1SDimitry Andric return static_cast<unsigned>(Local); 88*fe6060f1SDimitry Andric } 89*fe6060f1SDimitry Andric 900b57cec5SDimitry Andric /// We need a base pointer in the case of having items on the stack that 910b57cec5SDimitry Andric /// require stricter alignment than the stack pointer itself. Because we need 920b57cec5SDimitry Andric /// to shift the stack pointer by some unknown amount to force the alignment, 930b57cec5SDimitry Andric /// we need to record the value of the stack pointer on entry to the function. 940b57cec5SDimitry Andric bool WebAssemblyFrameLowering::hasBP(const MachineFunction &MF) const { 950b57cec5SDimitry Andric const auto *RegInfo = 960b57cec5SDimitry Andric MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 97*fe6060f1SDimitry Andric return RegInfo->hasStackRealignment(MF); 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric /// Return true if the specified function should have a dedicated frame pointer 1010b57cec5SDimitry Andric /// register. 1020b57cec5SDimitry Andric bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const { 1030b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric // When we have var-sized objects, we move the stack pointer by an unknown 1060b57cec5SDimitry Andric // amount, and need to emit a frame pointer to restore the stack to where we 1070b57cec5SDimitry Andric // were on function entry. 1080b57cec5SDimitry Andric // If we already need a base pointer, we use that to fix up the stack pointer. 1090b57cec5SDimitry Andric // If there are no fixed-size objects, we would have no use of a frame 1100b57cec5SDimitry Andric // pointer, and thus should not emit one. 1110b57cec5SDimitry Andric bool HasFixedSizedObjects = MFI.getStackSize() > 0; 1120b57cec5SDimitry Andric bool NeedsFixedReference = !hasBP(MF) || HasFixedSizedObjects; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric return MFI.isFrameAddressTaken() || 1150b57cec5SDimitry Andric (MFI.hasVarSizedObjects() && NeedsFixedReference) || 1160b57cec5SDimitry Andric MFI.hasStackMap() || MFI.hasPatchPoint(); 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric /// Under normal circumstances, when a frame pointer is not required, we reserve 1200b57cec5SDimitry Andric /// argument space for call sites in the function immediately on entry to the 1210b57cec5SDimitry Andric /// current function. This eliminates the need for add/sub sp brackets around 1220b57cec5SDimitry Andric /// call sites. Returns true if the call frame is included as part of the stack 1230b57cec5SDimitry Andric /// frame. 1240b57cec5SDimitry Andric bool WebAssemblyFrameLowering::hasReservedCallFrame( 1250b57cec5SDimitry Andric const MachineFunction &MF) const { 1260b57cec5SDimitry Andric return !MF.getFrameInfo().hasVarSizedObjects(); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric // Returns true if this function needs a local user-space stack pointer for its 1300b57cec5SDimitry Andric // local frame (not for exception handling). 1310b57cec5SDimitry Andric bool WebAssemblyFrameLowering::needsSPForLocalFrame( 1320b57cec5SDimitry Andric const MachineFunction &MF) const { 1330b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 1340b57cec5SDimitry Andric return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric // In function with EH pads, we need to make a copy of the value of 1385ffd83dbSDimitry Andric // __stack_pointer global in SP32/64 register, in order to use it when 1395ffd83dbSDimitry Andric // restoring __stack_pointer after an exception is caught. 1400b57cec5SDimitry Andric bool WebAssemblyFrameLowering::needsPrologForEH( 1410b57cec5SDimitry Andric const MachineFunction &MF) const { 1420b57cec5SDimitry Andric auto EHType = MF.getTarget().getMCAsmInfo()->getExceptionHandlingType(); 1430b57cec5SDimitry Andric return EHType == ExceptionHandling::Wasm && 1440b57cec5SDimitry Andric MF.getFunction().hasPersonalityFn() && MF.getFrameInfo().hasCalls(); 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric /// Returns true if this function needs a local user-space stack pointer. 1480b57cec5SDimitry Andric /// Unlike a machine stack pointer, the wasm user stack pointer is a global 1490b57cec5SDimitry Andric /// variable, so it is loaded into a register in the prolog. 1500b57cec5SDimitry Andric bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF) const { 1510b57cec5SDimitry Andric return needsSPForLocalFrame(MF) || needsPrologForEH(MF); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric /// Returns true if the local user-space stack pointer needs to be written back 1550b57cec5SDimitry Andric /// to __stack_pointer global by this function (this is not meaningful if 1560b57cec5SDimitry Andric /// needsSP is false). If false, the stack red zone can be used and only a local 1570b57cec5SDimitry Andric /// SP is needed. 1580b57cec5SDimitry Andric bool WebAssemblyFrameLowering::needsSPWriteback( 1590b57cec5SDimitry Andric const MachineFunction &MF) const { 1600b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 1610b57cec5SDimitry Andric assert(needsSP(MF)); 1620b57cec5SDimitry Andric // When we don't need a local stack pointer for its local frame but only to 1630b57cec5SDimitry Andric // support EH, we don't need to write SP back in the epilog, because we don't 1640b57cec5SDimitry Andric // bump down the stack pointer in the prolog. We need to write SP back in the 1650b57cec5SDimitry Andric // epilog only if 1660b57cec5SDimitry Andric // 1. We need SP not only for EH support but also because we actually use 1670b57cec5SDimitry Andric // stack or we have a frame address taken. 1680b57cec5SDimitry Andric // 2. We cannot use the red zone. 1690b57cec5SDimitry Andric bool CanUseRedZone = MFI.getStackSize() <= RedZoneSize && !MFI.hasCalls() && 1700b57cec5SDimitry Andric !MF.getFunction().hasFnAttribute(Attribute::NoRedZone); 1710b57cec5SDimitry Andric return needsSPForLocalFrame(MF) && !CanUseRedZone; 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1745ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getSPReg(const MachineFunction &MF) { 1755ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 1765ffd83dbSDimitry Andric ? WebAssembly::SP64 1775ffd83dbSDimitry Andric : WebAssembly::SP32; 1785ffd83dbSDimitry Andric } 1795ffd83dbSDimitry Andric 1805ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getFPReg(const MachineFunction &MF) { 1815ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 1825ffd83dbSDimitry Andric ? WebAssembly::FP64 1835ffd83dbSDimitry Andric : WebAssembly::FP32; 1845ffd83dbSDimitry Andric } 1855ffd83dbSDimitry Andric 1865ffd83dbSDimitry Andric unsigned 1875ffd83dbSDimitry Andric WebAssemblyFrameLowering::getOpcConst(const MachineFunction &MF) { 1885ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 1895ffd83dbSDimitry Andric ? WebAssembly::CONST_I64 1905ffd83dbSDimitry Andric : WebAssembly::CONST_I32; 1915ffd83dbSDimitry Andric } 1925ffd83dbSDimitry Andric 1935ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getOpcAdd(const MachineFunction &MF) { 1945ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 1955ffd83dbSDimitry Andric ? WebAssembly::ADD_I64 1965ffd83dbSDimitry Andric : WebAssembly::ADD_I32; 1975ffd83dbSDimitry Andric } 1985ffd83dbSDimitry Andric 1995ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getOpcSub(const MachineFunction &MF) { 2005ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 2015ffd83dbSDimitry Andric ? WebAssembly::SUB_I64 2025ffd83dbSDimitry Andric : WebAssembly::SUB_I32; 2035ffd83dbSDimitry Andric } 2045ffd83dbSDimitry Andric 2055ffd83dbSDimitry Andric unsigned WebAssemblyFrameLowering::getOpcAnd(const MachineFunction &MF) { 2065ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 2075ffd83dbSDimitry Andric ? WebAssembly::AND_I64 2085ffd83dbSDimitry Andric : WebAssembly::AND_I32; 2095ffd83dbSDimitry Andric } 2105ffd83dbSDimitry Andric 2115ffd83dbSDimitry Andric unsigned 2125ffd83dbSDimitry Andric WebAssemblyFrameLowering::getOpcGlobGet(const MachineFunction &MF) { 2135ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 2145ffd83dbSDimitry Andric ? WebAssembly::GLOBAL_GET_I64 2155ffd83dbSDimitry Andric : WebAssembly::GLOBAL_GET_I32; 2165ffd83dbSDimitry Andric } 2175ffd83dbSDimitry Andric 2185ffd83dbSDimitry Andric unsigned 2195ffd83dbSDimitry Andric WebAssemblyFrameLowering::getOpcGlobSet(const MachineFunction &MF) { 2205ffd83dbSDimitry Andric return MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() 2215ffd83dbSDimitry Andric ? WebAssembly::GLOBAL_SET_I64 2225ffd83dbSDimitry Andric : WebAssembly::GLOBAL_SET_I32; 2235ffd83dbSDimitry Andric } 2245ffd83dbSDimitry Andric 2250b57cec5SDimitry Andric void WebAssemblyFrameLowering::writeSPToGlobal( 2260b57cec5SDimitry Andric unsigned SrcReg, MachineFunction &MF, MachineBasicBlock &MBB, 2270b57cec5SDimitry Andric MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) const { 2280b57cec5SDimitry Andric const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric const char *ES = "__stack_pointer"; 2310b57cec5SDimitry Andric auto *SPSymbol = MF.createExternalSymbolName(ES); 2325ffd83dbSDimitry Andric 2335ffd83dbSDimitry Andric BuildMI(MBB, InsertStore, DL, TII->get(getOpcGlobSet(MF))) 2340b57cec5SDimitry Andric .addExternalSymbol(SPSymbol) 2350b57cec5SDimitry Andric .addReg(SrcReg); 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric MachineBasicBlock::iterator 2390b57cec5SDimitry Andric WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( 2400b57cec5SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 2410b57cec5SDimitry Andric MachineBasicBlock::iterator I) const { 2420b57cec5SDimitry Andric assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) && 2430b57cec5SDimitry Andric "Call frame pseudos should only be used for dynamic stack adjustment"); 2445ffd83dbSDimitry Andric auto &ST = MF.getSubtarget<WebAssemblySubtarget>(); 2455ffd83dbSDimitry Andric const auto *TII = ST.getInstrInfo(); 2460b57cec5SDimitry Andric if (I->getOpcode() == TII->getCallFrameDestroyOpcode() && 2470b57cec5SDimitry Andric needsSPWriteback(MF)) { 2480b57cec5SDimitry Andric DebugLoc DL = I->getDebugLoc(); 2495ffd83dbSDimitry Andric writeSPToGlobal(getSPReg(MF), MF, MBB, I, DL); 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric return MBB.erase(I); 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, 2550b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 2560b57cec5SDimitry Andric // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions 2570b57cec5SDimitry Andric auto &MFI = MF.getFrameInfo(); 2580b57cec5SDimitry Andric assert(MFI.getCalleeSavedInfo().empty() && 2590b57cec5SDimitry Andric "WebAssembly should not have callee-saved registers"); 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric if (!needsSP(MF)) 2620b57cec5SDimitry Andric return; 2630b57cec5SDimitry Andric uint64_t StackSize = MFI.getStackSize(); 2640b57cec5SDimitry Andric 2655ffd83dbSDimitry Andric auto &ST = MF.getSubtarget<WebAssemblySubtarget>(); 2665ffd83dbSDimitry Andric const auto *TII = ST.getInstrInfo(); 2670b57cec5SDimitry Andric auto &MRI = MF.getRegInfo(); 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric auto InsertPt = MBB.begin(); 2700b57cec5SDimitry Andric while (InsertPt != MBB.end() && 2710b57cec5SDimitry Andric WebAssembly::isArgument(InsertPt->getOpcode())) 2720b57cec5SDimitry Andric ++InsertPt; 2730b57cec5SDimitry Andric DebugLoc DL; 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric const TargetRegisterClass *PtrRC = 2760b57cec5SDimitry Andric MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 2775ffd83dbSDimitry Andric unsigned SPReg = getSPReg(MF); 2780b57cec5SDimitry Andric if (StackSize) 2790b57cec5SDimitry Andric SPReg = MRI.createVirtualRegister(PtrRC); 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric const char *ES = "__stack_pointer"; 2820b57cec5SDimitry Andric auto *SPSymbol = MF.createExternalSymbolName(ES); 2835ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcGlobGet(MF)), SPReg) 2840b57cec5SDimitry Andric .addExternalSymbol(SPSymbol); 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric bool HasBP = hasBP(MF); 2870b57cec5SDimitry Andric if (HasBP) { 2880b57cec5SDimitry Andric auto FI = MF.getInfo<WebAssemblyFunctionInfo>(); 2898bcb0991SDimitry Andric Register BasePtr = MRI.createVirtualRegister(PtrRC); 2900b57cec5SDimitry Andric FI->setBasePointerVreg(BasePtr); 2910b57cec5SDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr) 2920b57cec5SDimitry Andric .addReg(SPReg); 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric if (StackSize) { 2950b57cec5SDimitry Andric // Subtract the frame size 2968bcb0991SDimitry Andric Register OffsetReg = MRI.createVirtualRegister(PtrRC); 2975ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), OffsetReg) 2980b57cec5SDimitry Andric .addImm(StackSize); 2995ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcSub(MF)), getSPReg(MF)) 3000b57cec5SDimitry Andric .addReg(SPReg) 3010b57cec5SDimitry Andric .addReg(OffsetReg); 3020b57cec5SDimitry Andric } 3030b57cec5SDimitry Andric if (HasBP) { 3048bcb0991SDimitry Andric Register BitmaskReg = MRI.createVirtualRegister(PtrRC); 3055ffd83dbSDimitry Andric Align Alignment = MFI.getMaxAlign(); 3065ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), BitmaskReg) 3075ffd83dbSDimitry Andric .addImm((int64_t) ~(Alignment.value() - 1)); 3085ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcAnd(MF)), getSPReg(MF)) 3095ffd83dbSDimitry Andric .addReg(getSPReg(MF)) 3100b57cec5SDimitry Andric .addReg(BitmaskReg); 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric if (hasFP(MF)) { 3130b57cec5SDimitry Andric // Unlike most conventional targets (where FP points to the saved FP), 3140b57cec5SDimitry Andric // FP points to the bottom of the fixed-size locals, so we can use positive 3150b57cec5SDimitry Andric // offsets in load/store instructions. 3165ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), getFPReg(MF)) 3175ffd83dbSDimitry Andric .addReg(getSPReg(MF)); 3180b57cec5SDimitry Andric } 3190b57cec5SDimitry Andric if (StackSize && needsSPWriteback(MF)) { 3205ffd83dbSDimitry Andric writeSPToGlobal(getSPReg(MF), MF, MBB, InsertPt, DL); 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, 3250b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 3260b57cec5SDimitry Andric uint64_t StackSize = MF.getFrameInfo().getStackSize(); 3270b57cec5SDimitry Andric if (!needsSP(MF) || !needsSPWriteback(MF)) 3280b57cec5SDimitry Andric return; 3295ffd83dbSDimitry Andric auto &ST = MF.getSubtarget<WebAssemblySubtarget>(); 3305ffd83dbSDimitry Andric const auto *TII = ST.getInstrInfo(); 3310b57cec5SDimitry Andric auto &MRI = MF.getRegInfo(); 3320b57cec5SDimitry Andric auto InsertPt = MBB.getFirstTerminator(); 3330b57cec5SDimitry Andric DebugLoc DL; 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric if (InsertPt != MBB.end()) 3360b57cec5SDimitry Andric DL = InsertPt->getDebugLoc(); 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric // Restore the stack pointer. If we had fixed-size locals, add the offset 3390b57cec5SDimitry Andric // subtracted in the prolog. 3400b57cec5SDimitry Andric unsigned SPReg = 0; 3415ffd83dbSDimitry Andric unsigned SPFPReg = hasFP(MF) ? getFPReg(MF) : getSPReg(MF); 3420b57cec5SDimitry Andric if (hasBP(MF)) { 3430b57cec5SDimitry Andric auto FI = MF.getInfo<WebAssemblyFunctionInfo>(); 3440b57cec5SDimitry Andric SPReg = FI->getBasePointerVreg(); 3450b57cec5SDimitry Andric } else if (StackSize) { 3460b57cec5SDimitry Andric const TargetRegisterClass *PtrRC = 3470b57cec5SDimitry Andric MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 3488bcb0991SDimitry Andric Register OffsetReg = MRI.createVirtualRegister(PtrRC); 3495ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcConst(MF)), OffsetReg) 3500b57cec5SDimitry Andric .addImm(StackSize); 3515ffd83dbSDimitry Andric // In the epilog we don't need to write the result back to the SP32/64 3525ffd83dbSDimitry Andric // physreg because it won't be used again. We can use a stackified register 3535ffd83dbSDimitry Andric // instead. 3540b57cec5SDimitry Andric SPReg = MRI.createVirtualRegister(PtrRC); 3555ffd83dbSDimitry Andric BuildMI(MBB, InsertPt, DL, TII->get(getOpcAdd(MF)), SPReg) 3565ffd83dbSDimitry Andric .addReg(SPFPReg) 3570b57cec5SDimitry Andric .addReg(OffsetReg); 3580b57cec5SDimitry Andric } else { 3595ffd83dbSDimitry Andric SPReg = SPFPReg; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric writeSPToGlobal(SPReg, MF, MBB, InsertPt, DL); 3630b57cec5SDimitry Andric } 3645ffd83dbSDimitry Andric 365*fe6060f1SDimitry Andric bool WebAssemblyFrameLowering::isSupportedStackID( 366*fe6060f1SDimitry Andric TargetStackID::Value ID) const { 367*fe6060f1SDimitry Andric // Use the Object stack for WebAssembly locals which can only be accessed 368*fe6060f1SDimitry Andric // by name, not via an address in linear memory. 369*fe6060f1SDimitry Andric if (ID == TargetStackID::WasmLocal) 370*fe6060f1SDimitry Andric return true; 371*fe6060f1SDimitry Andric 372*fe6060f1SDimitry Andric return TargetFrameLowering::isSupportedStackID(ID); 373*fe6060f1SDimitry Andric } 374*fe6060f1SDimitry Andric 3755ffd83dbSDimitry Andric TargetFrameLowering::DwarfFrameBase 3765ffd83dbSDimitry Andric WebAssemblyFrameLowering::getDwarfFrameBase(const MachineFunction &MF) const { 3775ffd83dbSDimitry Andric DwarfFrameBase Loc; 3785ffd83dbSDimitry Andric Loc.Kind = DwarfFrameBase::WasmFrameBase; 3795ffd83dbSDimitry Andric const WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 3805ffd83dbSDimitry Andric if (needsSP(MF) && MFI.isFrameBaseVirtual()) { 3815ffd83dbSDimitry Andric unsigned LocalNum = MFI.getFrameBaseLocal(); 3825ffd83dbSDimitry Andric Loc.Location.WasmLoc = {WebAssembly::TI_LOCAL, LocalNum}; 3835ffd83dbSDimitry Andric } else { 3845ffd83dbSDimitry Andric // TODO: This should work on a breakpoint at a function with no frame, 3855ffd83dbSDimitry Andric // but probably won't work for traversing up the stack. 3865ffd83dbSDimitry Andric Loc.Location.WasmLoc = {WebAssembly::TI_GLOBAL_RELOC, 0}; 3875ffd83dbSDimitry Andric } 3885ffd83dbSDimitry Andric return Loc; 3895ffd83dbSDimitry Andric } 390