diff options
author | Derek Schuff <dschuff@google.com> | 2015-12-16 23:21:30 +0000 |
---|---|---|
committer | Derek Schuff <dschuff@google.com> | 2015-12-16 23:21:30 +0000 |
commit | 8bb5f2927a36d1ec58b5fa090095ed0abfa5d1c6 (patch) | |
tree | e483943c93115cc76b03307adac8e5b4312d3d37 | |
parent | 433049f87b711db1adedac3fc35f6f894ede79ed (diff) | |
download | bcm5719-llvm-8bb5f2927a36d1ec58b5fa090095ed0abfa5d1c6.tar.gz bcm5719-llvm-8bb5f2927a36d1ec58b5fa090095ed0abfa5d1c6.zip |
[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
llvm-svn: 255844
8 files changed, 71 insertions, 37 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 8b0f48f4bd1..0eefd57f1f2 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/llvm/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<const WebAssemblyInstrInfo*>(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/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 597d6f4fd1d..2364366f3f5 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/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/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td index e9cad01f9df..cfa1519e6d9 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/llvm/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<WebAssemblyRegClass vt, string prefix> { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp index 3b219f4a901..41c8811ea76 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/llvm/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/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 0b04a6355a9..3a58826bd76 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/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/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index dcc393db6ea..c33c21fe685 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/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/llvm/test/CodeGen/WebAssembly/userstack.ll b/llvm/test/CodeGen/WebAssembly/userstack.ll index 855eaa00a4a..6e01e36cf9f 100644 --- a/llvm/test/CodeGen/WebAssembly/userstack.ll +++ b/llvm/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/llvm/test/CodeGen/WebAssembly/varargs.ll b/llvm/test/CodeGen/WebAssembly/varargs.ll index 10846f2a989..c564d942074 100644 --- a/llvm/test/CodeGen/WebAssembly/varargs.ll +++ b/llvm/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*) |