diff options
author | Derek Schuff <dschuff@google.com> | 2016-01-29 18:37:49 +0000 |
---|---|---|
committer | Derek Schuff <dschuff@google.com> | 2016-01-29 18:37:49 +0000 |
commit | 6ea637af35c992cb3bece3e3e9e8de9cc42b8cd1 (patch) | |
tree | 611323b1eb845f348b851842c19d6ed0f16f709c | |
parent | 0df98ff9132a250aaf4b96accd1173ebe2f30ee5 (diff) | |
download | bcm5719-llvm-6ea637af35c992cb3bece3e3e9e8de9cc42b8cd1.tar.gz bcm5719-llvm-6ea637af35c992cb3bece3e3e9e8de9cc42b8cd1.zip |
[WebAssembly] Support frame pointer
Add support for frame pointer use in prolog/epilog.
Supports dynamic allocas but not yet over-aligned locals.
Target-independend CG generates SP updates, but we still need to write
back the SP value to memory when necessary.
llvm-svn: 259220
4 files changed, 112 insertions, 20 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); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp index 00aca688af4..a1181c8a4a3 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -58,7 +58,7 @@ void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, const TargetRegisterClass *RC = TargetRegisterInfo::isVirtualRegister(DestReg) ? MRI.getRegClass(DestReg) - : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(SrcReg); + : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg); unsigned CopyLocalOpcode; if (RC == &WebAssembly::I32RegClass) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp index a76cb81b34f..f38f635d822 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp @@ -108,10 +108,15 @@ bool WebAssemblyRegNumbering::runOnMachineFunction(MachineFunction &MF) { } } // Allocate locals for used physical registers - if (FrameInfo.getStackSize() > 0) { + if (FrameInfo.getStackSize() > 0 || FrameInfo.adjustsStack()) { DEBUG(dbgs() << "PReg SP " << CurReg << "\n"); MFI.addPReg(WebAssembly::SP32, CurReg++); } + bool HasFP = MF.getSubtarget().getFrameLowering()->hasFP(MF); + if (HasFP) { + DEBUG(dbgs() << "PReg FP " << CurReg << "\n"); + MFI.addPReg(WebAssembly::FP32, CurReg++); + } return true; } diff --git a/llvm/test/CodeGen/WebAssembly/userstack.ll b/llvm/test/CodeGen/WebAssembly/userstack.ll index 72160cd9b20..4da1324260a 100644 --- a/llvm/test/CodeGen/WebAssembly/userstack.ll +++ b/llvm/test/CodeGen/WebAssembly/userstack.ll @@ -119,9 +119,36 @@ define void @allocarray_inbounds() { ; CHECK-LABEL: dynamic_alloca: define void @dynamic_alloca(i32 %alloc) { - ; TODO: Support frame pointers - ;%r = alloca i32, i32 %alloc - ;store i32 0, i32* %r + ; CHECK: i32.const [[L0:.+]]=, __stack_pointer + ; CHECK-NEXT: i32.load [[SP:.+]]=, 0([[L0]]) + ; CHECK-NEXT: copy_local [[FP:.+]]=, [[SP]] + ; Target independent codegen bumps the stack pointer + ; FIXME: we need to write the value back to memory + %r = alloca i32, i32 %alloc + ; Target-independent codegen also calculates the store addr + store i32 0, i32* %r + ; CHECK: i32.const [[L3:.+]]=, __stack_pointer + ; CHECK-NEXT: i32.store [[SP]]=, 0([[L3]]), [[FP]] + ret void +} + + +; CHECK-LABEL: dynamic_static_alloca: +define void @dynamic_static_alloca(i32 %alloc) { + ; CHECK: i32.const [[L0:.+]]=, __stack_pointer + ; CHECK-NEXT: i32.load [[L0]]=, 0([[L0]]) + ; CHECK-NEXT: i32.const [[L2:.+]]=, 16 + ; CHECK-NEXT: i32.sub [[SP:.+]]=, [[L0]], [[L2]] + ; CHECK-NEXT: copy_local [[FP:.+]]=, [[SP]] + ; CHECK-NEXT: i32.const [[L3:.+]]=, __stack_pointer + ; CHECK-NEXT: i32.store {{.*}}=, 0([[L3]]), [[SP]] + %r1 = alloca i32 + %r = alloca i32, i32 %alloc + store i32 0, i32* %r + ; CHECK: i32.const [[L3:.+]]=, 16 + ; CHECK: i32.add [[SP]]=, [[FP]], [[L3]] + ; CHECK: i32.const [[L4:.+]]=, __stack_pointer + ; CHECK-NEXT: i32.store [[SP]]=, 0([[L4]]), [[SP]] ret void } ; TODO: test aligned alloc |