110e730a2SDan Gohman //===-- WebAssemblyFrameLowering.cpp - WebAssembly Frame Lowering ----------==// 210e730a2SDan Gohman // 310e730a2SDan Gohman // The LLVM Compiler Infrastructure 410e730a2SDan Gohman // 510e730a2SDan Gohman // This file is distributed under the University of Illinois Open Source 610e730a2SDan Gohman // License. See LICENSE.TXT for details. 710e730a2SDan Gohman // 810e730a2SDan Gohman //===----------------------------------------------------------------------===// 910e730a2SDan Gohman /// 1010e730a2SDan Gohman /// \file 1110e730a2SDan Gohman /// \brief This file contains the WebAssembly implementation of 1210e730a2SDan Gohman /// TargetFrameLowering class. 1310e730a2SDan Gohman /// 1410e730a2SDan Gohman /// On WebAssembly, there aren't a lot of things to do here. There are no 1510e730a2SDan Gohman /// callee-saved registers to save, and no spill slots. 1610e730a2SDan Gohman /// 1710e730a2SDan Gohman /// The stack grows downward. 1810e730a2SDan Gohman /// 1910e730a2SDan Gohman //===----------------------------------------------------------------------===// 2010e730a2SDan Gohman 2110e730a2SDan Gohman #include "WebAssemblyFrameLowering.h" 2210e730a2SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 2310e730a2SDan Gohman #include "WebAssemblyInstrInfo.h" 2410e730a2SDan Gohman #include "WebAssemblyMachineFunctionInfo.h" 2510e730a2SDan Gohman #include "WebAssemblySubtarget.h" 2610e730a2SDan Gohman #include "WebAssemblyTargetMachine.h" 2710e730a2SDan Gohman #include "llvm/CodeGen/MachineFrameInfo.h" 2810e730a2SDan Gohman #include "llvm/CodeGen/MachineFunction.h" 2910e730a2SDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h" 3010e730a2SDan Gohman #include "llvm/CodeGen/MachineModuleInfo.h" 3110e730a2SDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h" 3210e730a2SDan Gohman #include "llvm/Support/Debug.h" 3310e730a2SDan Gohman using namespace llvm; 3410e730a2SDan Gohman 3503855df1SJF Bastien #define DEBUG_TYPE "wasm-frame-info" 3610e730a2SDan Gohman 379769debfSDerek Schuff // TODO: wasm64 389769debfSDerek Schuff // TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions 3910e730a2SDan Gohman 40*0d41b7b3SDerek Schuff /// We need a base pointer in the case of having items on the stack that 41*0d41b7b3SDerek Schuff /// require stricter alignment than the stack pointer itself. Because we need 42*0d41b7b3SDerek Schuff /// to shift the stack pointer by some unknown amount to force the alignment, 43*0d41b7b3SDerek Schuff /// we need to record the value of the stack pointer on entry to the function. 44*0d41b7b3SDerek Schuff bool WebAssemblyFrameLowering::hasBP( 45*0d41b7b3SDerek Schuff const MachineFunction &MF) const { 46*0d41b7b3SDerek Schuff const auto *RegInfo = 47*0d41b7b3SDerek Schuff MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 48*0d41b7b3SDerek Schuff return RegInfo->needsStackRealignment(MF); 49*0d41b7b3SDerek Schuff } 50*0d41b7b3SDerek Schuff 5110e730a2SDan Gohman /// Return true if the specified function should have a dedicated frame pointer 5210e730a2SDan Gohman /// register. 5310e730a2SDan Gohman bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const { 54941a705bSMatthias Braun const MachineFrameInfo &MFI = MF.getFrameInfo(); 55*0d41b7b3SDerek Schuff 56*0d41b7b3SDerek Schuff // When we have var-sized objects, we move the stack pointer by an unknown 57*0d41b7b3SDerek Schuff // amount, and need to emit a frame pointer to restore the stack to where we 58*0d41b7b3SDerek Schuff // were on function entry. 59*0d41b7b3SDerek Schuff // If we already need a base pointer, we use that to fix up the stack pointer. 60*0d41b7b3SDerek Schuff // If there are no fixed-size objects, we would have no use of a frame 61*0d41b7b3SDerek Schuff // pointer, and thus should not emit one. 62*0d41b7b3SDerek Schuff bool HasFixedSizedObjects = MFI.getStackSize() > 0; 63*0d41b7b3SDerek Schuff bool NeedsFixedReference = !hasBP(MF) || HasFixedSizedObjects; 64*0d41b7b3SDerek Schuff 65*0d41b7b3SDerek Schuff return MFI.isFrameAddressTaken() || 66*0d41b7b3SDerek Schuff (MFI.hasVarSizedObjects() && NeedsFixedReference) || 67*0d41b7b3SDerek Schuff MFI.hasStackMap() || MFI.hasPatchPoint(); 6810e730a2SDan Gohman } 6910e730a2SDan Gohman 7010e730a2SDan Gohman /// Under normal circumstances, when a frame pointer is not required, we reserve 7110e730a2SDan Gohman /// argument space for call sites in the function immediately on entry to the 7210e730a2SDan Gohman /// current function. This eliminates the need for add/sub sp brackets around 7310e730a2SDan Gohman /// call sites. Returns true if the call frame is included as part of the stack 7410e730a2SDan Gohman /// frame. 7510e730a2SDan Gohman bool WebAssemblyFrameLowering::hasReservedCallFrame( 7610e730a2SDan Gohman const MachineFunction &MF) const { 77941a705bSMatthias Braun return !MF.getFrameInfo().hasVarSizedObjects(); 7810e730a2SDan Gohman } 7910e730a2SDan Gohman 804b3bb213SDerek Schuff 814b3bb213SDerek Schuff /// Returns true if this function needs a local user-space stack pointer. 824b3bb213SDerek Schuff /// Unlike a machine stack pointer, the wasm user stack pointer is a global 834b3bb213SDerek Schuff /// variable, so it is loaded into a register in the prolog. 844b3bb213SDerek Schuff bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF, 854b3bb213SDerek Schuff const MachineFrameInfo &MFI) const { 864b3bb213SDerek Schuff return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF); 874b3bb213SDerek Schuff } 884b3bb213SDerek Schuff 894b3bb213SDerek Schuff /// Returns true if the local user-space stack pointer needs to be written back 904b3bb213SDerek Schuff /// to memory by this function (this is not meaningful if needsSP is false). If 914b3bb213SDerek Schuff /// false, the stack red zone can be used and only a local SP is needed. 924b3bb213SDerek Schuff bool WebAssemblyFrameLowering::needsSPWriteback( 934b3bb213SDerek Schuff const MachineFunction &MF, const MachineFrameInfo &MFI) const { 94450a8075SDan Gohman assert(needsSP(MF, MFI)); 954b3bb213SDerek Schuff return MFI.getStackSize() > RedZoneSize || MFI.hasCalls() || 964b3bb213SDerek Schuff MF.getFunction()->hasFnAttribute(Attribute::NoRedZone); 974b3bb213SDerek Schuff } 984b3bb213SDerek Schuff 9927e3b8a6SDerek Schuff static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF, 10027e3b8a6SDerek Schuff MachineBasicBlock &MBB, 101d4207ba0SDerek Schuff MachineBasicBlock::iterator &InsertAddr, 102d4207ba0SDerek Schuff MachineBasicBlock::iterator &InsertStore, 103bdc4956bSBenjamin Kramer const DebugLoc &DL) { 104d08cd15fSDan Gohman const char *ES = "__stack_pointer"; 105d08cd15fSDan Gohman auto *SPSymbol = MF.createExternalSymbolName(ES); 1060cfb5f85SDan Gohman MachineRegisterInfo &MRI = MF.getRegInfo(); 1070cfb5f85SDan Gohman const TargetRegisterClass *PtrRC = 1080cfb5f85SDan Gohman MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 109d530f68dSDan Gohman unsigned Zero = MRI.createVirtualRegister(PtrRC); 11027e3b8a6SDerek Schuff const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 11127e3b8a6SDerek Schuff 112d530f68dSDan Gohman BuildMI(MBB, InsertAddr, DL, TII->get(WebAssembly::CONST_I32), Zero) 113d530f68dSDan Gohman .addImm(0); 1149bc1b230SBenjamin Kramer MachineMemOperand *MMO = MF.getMachineMemOperand( 1159bc1b230SBenjamin Kramer MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)), 11627e3b8a6SDerek Schuff MachineMemOperand::MOStore, 4, 4); 1177f1bdb2eSDan Gohman BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::STORE_I32)) 11848abaa9cSDan Gohman .addImm(2) // p2align 119d530f68dSDan Gohman .addExternalSymbol(SPSymbol) 120d530f68dSDan Gohman .addReg(Zero) 12127e3b8a6SDerek Schuff .addReg(SrcReg) 12227e3b8a6SDerek Schuff .addMemOperand(MMO); 12327e3b8a6SDerek Schuff } 12427e3b8a6SDerek Schuff 125e1a2e90fSHans Wennborg MachineBasicBlock::iterator 126e1a2e90fSHans Wennborg WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( 1278bb5f292SDerek Schuff MachineFunction &MF, MachineBasicBlock &MBB, 1288bb5f292SDerek Schuff MachineBasicBlock::iterator I) const { 129*0d41b7b3SDerek Schuff assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) && 13027e3b8a6SDerek Schuff "Call frame pseudos should only be used for dynamic stack adjustment"); 13127e3b8a6SDerek Schuff const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1324b3bb213SDerek Schuff if (I->getOpcode() == TII->getCallFrameDestroyOpcode() && 133941a705bSMatthias Braun needsSPWriteback(MF, MF.getFrameInfo())) { 13427e3b8a6SDerek Schuff DebugLoc DL = I->getDebugLoc(); 135d4207ba0SDerek Schuff writeSPToMemory(WebAssembly::SP32, MF, MBB, I, I, DL); 13627e3b8a6SDerek Schuff } 137e1a2e90fSHans Wennborg return MBB.erase(I); 1388bb5f292SDerek Schuff } 1398bb5f292SDerek Schuff 1408bb5f292SDerek Schuff void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, 1418bb5f292SDerek Schuff MachineBasicBlock &MBB) const { 1428bb5f292SDerek Schuff // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions 143941a705bSMatthias Braun auto &MFI = MF.getFrameInfo(); 144941a705bSMatthias Braun assert(MFI.getCalleeSavedInfo().empty() && 1458bb5f292SDerek Schuff "WebAssembly should not have callee-saved registers"); 1466ea637afSDerek Schuff 147941a705bSMatthias Braun if (!needsSP(MF, MFI)) return; 148941a705bSMatthias Braun uint64_t StackSize = MFI.getStackSize(); 1498bb5f292SDerek Schuff 1503196650bSDan Gohman const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1516ea637afSDerek Schuff auto &MRI = MF.getRegInfo(); 1528bb5f292SDerek Schuff 1538bb5f292SDerek Schuff auto InsertPt = MBB.begin(); 1548bb5f292SDerek Schuff DebugLoc DL; 1558bb5f292SDerek Schuff 1560cfb5f85SDan Gohman const TargetRegisterClass *PtrRC = 1570cfb5f85SDan Gohman MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 158d530f68dSDan Gohman unsigned Zero = MRI.createVirtualRegister(PtrRC); 159*0d41b7b3SDerek Schuff unsigned SPReg = WebAssembly::SP32; 160*0d41b7b3SDerek Schuff if (StackSize) 161*0d41b7b3SDerek Schuff SPReg = MRI.createVirtualRegister(PtrRC); 162d08cd15fSDan Gohman const char *ES = "__stack_pointer"; 163d08cd15fSDan Gohman auto *SPSymbol = MF.createExternalSymbolName(ES); 164d530f68dSDan Gohman BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero) 165d530f68dSDan Gohman .addImm(0); 1669bc1b230SBenjamin Kramer MachineMemOperand *LoadMMO = MF.getMachineMemOperand( 1679bc1b230SBenjamin Kramer MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)), 1686ea637afSDerek Schuff MachineMemOperand::MOLoad, 4, 4); 1696ea637afSDerek Schuff // Load the SP value. 170*0d41b7b3SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg) 17148abaa9cSDan Gohman .addImm(2) // p2align 172d530f68dSDan Gohman .addExternalSymbol(SPSymbol) 173d530f68dSDan Gohman .addReg(Zero) // addr 1746ea637afSDerek Schuff .addMemOperand(LoadMMO); 1756ea637afSDerek Schuff 176*0d41b7b3SDerek Schuff bool HasBP = hasBP(MF); 177*0d41b7b3SDerek Schuff if (HasBP) { 178*0d41b7b3SDerek Schuff auto FI = MF.getInfo<WebAssemblyFunctionInfo>(); 179*0d41b7b3SDerek Schuff unsigned BasePtr = MRI.createVirtualRegister(PtrRC); 180*0d41b7b3SDerek Schuff FI->setBasePointerVreg(BasePtr); 181*0d41b7b3SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr) 182*0d41b7b3SDerek Schuff .addReg(SPReg); 183*0d41b7b3SDerek Schuff } 1846ea637afSDerek Schuff if (StackSize) { 1856ea637afSDerek Schuff // Subtract the frame size 1860cfb5f85SDan Gohman unsigned OffsetReg = MRI.createVirtualRegister(PtrRC); 1876ea637afSDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) 1886ea637afSDerek Schuff .addImm(StackSize); 1893f063295SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32), 1906ea637afSDerek Schuff WebAssembly::SP32) 1916ea637afSDerek Schuff .addReg(SPReg) 1926ea637afSDerek Schuff .addReg(OffsetReg); 1936ea637afSDerek Schuff } 194*0d41b7b3SDerek Schuff if (HasBP) { 195*0d41b7b3SDerek Schuff unsigned BitmaskReg = MRI.createVirtualRegister(PtrRC); 196*0d41b7b3SDerek Schuff unsigned Alignment = MFI.getMaxAlignment(); 197*0d41b7b3SDerek Schuff assert((1 << countTrailingZeros(Alignment)) == Alignment && 198*0d41b7b3SDerek Schuff "Alignment must be a power of 2"); 199*0d41b7b3SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), BitmaskReg) 200*0d41b7b3SDerek Schuff .addImm((int)~(Alignment - 1)); 201*0d41b7b3SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::AND_I32), 202*0d41b7b3SDerek Schuff WebAssembly::SP32) 203*0d41b7b3SDerek Schuff .addReg(WebAssembly::SP32) 204*0d41b7b3SDerek Schuff .addReg(BitmaskReg); 205*0d41b7b3SDerek Schuff } 2066ea637afSDerek Schuff if (hasFP(MF)) { 2076ea637afSDerek Schuff // Unlike most conventional targets (where FP points to the saved FP), 2086ea637afSDerek Schuff // FP points to the bottom of the fixed-size locals, so we can use positive 2096ea637afSDerek Schuff // offsets in load/store instructions. 2100cfb5f85SDan Gohman BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), 2116ea637afSDerek Schuff WebAssembly::FP32) 2126ea637afSDerek Schuff .addReg(WebAssembly::SP32); 2136ea637afSDerek Schuff } 214941a705bSMatthias Braun if (StackSize && needsSPWriteback(MF, MFI)) { 215d4207ba0SDerek Schuff writeSPToMemory(WebAssembly::SP32, MF, MBB, InsertPt, InsertPt, DL); 2166ea637afSDerek Schuff } 2178bb5f292SDerek Schuff } 2188bb5f292SDerek Schuff 2199769debfSDerek Schuff void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, 2209769debfSDerek Schuff MachineBasicBlock &MBB) const { 221941a705bSMatthias Braun auto &MFI = MF.getFrameInfo(); 222941a705bSMatthias Braun uint64_t StackSize = MFI.getStackSize(); 223941a705bSMatthias Braun if (!needsSP(MF, MFI) || !needsSPWriteback(MF, MFI)) return; 2243196650bSDan Gohman const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 2259769debfSDerek Schuff auto &MRI = MF.getRegInfo(); 2269769debfSDerek Schuff auto InsertPt = MBB.getFirstTerminator(); 2279769debfSDerek Schuff DebugLoc DL; 2289769debfSDerek Schuff 2290cfb5f85SDan Gohman if (InsertPt != MBB.end()) 2309769debfSDerek Schuff DL = InsertPt->getDebugLoc(); 231450a8075SDan Gohman 2326ea637afSDerek Schuff // Restore the stack pointer. If we had fixed-size locals, add the offset 2336ea637afSDerek Schuff // subtracted in the prolog. 234d4207ba0SDerek Schuff unsigned SPReg = 0; 235d4207ba0SDerek Schuff MachineBasicBlock::iterator InsertAddr = InsertPt; 236*0d41b7b3SDerek Schuff if (hasBP(MF)) { 237*0d41b7b3SDerek Schuff auto FI = MF.getInfo<WebAssemblyFunctionInfo>(); 238*0d41b7b3SDerek Schuff SPReg = FI->getBasePointerVreg(); 239*0d41b7b3SDerek Schuff } else if (StackSize) { 2400cfb5f85SDan Gohman const TargetRegisterClass *PtrRC = 2410cfb5f85SDan Gohman MRI.getTargetRegisterInfo()->getPointerRegClass(MF); 2420cfb5f85SDan Gohman unsigned OffsetReg = MRI.createVirtualRegister(PtrRC); 243d4207ba0SDerek Schuff InsertAddr = 2449769debfSDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) 2459769debfSDerek Schuff .addImm(StackSize); 246d4207ba0SDerek Schuff // In the epilog we don't need to write the result back to the SP32 physreg 247d4207ba0SDerek Schuff // because it won't be used again. We can use a stackified register instead. 2480cfb5f85SDan Gohman SPReg = MRI.createVirtualRegister(PtrRC); 249d4207ba0SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), SPReg) 2506ea637afSDerek Schuff .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32) 2519769debfSDerek Schuff .addReg(OffsetReg); 252d4207ba0SDerek Schuff } else { 253d4207ba0SDerek Schuff SPReg = hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32; 2546ea637afSDerek Schuff } 2556ea637afSDerek Schuff 256d4207ba0SDerek Schuff writeSPToMemory(SPReg, MF, MBB, InsertAddr, InsertPt, DL); 25710e730a2SDan Gohman } 258