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 3710e730a2SDan Gohman // TODO: Implement a red zone? 389769debfSDerek Schuff // TODO: wasm64 399769debfSDerek Schuff // TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions 4010e730a2SDan Gohman 4110e730a2SDan Gohman /// Return true if the specified function should have a dedicated frame pointer 4210e730a2SDan Gohman /// register. 4310e730a2SDan Gohman bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const { 44b9073fb2SJF Bastien const MachineFrameInfo *MFI = MF.getFrameInfo(); 45e419a7c3SDan Gohman const auto *RegInfo = 46e419a7c3SDan Gohman MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 4794c65660SDan Gohman return MFI->isFrameAddressTaken() || MFI->hasVarSizedObjects() || 4894c65660SDan Gohman MFI->hasStackMap() || MFI->hasPatchPoint() || 4994c65660SDan Gohman RegInfo->needsStackRealignment(MF); 5010e730a2SDan Gohman } 5110e730a2SDan Gohman 5210e730a2SDan Gohman /// Under normal circumstances, when a frame pointer is not required, we reserve 5310e730a2SDan Gohman /// argument space for call sites in the function immediately on entry to the 5410e730a2SDan Gohman /// current function. This eliminates the need for add/sub sp brackets around 5510e730a2SDan Gohman /// call sites. Returns true if the call frame is included as part of the stack 5610e730a2SDan Gohman /// frame. 5710e730a2SDan Gohman bool WebAssemblyFrameLowering::hasReservedCallFrame( 5810e730a2SDan Gohman const MachineFunction &MF) const { 5910e730a2SDan Gohman return !MF.getFrameInfo()->hasVarSizedObjects(); 6010e730a2SDan Gohman } 6110e730a2SDan Gohman 628bb5f292SDerek Schuff void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( 638bb5f292SDerek Schuff MachineFunction &MF, MachineBasicBlock &MBB, 648bb5f292SDerek Schuff MachineBasicBlock::iterator I) const { 6527501e20SDerek Schuff // TODO: can we avoid using call frame pseudos altogether? 6627501e20SDerek Schuff assert(!I->getOperand(0).getImm() && 6727501e20SDerek Schuff "Stack should not be adjusted around calls"); 688bb5f292SDerek Schuff MBB.erase(I); 698bb5f292SDerek Schuff } 708bb5f292SDerek Schuff 718bb5f292SDerek Schuff void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, 728bb5f292SDerek Schuff MachineBasicBlock &MBB) const { 738bb5f292SDerek Schuff // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions 748bb5f292SDerek Schuff auto *MFI = MF.getFrameInfo(); 758bb5f292SDerek Schuff assert(MFI->getCalleeSavedInfo().empty() && 768bb5f292SDerek Schuff "WebAssembly should not have callee-saved registers"); 77*dc5f6aa4SDerek Schuff auto *WFI = MF.getInfo<WebAssemblyFunctionInfo>(); 786ea637afSDerek Schuff 798bb5f292SDerek Schuff uint64_t StackSize = MFI->getStackSize(); 8027501e20SDerek Schuff if (!StackSize && !MFI->adjustsStack() && !hasFP(MF)) return; 818bb5f292SDerek Schuff 823196650bSDan Gohman const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 836ea637afSDerek Schuff auto &MRI = MF.getRegInfo(); 848bb5f292SDerek Schuff 858bb5f292SDerek Schuff auto InsertPt = MBB.begin(); 868bb5f292SDerek Schuff DebugLoc DL; 878bb5f292SDerek Schuff 88*dc5f6aa4SDerek Schuff unsigned SPAddr = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 896ea637afSDerek Schuff unsigned SPReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 906ea637afSDerek Schuff auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer"); 91*dc5f6aa4SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr) 926ea637afSDerek Schuff .addExternalSymbol(SPSymbol); 936ea637afSDerek Schuff // This MachinePointerInfo should reference __stack_pointer as well but 946ea637afSDerek Schuff // doesn't because MachinePointerInfo() takes a GV which we don't have for 956ea637afSDerek Schuff // __stack_pointer. TODO: check if PseudoSourceValue::ExternalSymbolCallEntry 966ea637afSDerek Schuff // is appropriate instead. (likewise for EmitEpologue below) 976ea637afSDerek Schuff auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(), 986ea637afSDerek Schuff MachineMemOperand::MOLoad, 4, 4); 996ea637afSDerek Schuff // Load the SP value. 1006ea637afSDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), 1013ca3ea69SJF Bastien StackSize ? SPReg : (unsigned)WebAssembly::SP32) 1026ea637afSDerek Schuff .addImm(0) // offset 103*dc5f6aa4SDerek Schuff .addReg(SPAddr) // addr 1046ea637afSDerek Schuff .addImm(2) // p2align 1056ea637afSDerek Schuff .addMemOperand(LoadMMO); 106*dc5f6aa4SDerek Schuff WFI->stackifyVReg(SPAddr); 1076ea637afSDerek Schuff 1086ea637afSDerek Schuff if (StackSize) { 1096ea637afSDerek Schuff // Subtract the frame size 110*dc5f6aa4SDerek Schuff unsigned OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 1116ea637afSDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) 1126ea637afSDerek Schuff .addImm(StackSize); 1133f063295SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32), 1146ea637afSDerek Schuff WebAssembly::SP32) 1156ea637afSDerek Schuff .addReg(SPReg) 1166ea637afSDerek Schuff .addReg(OffsetReg); 117*dc5f6aa4SDerek Schuff WFI->stackifyVReg(OffsetReg); 118*dc5f6aa4SDerek Schuff WFI->stackifyVReg(SPReg); 1196ea637afSDerek Schuff } 1206ea637afSDerek Schuff if (hasFP(MF)) { 1216ea637afSDerek Schuff // Unlike most conventional targets (where FP points to the saved FP), 1226ea637afSDerek Schuff // FP points to the bottom of the fixed-size locals, so we can use positive 1236ea637afSDerek Schuff // offsets in load/store instructions. 1246ea637afSDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY_LOCAL_I32), 1256ea637afSDerek Schuff WebAssembly::FP32) 1266ea637afSDerek Schuff .addReg(WebAssembly::SP32); 1276ea637afSDerek Schuff } 1286ea637afSDerek Schuff if (StackSize) { 129*dc5f6aa4SDerek Schuff SPAddr = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 1306ea637afSDerek Schuff // The SP32 register now has the new stacktop. Also write it back to memory. 131*dc5f6aa4SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr) 1326ea637afSDerek Schuff .addExternalSymbol(SPSymbol); 1336ea637afSDerek Schuff auto *MMO = new MachineMemOperand(MachinePointerInfo(), 1346ea637afSDerek Schuff MachineMemOperand::MOStore, 4, 4); 1353f063295SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), 1363f063295SDerek Schuff WebAssembly::SP32) 1376ea637afSDerek Schuff .addImm(0) 138*dc5f6aa4SDerek Schuff .addReg(SPAddr) 1396ea637afSDerek Schuff .addImm(2) // p2align 1406ea637afSDerek Schuff .addReg(WebAssembly::SP32) 1416ea637afSDerek Schuff .addMemOperand(MMO); 142*dc5f6aa4SDerek Schuff WFI->stackifyVReg(SPAddr); 1436ea637afSDerek Schuff } 1448bb5f292SDerek Schuff } 1458bb5f292SDerek Schuff 1469769debfSDerek Schuff void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, 1479769debfSDerek Schuff MachineBasicBlock &MBB) const { 1486ea637afSDerek Schuff auto *MFI = MF.getFrameInfo(); 1496ea637afSDerek Schuff uint64_t StackSize = MFI->getStackSize(); 15027501e20SDerek Schuff if (!StackSize && !MFI->adjustsStack() && !hasFP(MF)) return; 151*dc5f6aa4SDerek Schuff auto *WFI = MF.getInfo<WebAssemblyFunctionInfo>(); 1523196650bSDan Gohman const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1539769debfSDerek Schuff auto &MRI = MF.getRegInfo(); 1549769debfSDerek Schuff auto InsertPt = MBB.getFirstTerminator(); 1559769debfSDerek Schuff DebugLoc DL; 1569769debfSDerek Schuff 1579769debfSDerek Schuff if (InsertPt != MBB.end()) { 1589769debfSDerek Schuff DL = InsertPt->getDebugLoc(); 1599769debfSDerek Schuff } 1609769debfSDerek Schuff 1616ea637afSDerek Schuff // Restore the stack pointer. If we had fixed-size locals, add the offset 1626ea637afSDerek Schuff // subtracted in the prolog. 1636ea637afSDerek Schuff if (StackSize) { 164*dc5f6aa4SDerek Schuff unsigned OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 1659769debfSDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) 1669769debfSDerek Schuff .addImm(StackSize); 1673f063295SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), 1683f063295SDerek Schuff WebAssembly::SP32) 1696ea637afSDerek Schuff .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32) 1709769debfSDerek Schuff .addReg(OffsetReg); 171*dc5f6aa4SDerek Schuff WFI->stackifyVReg(OffsetReg); 1726ea637afSDerek Schuff } 1736ea637afSDerek Schuff 1746ea637afSDerek Schuff auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer"); 175*dc5f6aa4SDerek Schuff unsigned SPAddr = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 176*dc5f6aa4SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPAddr) 1779769debfSDerek Schuff .addExternalSymbol(SPSymbol); 1789769debfSDerek Schuff auto *MMO = new MachineMemOperand(MachinePointerInfo(), 1799769debfSDerek Schuff MachineMemOperand::MOStore, 4, 4); 1803f063295SDerek Schuff BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), 1813f063295SDerek Schuff WebAssembly::SP32) 1829769debfSDerek Schuff .addImm(0) 183*dc5f6aa4SDerek Schuff .addReg(SPAddr) 184bb372243SDan Gohman .addImm(2) // p2align 1856ea637afSDerek Schuff .addReg((!StackSize && hasFP(MF)) ? WebAssembly::FP32 : WebAssembly::SP32) 1869769debfSDerek Schuff .addMemOperand(MMO); 187*dc5f6aa4SDerek Schuff WFI->stackifyVReg(SPAddr); 18810e730a2SDan Gohman } 189