From: Derek Schuff Date: Wed, 16 Dec 2015 23:21:30 +0000 (+0000) Subject: [WebAssembly] Implement eliminateCallFramePseudo X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=6b90fe4207bcd41cd7527fec66235c6c7c8cbc07;p=oota-llvm.git [WebAssembly] Implement eliminateCallFramePseudo Summary: Implement eliminateCallFramePsuedo to handle ADJCALLSTACKUP/DOWN pseudo-instructions. Add a test calling a vararg function which causes non-0 adjustments. This revealed an issue with RegisterCoalescer wherein it eliminates a COPY from SP32 to a vreg but failes to update the live ranges of EXPR_STACK, causing a machineinstr verifier failure (so this test is commented out). Also add a dynamic alloca test, which causes a callseq_end dag node with a 0 (instead of undef) second argument to be generated. We currently fail to select that, so adjust the ADJCALLSTACKUP tablegen code to handle it. Differential Revision: http://reviews.llvm.org/D15587 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255844 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 8b0f48f4bd1..0eefd57f1f2 100644 --- a/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -61,31 +61,16 @@ bool WebAssemblyFrameLowering::hasReservedCallFrame( 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. +static 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 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, .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 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, .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(); diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 597d6f4fd1d..2364366f3f5 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -445,7 +445,7 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI, } if (NumBytes) { - SDValue Unused = DAG.getUNDEF(PtrVT); + SDValue Unused = DAG.getTargetConstant(0, DL, PtrVT); Chain = DAG.getCALLSEQ_END(Chain, NB, Unused, SDValue(), DL); } diff --git a/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/lib/Target/WebAssembly/WebAssemblyInstrCall.td index e9cad01f9df..cfa1519e6d9 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -21,8 +21,8 @@ let Defs = [ARGUMENTS] in { 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 { diff --git a/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp index 3b219f4a901..41c8811ea76 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -36,8 +36,12 @@ void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 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) diff --git a/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 0b04a6355a9..3a58826bd76 100644 --- a/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -136,7 +136,6 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 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; diff --git a/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index dcc393db6ea..c33c21fe685 100644 --- a/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -169,6 +169,9 @@ void WebAssemblyPassConfig::addPreRegAlloc() { // 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() { diff --git a/test/CodeGen/WebAssembly/userstack.ll b/test/CodeGen/WebAssembly/userstack.ll index 855eaa00a4a..6e01e36cf9f 100644 --- a/test/CodeGen/WebAssembly/userstack.ll +++ b/test/CodeGen/WebAssembly/userstack.ll @@ -72,4 +72,10 @@ define void @allocarray() { ret void } +define void @dynamic_alloca(i32 %alloc) { + ; TODO: Support frame pointers + ;%r = alloca i32, i32 %alloc + ;store i32 0, i32* %r + ret void +} ; TODO: test aligned alloc diff --git a/test/CodeGen/WebAssembly/varargs.ll b/test/CodeGen/WebAssembly/varargs.ll index 10846f2a989..c564d942074 100644 --- a/test/CodeGen/WebAssembly/varargs.ll +++ b/test/CodeGen/WebAssembly/varargs.ll @@ -110,12 +110,13 @@ define void @caller_none() { 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() { + ; TODO: Fix interaction between register coalescer and reg stackifier, + ; or disable coalescer. + ;call void (...) @callee(i32 0, double 2.0) + ret void +} declare void @llvm.va_start(i8*) declare void @llvm.va_end(i8*)