[llvm] 9d37f5a - [WebAssembly] Implement multivalue call_indirects

Thomas Lively via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 18 13:49:55 PST 2020


Author: Thomas Lively
Date: 2020-02-18T13:49:46-08:00
New Revision: 9d37f5afac4a3b9194b9001bed84f58ca8bd6c02

URL: https://github.com/llvm/llvm-project/commit/9d37f5afac4a3b9194b9001bed84f58ca8bd6c02
DIFF: https://github.com/llvm/llvm-project/commit/9d37f5afac4a3b9194b9001bed84f58ca8bd6c02.diff

LOG: [WebAssembly] Implement multivalue call_indirects

Summary:
Unlike normal calls, call_indirects have immediate arguments that
caused a MachineVerifier failure without a small tweak to loosen the
verifier's requirements for variadicOpsAreDefs instructions.

One nice thing about the new call_indirects is that they do not need
to participate in the PCALL_INDIRECT mechanism because their post-isel
hook handles moving the function pointer argument and adding the flags
and typeindex arguments itself.

Reviewers: aheejin

Subscribers: dschuff, sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D74191

Added: 
    

Modified: 
    llvm/lib/CodeGen/MachineVerifier.cpp
    llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
    llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
    llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
    llvm/test/CodeGen/WebAssembly/multivalue.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index bf589a7019e5..8d1c2fed15ad 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -1595,7 +1595,7 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) {
     bool IsOptional = MI->isVariadic() && MONum == MCID.getNumOperands() - 1;
     if (!IsOptional) {
       if (MO->isReg()) {
-        if (MO->isDef() && !MCOI.isOptionalDef())
+        if (MO->isDef() && !MCOI.isOptionalDef() && !MCID.variadicOpsAreDefs())
           report("Explicit operand marked as def", MO, MONum);
         if (MO->isImplicit())
           report("Explicit operand marked as implicit", MO, MONum);

diff  --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
index f7d1aeb9ec68..bc6363ec7b32 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
@@ -465,6 +465,8 @@ inline bool isCallDirect(unsigned Opc) {
   case WebAssembly::CALL_v2f64_S:
   case WebAssembly::CALL_exnref:
   case WebAssembly::CALL_exnref_S:
+  case WebAssembly::CALL:
+  case WebAssembly::CALL_S:
   case WebAssembly::RET_CALL:
   case WebAssembly::RET_CALL_S:
     return true;
@@ -499,6 +501,8 @@ inline bool isCallIndirect(unsigned Opc) {
   case WebAssembly::CALL_INDIRECT_v2f64_S:
   case WebAssembly::CALL_INDIRECT_exnref:
   case WebAssembly::CALL_INDIRECT_exnref_S:
+  case WebAssembly::CALL_INDIRECT:
+  case WebAssembly::CALL_INDIRECT_S:
   case WebAssembly::RET_CALL_INDIRECT:
   case WebAssembly::RET_CALL_INDIRECT_S:
     return true;
@@ -507,72 +511,6 @@ inline bool isCallIndirect(unsigned Opc) {
   }
 }
 
-/// Returns the operand number of a callee, assuming the argument is a call
-/// instruction.
-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");
-  }
-}
-
 inline bool isMarker(unsigned Opc) {
   switch (Opc) {
   case WebAssembly::BLOCK:

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index a3b1bc19698b..d62091e9c7e0 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -418,12 +418,29 @@ static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults,
   assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS);
   assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS);
 
+  bool IsIndirect = CallParams.getOperand(0).isReg();
+  unsigned CallOp = IsIndirect ? WebAssembly::CALL_INDIRECT : WebAssembly::CALL;
+
   MachineFunction &MF = *BB->getParent();
-  const MCInstrDesc &MCID = TII.get(WebAssembly::CALL);
+  const MCInstrDesc &MCID = TII.get(CallOp);
   MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
 
+  // Move the function pointer to the end of the arguments for indirect calls
+  if (IsIndirect) {
+    auto FnPtr = CallParams.getOperand(0);
+    CallParams.RemoveOperand(0);
+    CallParams.addOperand(FnPtr);
+  }
+
   for (auto Def : CallResults.defs())
     MIB.add(Def);
+
+  // Add placeholders for the type index and immediate flags
+  if (IsIndirect) {
+    MIB.addImm(0);
+    MIB.addImm(0);
+  }
+
   for (auto Use : CallParams.uses())
     MIB.add(Use);
 

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
index 818b6ce0df49..0020fe2c6ed7 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
@@ -73,12 +73,19 @@ defm CALL_RESULTS :
 
 let Uses = [SP32, SP64], isCall = 1 in {
 
-// TODO: Add an indirect version of the variadic call, delete CALL_*
+// TODO: 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>;
 
+let variadicOpsAreDefs = 1 in
+defm CALL_INDIRECT :
+ I<(outs), (ins TypeIndex:$type, i32imm:$flags, variable_ops),
+   (outs), (ins TypeIndex:$type, i32imm:$flags), [],
+   "call_indirect", "call_indirect\t$type", 0x11>;
+
 defm "" : CALL<i32, I32, "i32.">;
 defm "" : CALL<i64, I64, "i64.">;
 defm "" : CALL<f32, F32, "f32.">;

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 59c10243c545..75cde7d3b858 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -208,6 +208,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
   OutMI.setOpcode(MI->getOpcode());
 
   const MCInstrDesc &Desc = MI->getDesc();
+  unsigned NumVariadicDefs = MI->getNumExplicitDefs() - Desc.getNumDefs();
   for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
     const MachineOperand &MO = MI->getOperand(I);
 
@@ -229,9 +230,10 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
       MCOp = MCOperand::createReg(WAReg);
       break;
     }
-    case MachineOperand::MO_Immediate:
-      if (I < Desc.NumOperands) {
-        const MCOperandInfo &Info = Desc.OpInfo[I];
+    case MachineOperand::MO_Immediate: {
+      unsigned DescIndex = I - NumVariadicDefs;
+      if (DescIndex < Desc.NumOperands) {
+        const MCOperandInfo &Info = Desc.OpInfo[DescIndex];
         if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
           SmallVector<wasm::ValType, 4> Returns;
           SmallVector<wasm::ValType, 4> Params;
@@ -270,6 +272,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
       }
       MCOp = MCOperand::createImm(MO.getImm());
       break;
+    }
     case MachineOperand::MO_FPImmediate: {
       // TODO: MC converts all floating point immediate operands to double.
       // This is fine for numeric values, but may cause NaNs to change bits.

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
index 5b777984ffa6..1e044383547b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
@@ -80,7 +80,7 @@ bool WebAssembly::mayThrow(const MachineInstr &MI) {
   return true;
 }
 
-inline const MachineOperand &getCalleeOp(const MachineInstr &MI) {
+const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
   switch (MI.getOpcode()) {
   case WebAssembly::CALL_VOID:
   case WebAssembly::CALL_VOID_S:
@@ -138,7 +138,10 @@ inline const MachineOperand &getCalleeOp(const MachineInstr &MI) {
     return MI.getOperand(1);
   case WebAssembly::CALL:
   case WebAssembly::CALL_S:
-    return MI.getOperand(MI.getNumDefs());
+    return MI.getOperand(MI.getNumExplicitDefs());
+  case WebAssembly::CALL_INDIRECT:
+  case WebAssembly::CALL_INDIRECT_S:
+    return MI.getOperand(MI.getNumOperands() - 1);
   default:
     llvm_unreachable("Not a call instruction");
   }

diff  --git a/llvm/test/CodeGen/WebAssembly/multivalue.ll b/llvm/test/CodeGen/WebAssembly/multivalue.ll
index af601f7cbe92..0e4cb0847640 100644
--- a/llvm/test/CodeGen/WebAssembly/multivalue.ll
+++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll
@@ -1,4 +1,4 @@
-; 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 -asm-verbose=false -verify-machineinstrs -mattr=+multivalue,+tail-call | FileCheck %s
 ; RUN: llc < %s --filetype=obj -mattr=+multivalue,+tail-call | obj2yaml | FileCheck %s --check-prefix OBJ
 
 ; Test that the multivalue calls, returns, function types, and block
@@ -8,109 +8,82 @@ 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]]{{$}}
+; CHECK-NEXT: i32.const 42{{$}}
+; CHECK-NEXT: i64.const 42{{$}}
+; CHECK-NEXT: end_function{{$}}
 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 }>
-}
-
 ; CHECK-LABEL: pair_ident:
 ; CHECK-NEXT: .functype pair_ident (i32, i64) -> (i32, i64)
-; CHECK-NEXT: return $0, $1{{$}}
+; CHECK-NEXT: local.get 0{{$}}
+; CHECK-NEXT: local.get 1{{$}}
+; CHECK-NEXT: end_function{{$}}
 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: 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.
+;; TODO: Multivalue calls are a WIP and the following test cases do
+;; not necessarily produce correct output. For now just check that
+;; they do not crash.
 
+; CHECK-LABEL: pair_call:
+; CHECK-NEXT: .functype pair_call () -> ()
 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
-}
-
+; CHECK-LABEL: pair_call_return:
+; CHECK-NEXT: .functype pair_call_return () -> (i32, i64)
 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
+; CHECK-LABEL: pair_call_indirect:
+; CHECK-NEXT: .functype pair_call_indirect (i32) -> (i32, i64)
+; CHECK: call_indirect () -> (i32, i64){{$}}
+define %pair @pair_call_indirect(%pair()* %f) {
+  %p = call %pair %f()
+  ret %pair %p
 }
 
+; CHECK-LABEL: pair_tail_call:
+; CHECK-NEXT: .functype pair_tail_call () -> (i32, i64)
 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
-}
-
+; CHECK-LABEL: pair_call_return_first:
+; CHECK-NEXT: .functype pair_call_return_first () -> (i32)
 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
