Index: lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -61,31 +61,16 @@ return !MF.getFrameInfo()->hasVarSizedObjects(); } -void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( - MachineFunction & /*MF*/, MachineBasicBlock & /*MBB*/, - MachineBasicBlock::iterator /*I*/) const { - llvm_unreachable("TODO: implement eliminateCallFramePseudoInstr"); -} -void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, - MachineBasicBlock &MBB) const { - // 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(); +/// Adjust the stack pointer by a constant amount. +void adjustStackPointer(unsigned StackSize, + bool AdjustUp, + MachineFunction& MF, + MachineBasicBlock& MBB, + const TargetInstrInfo* TII, + MachineBasicBlock::iterator InsertPt, + const DebugLoc& DL) { 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) @@ -100,11 +85,13 @@ .addImm(0) .addReg(SPReg) .addMemOperand(LoadMMO); - // Subtract the frame size + // Add/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) + BuildMI(MBB, InsertPt, DL, + TII->get(AdjustUp ? WebAssembly::ADD_I32 : WebAssembly::SUB_I32), + WebAssembly::SP32) .addReg(SPReg) .addReg(OffsetReg); // The SP32 register now has the new stacktop. Also write it back to memory. @@ -119,6 +106,40 @@ .addMemOperand(MMO); } +void WebAssemblyFrameLowering::eliminateCallFramePseudoInstr( + MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + const auto *TII = + static_cast(MF.getSubtarget().getInstrInfo()); + DebugLoc DL = I->getDebugLoc(); + unsigned Opc = I->getOpcode(); + bool IsDestroy = Opc == TII->getCallFrameDestroyOpcode(); + unsigned Amount = I->getOperand(0).getImm(); + if (Amount) + adjustStackPointer(Amount, IsDestroy, MF, MBB, + TII, I, DL); + MBB.erase(I); +} + +void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + // 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"); + uint64_t StackSize = MFI->getStackSize(); + if (!StackSize && (!MFI->adjustsStack() || MFI->getMaxCallFrameSize() == 0)) + return; + + const auto *TII = MF.getSubtarget().getInstrInfo(); + + auto InsertPt = MBB.begin(); + DebugLoc DL; + + adjustStackPointer(StackSize, false, MF, MBB, TII, InsertPt, DL); +} + void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { uint64_t StackSize = MF.getFrameInfo()->getStackSize(); Index: lib/Target/WebAssembly/WebAssemblyInstrCall.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -21,8 +21,8 @@ let Uses = [SP32, SP64], Defs = [SP32, SP64], isCodeGenOnly = 1 in { def ADJCALLSTACKDOWN : I<(outs), (ins i32imm:$amt), [(WebAssemblycallseq_start timm:$amt)]>; -def ADJCALLSTACKUP : I<(outs), (ins i32imm:$amt), - [(WebAssemblycallseq_end timm:$amt, undef)]>; +def ADJCALLSTACKUP : I<(outs), (ins i32imm:$amt, i32imm:$amt2), + [(WebAssemblycallseq_end timm:$amt, timm:$amt2)]>; } // isCodeGenOnly = 1 multiclass CALL { @@ -49,6 +49,10 @@ } // Defs = [ARGUMENTS] +def : Pat<(WebAssemblycallseq_end timm:$amt, undef), + (ADJCALLSTACKUP i32imm:$amt, 0)>; + + // Patterns for matching a direct call to a global address. def : Pat<(i32 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))), (CALL_I32 tglobaladdr:$callee)>; Index: lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -36,8 +36,12 @@ MachineBasicBlock::iterator I, DebugLoc DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const { - const TargetRegisterClass *RC = - MBB.getParent()->getRegInfo().getRegClass(SrcReg); + // This method is called by post-RA expansion, which expects only pregs to + // exist. However we need to handle both here. + auto &MRI = MBB.getParent()->getRegInfo(); + const TargetRegisterClass *RC = TargetRegisterInfo::isVirtualRegister(DestReg) ? + MRI.getRegClass(DestReg) : + MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(SrcReg); unsigned CopyLocalOpcode; if (RC == &WebAssembly::I32RegClass) Index: lib/Target/WebAssembly/WebAssemblyRegStackify.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -136,7 +136,6 @@ for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : reverse(MBB)) { MachineInstr *Insert = &MI; - // Don't nest anything inside a phi. if (Insert->getOpcode() == TargetOpcode::PHI) break; Index: lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -101,6 +101,7 @@ FunctionPass *createTargetRegisterAllocator(bool) override; + void addIRPasses() override; bool addInstSelector() override; bool addILPOpts() override; @@ -125,6 +126,8 @@ return nullptr; // No reg alloc } + + //===----------------------------------------------------------------------===// // The following functions are called from lib/CodeGen/Passes.cpp to modify // the CodeGen pass sequence. @@ -169,6 +172,9 @@ // Mark registers as representing wasm's expression stack. addPass(createWebAssemblyRegStackify()); + // The register coalescing pass has a bad interaction with COPY MIs which have + // EXPR_STACK as an extra operand + //disablePass(&RegisterCoalescerID); } void WebAssemblyPassConfig::addPostRegAlloc() { Index: test/CodeGen/WebAssembly/userstack.ll =================================================================== --- test/CodeGen/WebAssembly/userstack.ll +++ test/CodeGen/WebAssembly/userstack.ll @@ -72,4 +72,9 @@ ret void } +define void @dynamic_alloca(i32 %alloc) { + %r = alloca i32, i32 %alloc + store i32 0, i32* %r + ret void +} ; TODO: test aligned alloc Index: test/CodeGen/WebAssembly/varargs.ll =================================================================== --- test/CodeGen/WebAssembly/varargs.ll +++ test/CodeGen/WebAssembly/varargs.ll @@ -110,12 +110,11 @@ ret void } -; TODO: Test a varargs call with actual arguments. - -;define void @caller_some() { -; call void (...) @callee(i32 0, double 2.0) -; ret void -;} +; CHECK-LABEL: caller_some +define void @caller_some() { + call void (...) @callee(i32 0, double 2.0) + ret void +} declare void @llvm.va_start(i8*) declare void @llvm.va_end(i8*)