diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -361,13 +361,11 @@ raw_pwrite_stream *DwoOut, CodeGenFileType FileType, MCContext &Context); - /// True if the target uses physical regs (as nearly all targets do). False - /// for stack machines such as WebAssembly and other virtual-register - /// machines. If true, all vregs must be allocated before PEI. If false, then - /// callee-save register spilling and scavenging are not needed or used. If - /// false, implicitly defined registers will still be assumed to be physical - /// registers, except that variadic defs will be allocated vregs. - virtual bool usesPhysRegsForValues() const { return true; } + /// True if the target uses physical regs at Prolog/Epilog insertion + /// time. If true (most machines), all vregs must be allocated before + /// PEI. If false (virtual-register machines), then callee-save register + /// spilling and scavenging are not needed or used. + virtual bool usesPhysRegsForPEI() const { return true; } /// True if the target wants to use interprocedural register allocation by /// default. The -enable-ipra flag can be used to override this. diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -237,7 +237,7 @@ stashEntryDbgValues(*SaveBlock, EntryDbgValues); // Handle CSR spilling and restoring, for targets that need it. - if (MF.getTarget().usesPhysRegsForValues()) + if (MF.getTarget().usesPhysRegsForPEI()) spillCalleeSavedRegs(MF); // Allow the target machine to make final modifications to the function diff --git a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp --- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -195,10 +195,7 @@ "IMPLICIT_DEF should have been handled as a special case elsewhere!"); unsigned NumResults = CountResults(Node); - bool HasVRegVariadicDefs = !MF->getTarget().usesPhysRegsForValues() && - II.isVariadic() && II.variadicOpsAreDefs(); - unsigned NumVRegs = HasVRegVariadicDefs ? NumResults : II.getNumDefs(); - for (unsigned i = 0; i < NumVRegs; ++i) { + for (unsigned i = 0; i < II.getNumDefs(); ++i) { // If the specific node value is only used by a CopyToReg and the dest reg // is a vreg in the same register class, use the CopyToReg'd destination // register instead of creating a new vreg. @@ -219,7 +216,7 @@ RC = VTRC; } - if (II.OpInfo != nullptr && II.OpInfo[i].isOptionalDef()) { + if (II.OpInfo[i].isOptionalDef()) { // Optional def must be a physical register. VRBase = cast(Node->getOperand(i-NumResults))->getReg(); assert(Register::isPhysicalRegister(VRBase)); @@ -831,10 +828,7 @@ unsigned NumImpUses = 0; unsigned NodeOperands = countOperands(Node, II.getNumOperands() - NumDefs, NumImpUses); - bool HasVRegVariadicDefs = !MF->getTarget().usesPhysRegsForValues() && - II.isVariadic() && II.variadicOpsAreDefs(); - bool HasPhysRegOuts = NumResults > NumDefs && - II.getImplicitDefs() != nullptr && !HasVRegVariadicDefs; + bool HasPhysRegOuts = NumResults > NumDefs && II.getImplicitDefs()!=nullptr; #ifndef NDEBUG unsigned NumMIOperands = NodeOperands + NumResults; if (II.isVariadic()) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -509,8 +509,8 @@ /// Returns the operand number of a callee, assuming the argument is a call /// instruction. -inline const MachineOperand &getCalleeOp(const MachineInstr &MI) { - switch (MI.getOpcode()) { +inline unsigned getCalleeOpNo(unsigned Opc) { + switch (Opc) { case WebAssembly::CALL_VOID: case WebAssembly::CALL_VOID_S: case WebAssembly::CALL_INDIRECT_VOID: @@ -519,7 +519,7 @@ case WebAssembly::RET_CALL_S: case WebAssembly::RET_CALL_INDIRECT: case WebAssembly::RET_CALL_INDIRECT_S: - return MI.getOperand(0); + return 0; case WebAssembly::CALL_i32: case WebAssembly::CALL_i32_S: case WebAssembly::CALL_i64: @@ -564,10 +564,7 @@ case WebAssembly::CALL_INDIRECT_v2f64_S: case WebAssembly::CALL_INDIRECT_exnref: case WebAssembly::CALL_INDIRECT_exnref_S: - return MI.getOperand(1); - case WebAssembly::CALL: - case WebAssembly::CALL_S: - return MI.getOperand(MI.getNumDefs()); + return 1; default: llvm_unreachable("Not a call instruction"); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def --- a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def @@ -15,7 +15,6 @@ HANDLE_NODETYPE(CALL1) HANDLE_NODETYPE(CALL0) -HANDLE_NODETYPE(CALL) HANDLE_NODETYPE(RET_CALL) HANDLE_NODETYPE(RETURN) HANDLE_NODETYPE(ARGUMENT) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -206,25 +206,6 @@ } break; } - case WebAssemblyISD::CALL: { - // CALL has both variable operands and variable results, but ISel only - // supports one or the other. Split calls into two nodes glued together, one - // for the operands and one for the results. These two nodes will be - // recombined in a custom inserter hook. - // TODO: Split CALL - SmallVector Ops; - for (size_t i = 1; i < Node->getNumOperands(); ++i) { - SDValue Op = Node->getOperand(i); - if (Op->getOpcode() == WebAssemblyISD::Wrapper) - Op = Op->getOperand(0); - Ops.push_back(Op); - } - Ops.push_back(Node->getOperand(0)); - MachineSDNode *Call = - CurDAG->getMachineNode(WebAssembly::CALL, DL, Node->getVTList(), Ops); - ReplaceNode(Node, Call); - return; - } default: break; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -680,6 +680,9 @@ } SmallVectorImpl &Ins = CLI.Ins; + if (Ins.size() > 1) + fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet"); + SmallVectorImpl &Outs = CLI.Outs; SmallVectorImpl &OutVals = CLI.OutVals; @@ -825,27 +828,18 @@ } InTys.push_back(MVT::Other); - unsigned Opc; - // TODO: Remove CALL0 and CALL1 in favor of CALL - switch (Ins.size()) { - case 0: - Opc = WebAssemblyISD::CALL0; - break; - case 1: - Opc = WebAssemblyISD::CALL1; - break; - default: - Opc = WebAssemblyISD::CALL; - break; - } SDVTList InTyList = DAG.getVTList(InTys); - SDValue Res = DAG.getNode(Opc, DL, InTyList, Ops); - - for (size_t I = 0; I < Ins.size(); ++I) - InVals.push_back(Res.getValue(I)); + SDValue Res = + DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1, + DL, InTyList, Ops); + if (Ins.empty()) { + Chain = Res; + } else { + InVals.push_back(Res); + Chain = Res.getValue(1); + } - // Return the chain - return Res.getValue(Ins.size()); + return Chain; } bool WebAssemblyTargetLowering::CanLowerReturn( diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -55,15 +55,6 @@ } let Uses = [SP32, SP64], isCall = 1 in { - -// TODO: Split CALL into separate nodes for operands and results. -// TODO: Add an indirect version of the variadic call, delete CALL_* -let variadicOpsAreDefs = 1 in -defm CALL : - I<(outs), (ins function32_op:$callee, variable_ops), - (outs), (ins function32_op:$callee), [], - "call \t$callee", "call\t$callee", 0x10>; - defm "" : CALL; defm "" : CALL; defm "" : CALL; @@ -77,7 +68,6 @@ defm "" : CALL; let IsCanonical = 1 in { - defm CALL_VOID : I<(outs), (ins function32_op:$callee, variable_ops), (outs), (ins function32_op:$callee), diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -135,12 +135,12 @@ // Determine whether a call to the callee referenced by // MI->getOperand(CalleeOpNo) reads memory, writes memory, and/or has side // effects. -static void queryCallee(const MachineInstr &MI, bool &Read, bool &Write, - bool &Effects, bool &StackPointer) { +static void queryCallee(const MachineInstr &MI, unsigned CalleeOpNo, bool &Read, + bool &Write, bool &Effects, bool &StackPointer) { // All calls can use the stack pointer. StackPointer = true; - const MachineOperand &MO = WebAssembly::getCalleeOp(MI); + const MachineOperand &MO = MI.getOperand(CalleeOpNo); if (MO.isGlobal()) { const Constant *GV = MO.getGlobal(); if (const auto *GA = dyn_cast(GV)) @@ -252,7 +252,8 @@ // Analyze calls. if (MI.isCall()) { - queryCallee(MI, Read, Write, Effects, StackPointer); + unsigned CalleeOpNo = WebAssembly::getCalleeOpNo(MI.getOpcode()); + queryCallee(MI, CalleeOpNo, Read, Write, Effects, StackPointer); } } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h @@ -47,7 +47,7 @@ TargetTransformInfo getTargetTransformInfo(const Function &F) override; - bool usesPhysRegsForValues() const override { return false; } + bool usesPhysRegsForPEI() const override { return false; } yaml::MachineFunctionInfo *createDefaultFuncInfoYAML() const override; yaml::MachineFunctionInfo * diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -44,10 +44,6 @@ return Bottom; } -/// Returns the operand number of a callee, assuming the argument is a call -/// instruction. -const MachineOperand &getCalleeOp(const MachineInstr &MI); - } // end namespace WebAssembly } // end namespace llvm diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -49,7 +49,7 @@ if (!MI.isCall()) return false; - const MachineOperand &MO = getCalleeOp(MI); + const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI.getOpcode())); assert(MO.isGlobal() || MO.isSymbol()); if (MO.isSymbol()) { @@ -79,67 +79,3 @@ // original LLVm IR? (Even when the callee may throw) return true; } - -inline const MachineOperand &getCalleeOp(const MachineInstr &MI) { - switch (MI.getOpcode()) { - case WebAssembly::CALL_VOID: - case WebAssembly::CALL_VOID_S: - case WebAssembly::CALL_INDIRECT_VOID: - case WebAssembly::CALL_INDIRECT_VOID_S: - case WebAssembly::RET_CALL: - case WebAssembly::RET_CALL_S: - case WebAssembly::RET_CALL_INDIRECT: - case WebAssembly::RET_CALL_INDIRECT_S: - return MI.getOperand(0); - case WebAssembly::CALL_i32: - case WebAssembly::CALL_i32_S: - case WebAssembly::CALL_i64: - case WebAssembly::CALL_i64_S: - case WebAssembly::CALL_f32: - case WebAssembly::CALL_f32_S: - case WebAssembly::CALL_f64: - case WebAssembly::CALL_f64_S: - case WebAssembly::CALL_v16i8: - case WebAssembly::CALL_v16i8_S: - case WebAssembly::CALL_v8i16: - case WebAssembly::CALL_v8i16_S: - case WebAssembly::CALL_v4i32: - case WebAssembly::CALL_v4i32_S: - case WebAssembly::CALL_v2i64: - case WebAssembly::CALL_v2i64_S: - case WebAssembly::CALL_v4f32: - case WebAssembly::CALL_v4f32_S: - case WebAssembly::CALL_v2f64: - case WebAssembly::CALL_v2f64_S: - case WebAssembly::CALL_exnref: - case WebAssembly::CALL_exnref_S: - case WebAssembly::CALL_INDIRECT_i32: - case WebAssembly::CALL_INDIRECT_i32_S: - case WebAssembly::CALL_INDIRECT_i64: - case WebAssembly::CALL_INDIRECT_i64_S: - case WebAssembly::CALL_INDIRECT_f32: - case WebAssembly::CALL_INDIRECT_f32_S: - case WebAssembly::CALL_INDIRECT_f64: - case WebAssembly::CALL_INDIRECT_f64_S: - case WebAssembly::CALL_INDIRECT_v16i8: - case WebAssembly::CALL_INDIRECT_v16i8_S: - case WebAssembly::CALL_INDIRECT_v8i16: - case WebAssembly::CALL_INDIRECT_v8i16_S: - case WebAssembly::CALL_INDIRECT_v4i32: - case WebAssembly::CALL_INDIRECT_v4i32_S: - case WebAssembly::CALL_INDIRECT_v2i64: - case WebAssembly::CALL_INDIRECT_v2i64_S: - case WebAssembly::CALL_INDIRECT_v4f32: - case WebAssembly::CALL_INDIRECT_v4f32_S: - case WebAssembly::CALL_INDIRECT_v2f64: - case WebAssembly::CALL_INDIRECT_v2f64_S: - case WebAssembly::CALL_INDIRECT_exnref: - case WebAssembly::CALL_INDIRECT_exnref_S: - return MI.getOperand(1); - case WebAssembly::CALL: - case WebAssembly::CALL_S: - return MI.getOperand(MI.getNumDefs()); - default: - llvm_unreachable("Not a call instruction"); - } -} diff --git a/llvm/test/CodeGen/WebAssembly/multivalue.ll b/llvm/test/CodeGen/WebAssembly/multivalue.ll --- a/llvm/test/CodeGen/WebAssembly/multivalue.ll +++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll @@ -1,116 +1,29 @@ -; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+multivalue,+tail-call | FileCheck %s -; RUN: llc < %s --filetype=obj -mattr=+multivalue,+tail-call | obj2yaml | FileCheck %s --check-prefix OBJ +; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+multivalue | FileCheck %s +; RUN: llc < %s --filetype=obj -mattr=+multivalue | obj2yaml | FileCheck %s --check-prefix OBJ -; Test that the multivalue calls, returns, function types, and block -; types work as expected. +; Test that the multivalue returns, function types, and block types +; work as expected. target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" -%pair = type { i32, i64 } -%packed_pair = type <{ i32, i64 }> - - -; CHECK-LABEL: pair_const: -; CHECK-NEXT: .functype pair_const () -> (i32, i64) -; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 42{{$}} -; CHECK-NEXT: i64.const $push[[L1:[0-9]+]]=, 42{{$}} -; CHECK-NEXT: return $pop[[L0]], $pop[[L1]]{{$}} -define %pair @pair_const() { - ret %pair { i32 42, i64 42 } -} - -; CHECK-LABEL: packed_pair_const: -; CHECK-NEXT: .functype packed_pair_const () -> (i32, i64) -; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 42{{$}} -; CHECK-NEXT: i64.const $push[[L1:[0-9]+]]=, 42{{$}} -; CHECK-NEXT: return $pop[[L0]], $pop[[L1]]{{$}} -define %packed_pair @packed_pair_const() { - ret %packed_pair <{ i32 42, i64 42 }> -} +%pair = type { i32, i32 } +%packed_pair = type <{ i32, i32 }> ; CHECK-LABEL: pair_ident: -; CHECK-NEXT: .functype pair_ident (i32, i64) -> (i32, i64) +; CHECK-NEXT: .functype pair_ident (i32, i32) -> (i32, i32) ; CHECK-NEXT: return $0, $1{{$}} define %pair @pair_ident(%pair %p) { ret %pair %p } ; CHECK-LABEL: packed_pair_ident: -; CHECK-NEXT: .functype packed_pair_ident (i32, i64) -> (i32, i64) +; CHECK-NEXT: .functype packed_pair_ident (i32, i32) -> (i32, i32) ; CHECK-NEXT: return $0, $1{{$}} define %packed_pair @packed_pair_ident(%packed_pair %p) { ret %packed_pair %p } -;; TODO: Multivalue calls are a WIP and do not necessarily produce -;; correct output. For now, just check that they don't cause any -;; crashes. - -define void @pair_call() { - %p = call %pair @pair_const() - ret void -} - -define void @packed_pair_call() { - %p = call %packed_pair @packed_pair_const() - ret void -} - -define %pair @pair_call_return() { - %p = call %pair @pair_const() - ret %pair %p -} - -define %packed_pair @packed_pair_call_return() { - %p = call %packed_pair @packed_pair_const() - ret %packed_pair %p -} - -define %pair @pair_tail_call() { - %p = musttail call %pair @pair_const() - ret %pair %p -} - -define %packed_pair @packed_pair_tail_call() { - %p = musttail call %packed_pair @packed_pair_const() - ret %packed_pair %p -} - -define i32 @pair_call_return_first() { - %p = call %pair @pair_const() - %v = extractvalue %pair %p, 0 - ret i32 %v -} - -define i32 @packed_pair_call_return_first() { - %p = call %packed_pair @packed_pair_const() - %v = extractvalue %packed_pair %p, 0 - ret i32 %v -} - -define i64 @pair_call_return_second() { - %p = call %pair @pair_const() - %v = extractvalue %pair %p, 1 - ret i64 %v -} - -define i64 @packed_pair_call_return_second() { - %p = call %packed_pair @packed_pair_const() - %v = extractvalue %packed_pair %p, 1 - ret i64 %v -} - -define %pair @pair_pass_through(%pair %p) { - %r = call %pair @pair_ident(%pair %p) - ret %pair %r -} - -define %packed_pair @packed_pair_pass_through(%packed_pair %p) { - %r = call %packed_pair @packed_pair_ident(%packed_pair %p) - ret %packed_pair %r -} - ; CHECK-LABEL: minimal_loop: ; CHECK-NEXT: .functype minimal_loop (i32) -> (i32, i64) ; CHECK-NEXT: .LBB{{[0-9]+}}_1: @@ -118,7 +31,7 @@ ; CHECK-NEXT: br 0{{$}} ; CHECK-NEXT: .LBB{{[0-9]+}}_2: ; CHECK-NEXT: end_loop{{$}} -define %pair @minimal_loop(i32* %p) { +define {i32, i64} @minimal_loop(i32* %p) { entry: br label %loop loop: @@ -126,40 +39,21 @@ } ; CHECK-LABEL: .section .custom_section.target_features -; CHECK-NEXT: .int8 2 +; CHECK-NEXT: .int8 1 ; CHECK-NEXT: .int8 43 ; CHECK-NEXT: .int8 10 ; CHECK-NEXT: .ascii "multivalue" -; CHECK-NEXT: .int8 43 -; CHECK-NEXT: .int8 9 -; CHECK-NEXT: .ascii "tail-call" ; OBJ-LABEL: - Type: TYPE ; OBJ-NEXT: Signatures: ; OBJ-NEXT: - Index: 0 -; OBJ-NEXT: ParamTypes: [] -; OBJ-NEXT: ReturnTypes: -; OBJ-NEXT: - I32 -; OBJ-NEXT: - I64 -; OBJ-NEXT: - Index: 1 ; OBJ-NEXT: ParamTypes: ; OBJ-NEXT: - I32 -; OBJ-NEXT: - I64 -; OBJ-NEXT: ReturnTypes: ; OBJ-NEXT: - I32 -; OBJ-NEXT: - I64 -; OBJ-NEXT: - Index: 2 -; OBJ-NEXT: ParamTypes: [] -; OBJ-NEXT: ReturnTypes: [] -; OBJ-NEXT: - Index: 3 -; OBJ-NEXT: ParamTypes: [] ; OBJ-NEXT: ReturnTypes: ; OBJ-NEXT: - I32 -; OBJ-NEXT: - Index: 4 -; OBJ-NEXT: ParamTypes: [] -; OBJ-NEXT: ReturnTypes: -; OBJ-NEXT: - I64 -; OBJ-NEXT: - Index: 5 +; OBJ-NEXT: - I32 +; OBJ-NEXT: - Index: 1 ; OBJ-NEXT: ParamTypes: ; OBJ-NEXT: - I32 ; OBJ-NEXT: ReturnTypes: