#define DEBUG_TYPE "wasm-frame-info"
// TODO: Implement a red zone?
+// TODO: wasm64
+// TODO: Prolog/epilog should be stackified too. This pass runs after register
+// stackification, so we'll have to do it manually.
+// TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
/// Return true if the specified function should have a dedicated frame pointer
/// register.
bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
- llvm_unreachable("TODO: implement hasFP");
+ const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const auto *RegInfo =
+ MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
+ return MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken() ||
+ MFI->hasStackMap() || MFI->hasPatchPoint() ||
+ RegInfo->needsStackRealignment(MF);
}
/// Under normal circumstances, when a frame pointer is not required, we reserve
}
void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
- MachineFunction &MF, MachineBasicBlock &MBB,
- MachineBasicBlock::iterator I) const {
+ MachineFunction & /*MF*/, MachineBasicBlock & /*MBB*/,
+ MachineBasicBlock::iterator /*I*/) const {
llvm_unreachable("TODO: implement eliminateCallFramePseudoInstr");
}
void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
- llvm_unreachable("TODO: implement emitPrologue");
+ // TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
+ auto *MFI = MF.getFrameInfo();
+ assert(MFI->getCalleeSavedInfo().empty() &&
+ "WebAssembly should not have callee-saved registers");
+ assert(!hasFP(MF) && "Functions needing frame pointers not yet supported");
+ assert(!MFI->adjustsStack() && "Dynamic stack adjustmet not yet supported");
+ uint64_t StackSize = MFI->getStackSize();
+ if (!StackSize)
+ return;
+
+ const auto *TII = MF.getSubtarget().getInstrInfo();
+ auto &MRI = MF.getRegInfo();
+ auto InsertPt = MBB.begin();
+ DebugLoc DL;
+
+ // Get the current stacktop
+ // TODO: To support dynamic alloc, also copy to FP
+ unsigned SPReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
+ auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPReg)
+ .addExternalSymbol(SPSymbol);
+ // This MachinePointerInfo should reference __stack_pointer as well but
+ // doesn't because MachinePointerInfo() takes a GV which we don't have for
+ // __stack_pointer. TODO: check if PseudoSourceValue::ExternalSymbolCallEntry
+ // is appropriate instead. (likewise for EmitEpologue below)
+ auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(),
+ MachineMemOperand::MOLoad, 4, 4);
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg)
+ .addImm(0)
+ .addReg(SPReg)
+ .addMemOperand(LoadMMO);
+ // Subtract the frame size
+ unsigned OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
+ .addImm(StackSize);
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::SUB_I32), WebAssembly::SP32)
+ .addReg(SPReg)
+ .addReg(OffsetReg);
+ // The SP32 register now has the new stacktop. Also write it back to memory.
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
+ .addExternalSymbol(SPSymbol);
+ auto *MMO = new MachineMemOperand(MachinePointerInfo(),
+ MachineMemOperand::MOStore, 4, 4);
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), WebAssembly::SP32)
+ .addImm(0)
+ .addReg(OffsetReg)
+ .addReg(WebAssembly::SP32)
+ .addMemOperand(MMO);
}
void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
- llvm_unreachable("TODO: implement emitEpilogue");
-}
+ uint64_t StackSize = MF.getFrameInfo()->getStackSize();
+ if (!StackSize)
+ return;
+ const auto *TII = MF.getSubtarget().getInstrInfo();
+ auto &MRI = MF.getRegInfo();
+ unsigned OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
+ auto InsertPt = MBB.getFirstTerminator();
+ DebugLoc DL;
+
+ if (InsertPt != MBB.end()) {
+ DL = InsertPt->getDebugLoc();
+ }
-void WebAssemblyFrameLowering::determineCalleeSaves(MachineFunction &MF,
- BitVector &SavedRegs,
- RegScavenger *RS) const {
- llvm_unreachable("TODO: implement determineCalleeSaves");
+ // Restore the stack pointer. Without FP its value is just SP32 - stacksize
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
+ .addImm(StackSize);
+ auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), WebAssembly::SP32)
+ .addReg(WebAssembly::SP32)
+ .addReg(OffsetReg);
+ // Re-use OffsetReg to hold the address of the stacktop
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
+ .addExternalSymbol(SPSymbol);
+ auto *MMO = new MachineMemOperand(MachinePointerInfo(),
+ MachineMemOperand::MOStore, 4, 4);
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), WebAssembly::SP32)
+ .addImm(0)
+ .addReg(OffsetReg)
+ .addReg(WebAssembly::SP32)
+ .addMemOperand(MMO);
}