Index: lib/CodeGen/PrologEpilogInserter.cpp =================================================================== --- lib/CodeGen/PrologEpilogInserter.cpp +++ lib/CodeGen/PrologEpilogInserter.cpp @@ -168,7 +168,7 @@ const TargetRegisterInfo *TRI = Fn.getSubtarget().getRegisterInfo(); const TargetFrameLowering *TFI = Fn.getSubtarget().getFrameLowering(); - assert(!Fn.getRegInfo().getNumVirtRegs() && "Regalloc must assign all vregs"); + //assert(!Fn.getRegInfo().getNumVirtRegs() && "Regalloc must assign all vregs"); RS = TRI->requiresRegisterScavenging(Fn) ? new RegScavenger() : nullptr; FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(Fn); @@ -216,11 +216,11 @@ // If register scavenging is needed, as we've enabled doing it as a // post-pass, scavenge the virtual registers that frame index elimination // inserted. - if (TRI->requiresRegisterScavenging(Fn) && FrameIndexVirtualScavenging) + if (TRI->requiresRegisterScavenging(Fn) && FrameIndexVirtualScavenging) { scavengeFrameVirtualRegs(Fn); - - // Clear any vregs created by virtual scavenging. - Fn.getRegInfo().clearVirtRegs(); + // Clear any vregs created by virtual scavenging. + Fn.getRegInfo().clearVirtRegs(); + } // Warn on stack size when we exceeds the given limit. MachineFrameInfo *MFI = Fn.getFrameInfo(); Index: lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -35,6 +35,8 @@ #define DEBUG_TYPE "wasm-frame-info" // TODO: Implement a red zone? +// TODO: wasm64 +// TODO: Prolog/epilog should be stackified too. /// Return true if the specified function should have a dedicated frame pointer /// register. @@ -63,12 +65,43 @@ llvm_unreachable("TODO: implement eliminateCallFramePseudoInstr"); } -void WebAssemblyFrameLowering::emitPrologue(MachineFunction & /*MF*/, - MachineBasicBlock & /*MBB*/) const { - llvm_unreachable("TODO: implement emitPrologue"); +void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + uint64_t StackSize = MF.getFrameInfo()->getStackSize(); + if (!StackSize) + return; + const auto *TII = MF.getSubtarget().getInstrInfo(); + auto &MRI = MF.getRegInfo(); + auto InsertPt = MBB.begin(); + DebugLoc DL; + + 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(WebAssembly::SP32) + .addReg(OffsetReg); } -void WebAssemblyFrameLowering::emitEpilogue(MachineFunction & /*MF*/, - MachineBasicBlock & /*MBB*/) const { - llvm_unreachable("TODO: implement emitEpilogue"); +void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + 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(); + } + + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg) + .addImm(StackSize); + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), + WebAssembly::SP32) + .addReg(WebAssembly::SP32) + .addReg(OffsetReg); } Index: lib/Target/WebAssembly/WebAssemblyISelLowering.h =================================================================== --- lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -73,6 +73,7 @@ // Custom lowering hooks. SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + SDValue LowerFrameIndex(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const; Index: lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -167,6 +167,8 @@ setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand); + setOperationAction(ISD::FrameIndex, MVT::i32, Custom); + // Expand these forms; we pattern-match the forms that we can handle in isel. for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) for (auto Op : {ISD::BR_CC, ISD::SELECT_CC}) @@ -509,6 +511,8 @@ default: llvm_unreachable("unimplemented operation lowering"); return SDValue(); + case ISD::FrameIndex: + return LowerFrameIndex(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::ExternalSymbol: @@ -522,6 +526,12 @@ } } +SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op, + SelectionDAG &DAG) const { + int FI = cast(Op)->getIndex(); + return DAG.getTargetFrameIndex(FI, Op.getValueType()); +} + SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); Index: lib/Target/WebAssembly/WebAssemblyMCInstLower.h =================================================================== --- lib/Target/WebAssembly/WebAssemblyMCInstLower.h +++ lib/Target/WebAssembly/WebAssemblyMCInstLower.h @@ -42,6 +42,7 @@ void Lower(const MachineInstr *MI, MCInst &OutMI) const; MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + MCOperand LowerSPOperand() const; MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; Index: lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -15,6 +15,7 @@ #include "WebAssemblyMCInstLower.h" #include "WebAssemblyMachineFunctionInfo.h" +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "llvm/ADT/SmallString.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineFunction.h" @@ -53,6 +54,11 @@ return MCOperand::createExpr(Expr); } +MCOperand WebAssemblyMCInstLower::LowerSPOperand() const { + return MCOperand::createExpr( + MCSymbolRefExpr::create(Printer.GetExternalSymbolSymbol("SP"), Ctx)); +} + void WebAssemblyMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { OutMI.setOpcode(MI->getOpcode()); @@ -69,6 +75,10 @@ // Ignore all implicit register operands. if (MO.isImplicit()) continue; + if (MO.getReg() == WebAssembly::SP32) { + MCOp = LowerSPOperand(); + break; + } const WebAssemblyFunctionInfo &MFI = *MI->getParent()->getParent()->getInfo(); unsigned WAReg = MFI.getWAReg(MO.getReg()); Index: lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp +++ lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp @@ -52,10 +52,21 @@ } void WebAssemblyRegisterInfo::eliminateFrameIndex( - MachineBasicBlock::iterator /*II*/, int /*SPAdj*/, - unsigned /*FIOperandNum*/, RegScavenger * /*RS*/) const { - llvm_unreachable( - "TODO: implement WebAssemblyRegisterInfo::eliminateFrameIndex"); + MachineBasicBlock::iterator II, int SPAdj, + unsigned FIOperandNum, RegScavenger * /*RS*/) const { + assert(SPAdj == 0); + MachineInstr &MI = *II; + assert(MI.getOperand(1).getImm() == 0 && + "Can't eliminate FI yet if offset is already set"); + + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + const MachineFrameInfo& MFI = *MF.getFrameInfo(); + int Offset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex); + + MI.getOperand(1).setImm(Offset); + MI.getOperand(2).ChangeToRegister(WebAssembly::SP32, /*IsDef=*/false); } unsigned Index: lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -172,8 +172,6 @@ // virtual registers. Consider removing their restrictions and re-enabling // them. // - // Fails with: Regalloc must assign all vregs. - disablePass(&PrologEpilogCodeInserterID); // Fails with: should be run after register allocation. disablePass(&MachineCopyPropagationID); Index: test/CodeGen/WebAssembly/userstack.ll =================================================================== --- /dev/null +++ test/CodeGen/WebAssembly/userstack.ll @@ -0,0 +1,34 @@ +; RUN: llc < %s -asm-verbose=false | FileCheck %s +; RUN: llc < %s -asm-verbose=false -fast-isel | FileCheck %s + + +target datalayout = "e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + + +; CHECK-LABEL: foo: +define void @foo() { + ; CHECK: i32.const [[VREG:.+]]=, 16 + ; CHECK-NEXT: i32.sub SP, SP, [[VREG]] + %retval = alloca i32 + ; CHECK: i32.store {{.*}}=, 12(SP), $pop + store i32 0, i32* %retval + ; CHECK: i32.const [[VR2:.+]]=, 16 + ; CHECK-NEXT: i32.add SP, SP, [[VR2]] + ret void +} + +; CHECK-LABEL: bar: +define void @bar() { + ; CHECK: i32.const [[VREG:.+]]=, 16 + ; CHECK-NEXT: i32.sub SP, SP, [[VREG]] + %r1 = alloca i32 + %r2 = alloca double + ; CHECK: i32.store {{.+}}=, 12(SP), $pop + store i32 0, i32* %r1 + ; CHECK: i64.store {{.+}}=, 0(SP), $pop + store double 0.0, double* %r2 + ; CHECK: i32.const [[VR2:.+]]=, 16 + ; CHECK-NEXT: i32.add SP, SP, [[VR2]] + ret void +} \ No newline at end of file