diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp')
-rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp | 90 |
1 files changed, 75 insertions, 15 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 32d390de40a..2edcc3f8818 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -70,6 +70,7 @@ static void adjustStackPointer(unsigned StackSize, const TargetInstrInfo* TII, MachineBasicBlock::iterator InsertPt, const DebugLoc& DL) { + assert((StackSize || !AdjustUp) && "Adjusting up by 0"); auto &MRI = MF.getRegInfo(); unsigned SPReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer"); @@ -82,8 +83,8 @@ static void adjustStackPointer(unsigned StackSize, auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(), MachineMemOperand::MOLoad, 4, 4); BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg) - .addImm(0) - .addReg(SPReg) + .addImm(0) // offset + .addReg(SPReg) // addr .addImm(2) // p2align .addMemOperand(LoadMMO); // Add/Subtract the frame size @@ -116,6 +117,9 @@ void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( unsigned Opc = I->getOpcode(); bool IsDestroy = Opc == TII->getCallFrameDestroyOpcode(); unsigned Amount = I->getOperand(0).getImm(); + // TODO(dschuff): After we switch varargs to passing an explicit pointer + // rather than using an implicit call frame, assert here that Amount is 0 + // and remove adjustStackPointer altogether. if (Amount) adjustStackPointer(Amount, IsDestroy, MF, MBB, TII, I, DL); @@ -128,23 +132,76 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, 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"); + uint64_t StackSize = MFI->getStackSize(); - if (!StackSize && (!MFI->adjustsStack() || MFI->getMaxCallFrameSize() == 0)) + if (!StackSize && !MFI->adjustsStack()) return; const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); + auto &MRI = MF.getRegInfo(); auto InsertPt = MBB.begin(); DebugLoc DL; - adjustStackPointer(StackSize, false, MF, MBB, TII, InsertPt, DL); + 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); + // Load the SP value. + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), + StackSize ? SPReg : WebAssembly::SP32) + .addImm(0) // offset + .addReg(SPReg) // addr + .addImm(2) // p2align + .addMemOperand(LoadMMO); + + unsigned OffsetReg = 0; + if (StackSize) { + // Subtract the frame size + 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); + } + if (hasFP(MF)) { + // Unlike most conventional targets (where FP points to the saved FP), + // FP points to the bottom of the fixed-size locals, so we can use positive + // offsets in load/store instructions. + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY_LOCAL_I32), + WebAssembly::FP32) + .addReg(WebAssembly::SP32); + } + if (StackSize) { + assert(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) + .addImm(2) // p2align + .addReg(WebAssembly::SP32) + .addMemOperand(MMO); + } } void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { - uint64_t StackSize = MF.getFrameInfo()->getStackSize(); - if (!StackSize) + auto *MFI = MF.getFrameInfo(); + uint64_t StackSize = MFI->getStackSize(); + if (!StackSize && !MFI->adjustsStack()) return; const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); auto &MRI = MF.getRegInfo(); @@ -156,14 +213,17 @@ void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, DL = InsertPt->getDebugLoc(); } - // Restore the stack pointer. Without FP its value is just SP32 - stacksize - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) - .addImm(StackSize); + // Restore the stack pointer. If we had fixed-size locals, add the offset + // subtracted in the prolog. + if (StackSize) { + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) + .addImm(StackSize); + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), WebAssembly::SP32) + .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32) + .addReg(OffsetReg); + } + auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer"); - // TODO: Fold this add into the const offset field of the store. - 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); @@ -173,6 +233,6 @@ void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, .addImm(0) .addReg(OffsetReg) .addImm(2) // p2align - .addReg(WebAssembly::SP32) + .addReg((!StackSize && hasFP(MF)) ? WebAssembly::FP32 : WebAssembly::SP32) .addMemOperand(MMO); } |