-}
-
+; CHECK-LABEL: pair_call_return_second:
+; CHECK-NEXT: .functype pair_call_return_second () -> (i64)
 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
-}
 
+; CHECK-LABEL: pair_pass_through:
+; CHECK-NEXT: .functype pair_pass_through (i32, i64) -> (i32, i64)
 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:
@@ -152,16 +125,16 @@ loop:
 ; OBJ-NEXT:         ParamTypes:      []
 ; OBJ-NEXT:         ReturnTypes:     []
 ; OBJ-NEXT:       - Index:           3
-; OBJ-NEXT:         ParamTypes:      []
+; OBJ-NEXT:         ParamTypes:
+; OBJ-NEXT:           - I32
 ; OBJ-NEXT:         ReturnTypes:
 ; OBJ-NEXT:           - I32
+; OBJ-NEXT:           - I64
 ; OBJ-NEXT:       - Index:           4
 ; OBJ-NEXT:         ParamTypes:      []
 ; OBJ-NEXT:         ReturnTypes:
-; OBJ-NEXT:           - I64
-; OBJ-NEXT:       - Index:           5
-; OBJ-NEXT:         ParamTypes:
 ; OBJ-NEXT:           - I32
+; OBJ-NEXT:       - Index:           5
+; OBJ-NEXT:         ParamTypes:      []
 ; OBJ-NEXT:         ReturnTypes:
-; OBJ-NEXT:           - I32
 ; OBJ-NEXT:           - I64


        


More information about the llvm-commits mailing list