[clang] [llvm] [WebAssembly] Implement the wide-arithmetic proposal (PR #111598)

Alex Crichton via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 16 15:16:23 PDT 2024


https://github.com/alexcrichton updated https://github.com/llvm/llvm-project/pull/111598

>From ff058daf9e10347ab1b8d06a429d4997011ac74b Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex at alexcrichton.com>
Date: Tue, 8 Oct 2024 15:22:59 -0700
Subject: [PATCH 1/4] [WebAssembly] Implement the wide-arithmetic proposal

This commit implements the [wide-arithmetic] proposal which has recently
reached phase 2 in the WebAssembly proposals process. The goal here is
to implement support in LLVM for emitting these instructions which are
gated behind a new feature flag by default. A new `wide-arithmetic`
feature flag is introduced which gates these four new instructions from
being emitted.

Emission of each instruction itself is relatively simple given LLVM's
preexisting lowering rules and infrastructure. The main gotcha is that
due to the multi-result nature of all of these instructions it needed
the lowerings to be implemented in C++ rather than in TableGen.

[wide-arithmetic]: https://github.com/WebAssembly/wide-arithmetic
---
 llvm/lib/Target/WebAssembly/WebAssembly.td    |  4 ++
 .../lib/Target/WebAssembly/WebAssemblyISD.def |  4 ++
 .../WebAssembly/WebAssemblyISelLowering.cpp   | 71 +++++++++++++++++++
 .../WebAssembly/WebAssemblyISelLowering.h     |  2 +
 .../WebAssembly/WebAssemblyInstrInfo.td       |  4 ++
 .../WebAssembly/WebAssemblyInstrInteger.td    | 45 ++++++++++++
 .../Target/WebAssembly/WebAssemblySubtarget.h |  2 +
 .../CodeGen/WebAssembly/wide-arithmetic.ll    | 51 +++++++++++++
 8 files changed, 183 insertions(+)
 create mode 100644 llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll

diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td
index c632d4a74355d8..37d99690c25b1f 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.td
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.td
@@ -78,6 +78,10 @@ def FeatureTailCall :
       SubtargetFeature<"tail-call", "HasTailCall", "true",
                        "Enable tail call instructions">;
 
+def FeatureWideArithmetic :
+      SubtargetFeature<"wide-arithmetic", "HasWideArithmetic", "true",
+                       "Enable wide-arithmetic instructions">;
+
 //===----------------------------------------------------------------------===//
 // Architectures.
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def
index b8954f4693f0a0..f1ef58ef1f349c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def
@@ -44,6 +44,10 @@ HANDLE_NODETYPE(TRUNC_SAT_ZERO_U)
 HANDLE_NODETYPE(DEMOTE_ZERO)
 HANDLE_NODETYPE(MEMORY_COPY)
 HANDLE_NODETYPE(MEMORY_FILL)
+HANDLE_NODETYPE(I64_ADD128)
+HANDLE_NODETYPE(I64_SUB128)
+HANDLE_NODETYPE(I64_MUL_WIDE_S)
+HANDLE_NODETYPE(I64_MUL_WIDE_U)
 
 // Memory intrinsics
 HANDLE_MEM_NODETYPE(GLOBAL_GET)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index fa78bf38f426cd..465e72ff8c82c5 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -167,6 +167,13 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
         setOperationAction(Op, T, Expand);
   }
 
+  if (Subtarget->hasWideArithmetic()) {
+    setOperationAction(ISD::ADD, MVT::i128, Custom);
+    setOperationAction(ISD::SUB, MVT::i128, Custom);
+    setOperationAction(ISD::SMUL_LOHI, MVT::i64, Custom);
+    setOperationAction(ISD::UMUL_LOHI, MVT::i64, Custom);
+  }
+
   if (Subtarget->hasNontrappingFPToInt())
     for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT})
       for (auto T : {MVT::i32, MVT::i64})
@@ -1443,6 +1450,10 @@ void WebAssemblyTargetLowering::ReplaceNodeResults(
     // Do not add any results, signifying that N should not be custom lowered.
     // EXTEND_VECTOR_INREG is implemented for some vectors, but not all.
     break;
+  case ISD::ADD:
+  case ISD::SUB:
+    Results.push_back(Replace128Op(N, DAG));
+    break;
   default:
     llvm_unreachable(
         "ReplaceNodeResults not implemented for this op for WebAssembly!");
@@ -1519,6 +1530,9 @@ SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
     return DAG.UnrollVectorOp(Op.getNode());
   case ISD::CLEAR_CACHE:
     report_fatal_error("llvm.clear_cache is not supported on wasm");
+  case ISD::SMUL_LOHI:
+  case ISD::UMUL_LOHI:
+    return LowerMUL_LOHI(Op, DAG);
   }
 }
 
@@ -1617,6 +1631,63 @@ SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op,
   return Op;
 }
 
+SDValue WebAssemblyTargetLowering::LowerMUL_LOHI(SDValue Op,
+                                                 SelectionDAG &DAG) const {
+  assert(Subtarget->hasWideArithmetic());
+  assert(Op.getValueType() == MVT::i64);
+  SDLoc DL(Op);
+  unsigned Opcode;
+  switch (Op.getOpcode()) {
+  case ISD::UMUL_LOHI:
+    Opcode = WebAssemblyISD::I64_MUL_WIDE_U;
+    break;
+  case ISD::SMUL_LOHI:
+    Opcode = WebAssemblyISD::I64_MUL_WIDE_S;
+    break;
+  default:
+    llvm_unreachable("unexpected opcode");
+  }
+  SDValue LHS = Op.getOperand(0);
+  SDValue RHS = Op.getOperand(1);
+  SDValue Hi = DAG.getNode(Opcode, DL,
+                           DAG.getVTList(MVT::i64, MVT::i64), LHS, RHS);
+  SDValue Lo(Hi.getNode(), 1);
+  SDValue Ops[] = { Hi, Lo };
+  return DAG.getMergeValues(Ops, DL);
+}
+
+SDValue WebAssemblyTargetLowering::Replace128Op(SDNode *N,
+                                                SelectionDAG &DAG) const {
+  assert(Subtarget->hasWideArithmetic());
+  auto ValTy = N->getValueType(0);
+  assert(ValTy == MVT::i128);
+  SDLoc DL(N);
+  unsigned Opcode;
+  switch (N->getOpcode()) {
+  case ISD::ADD:
+    Opcode = WebAssemblyISD::I64_ADD128;
+    break;
+  case ISD::SUB:
+    Opcode = WebAssemblyISD::I64_SUB128;
+    break;
+  default:
+    llvm_unreachable("unexpected opcode");
+  }
+  SDValue LHS = N->getOperand(0);
+  SDValue RHS = N->getOperand(1);
+
+  SDValue C0 = DAG.getConstant(0, DL, MVT::i64);
+  SDValue C1 = DAG.getConstant(1, DL, MVT::i64);
+  SDValue LHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C0);
+  SDValue LHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C1);
+  SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C0);
+  SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C1);
+  SDValue Result_LO = DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64),
+      LHS_0, LHS_1, RHS_0, RHS_1);
+  SDValue Result_HI(Result_LO.getNode(), 1);
+  return DAG.getNode(ISD::BUILD_PAIR, DL, N->getVTList(), Result_LO, Result_HI);
+}
+
 SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
                                                   SelectionDAG &DAG) const {
   SDValue Src = Op.getOperand(2);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
index 7d9cfb7739e435..c04c463e968e0e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
@@ -138,6 +138,8 @@ class WebAssemblyTargetLowering final : public TargetLowering {
   SDValue LowerFP_TO_INT_SAT(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerLoad(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerStore(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerMUL_LOHI(SDValue Op, SelectionDAG &DAG) const;
+  SDValue Replace128Op(SDNode *N, SelectionDAG &DAG) const;
 
   // Custom DAG combine hooks
   SDValue
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 767ac86f1351b5..b3ea499c4f915e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -84,6 +84,10 @@ def HasTailCall :
     Predicate<"Subtarget->hasTailCall()">,
     AssemblerPredicate<(all_of FeatureTailCall), "tail-call">;
 
+def HasWideArithmetic :
+    Predicate<"Subtarget->hasWideArithmetic()">,
+    AssemblerPredicate<(all_of FeatureWideArithmetic), "wide-arithmetic">;
+
 //===----------------------------------------------------------------------===//
 // WebAssembly-specific DAG Node Types.
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
index 7a0c524d63b0d5..d4c8f92c883e78 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
@@ -129,3 +129,48 @@ def : Pat<(select (i32 (seteq I32:$cond, 0)), I32:$lhs, I32:$rhs),
           (SELECT_I32 I32:$rhs, I32:$lhs, I32:$cond)>;
 def : Pat<(select (i32 (seteq I32:$cond, 0)), I64:$lhs, I64:$rhs),
           (SELECT_I64 I64:$rhs, I64:$lhs, I32:$cond)>;
+
+let Predicates = [HasWideArithmetic] in {
+defm I64_ADD128 : I<(outs I64:$lo, I64:$hi), (ins I64:$lhs_lo, I64:$lhs_hi, I64:$rhs_lo, I64:$rhs_hi),
+                    (outs), (ins),
+                    [],
+                     "i64.add128\t$lo, $hi, $lhs_lo, $lhs_hi, $rhs_lo, $rhs_hi",
+                     "i64.add128",
+                     0xfc13>;
+defm I64_SUB128 : I<(outs I64:$lo, I64:$hi), (ins I64:$lhs_lo, I64:$lhs_hi, I64:$rhs_lo, I64:$rhs_hi),
+                    (outs), (ins),
+                    [],
+                     "i64.sub128\t$lo, $hi, $lhs_lo, $lhs_hi, $rhs_lo, $rhs_hi",
+                     "i64.sub128",
+                     0xfc14>;
+defm I64_MUL_WIDE_S : I<(outs I64:$lo, I64:$hi), (ins I64:$lhs, I64:$rhs),
+                        (outs), (ins),
+                        [],
+                         "i64.mul_wide_s\t$lo, $hi, $lhs, $rhs",
+                         "i64.mul_wide_s",
+                         0xfc15>;
+defm I64_MUL_WIDE_U : I<(outs I64:$lo, I64:$hi), (ins I64:$lhs, I64:$rhs),
+                        (outs), (ins),
+                        [],
+                        "i64.mul_wide_u\t$lo, $hi, $lhs, $rhs",
+                        "i64.mul_wide_u",
+                        0xfc16>;
+} // Predicates = [HasWideArithmetic]
+
+def wasm_binop128_t : SDTypeProfile<2, 4, []>;
+def wasm_add128 : SDNode<"WebAssemblyISD::I64_ADD128", wasm_binop128_t>;
+def wasm_sub128 : SDNode<"WebAssemblyISD::I64_SUB128", wasm_binop128_t>;
+
+def : Pat<(wasm_add128 I64:$a, I64:$b, I64:$c, I64:$d),
+          (I64_ADD128 $a, $b, $c, $d)>;
+def : Pat<(wasm_sub128 I64:$a, I64:$b, I64:$c, I64:$d),
+          (I64_SUB128 $a, $b, $c, $d)>;
+
+def wasm_mul_wide_t : SDTypeProfile<2, 2, []>;
+def wasm_mul_wide_s : SDNode<"WebAssemblyISD::I64_MUL_WIDE_S", wasm_mul_wide_t>;
+def wasm_mul_wide_u : SDNode<"WebAssemblyISD::I64_MUL_WIDE_U", wasm_mul_wide_t>;
+
+def : Pat<(wasm_mul_wide_s I64:$x, I64:$y),
+          (I64_MUL_WIDE_S $x, $y)>;
+def : Pat<(wasm_mul_wide_u I64:$x, I64:$y),
+          (I64_MUL_WIDE_U $x, $y)>;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
index f990120775d155..f2bf2902f775b6 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -51,6 +51,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool HasReferenceTypes = false;
   bool HasSignExt = false;
   bool HasTailCall = false;
+  bool HasWideArithmetic = false;
 
   /// What processor and OS we're targeting.
   Triple TargetTriple;
@@ -106,6 +107,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool hasSignExt() const { return HasSignExt; }
   bool hasSIMD128() const { return SIMDLevel >= SIMD128; }
   bool hasTailCall() const { return HasTailCall; }
+  bool hasWideArithmetic() const { return HasWideArithmetic; }
 
   /// Parses features string setting specified subtarget options. Definition of
   /// function is auto generated by tblgen.
diff --git a/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll b/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll
new file mode 100644
index 00000000000000..fdc5da6926e2a9
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll
@@ -0,0 +1,51 @@
+; RUN: llc -mattr=+wide-arithmetic < %s | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+define i128 @add_i128(i128 %a, i128 %b) {
+; CHECK-LABEL:  add_i128:
+; CHECK:        i64.add128
+  %c = add i128 %a, %b
+  ret i128 %c
+}
+
+define i128 @sub_i128(i128 %a, i128 %b) {
+; CHECK-LABEL:  sub_i128:
+; CHECK:        i64.sub128
+  %c = sub i128 %a, %b
+  ret i128 %c
+}
+
+define i128 @mul_i128(i128 %a, i128 %b) {
+; CHECK-LABEL:  mul_i128:
+; CHECK:        i64.mul_wide_u
+  %c = mul i128 %a, %b
+  ret i128 %c
+}
+
+define i128 @i64_mul_wide_s(i64 %a, i64 %b) {
+; CHECK-LABEL: i64_mul_wide_s:
+; CHECK:       i64.mul_wide_s
+  %a128 = sext i64 %a to i128
+  %b128 = sext i64 %b to i128
+  %c = mul i128 %a128, %b128
+  ret i128 %c
+}
+
+define i128 @i64_mul_wide_u(i64 %a, i64 %b) {
+; CHECK-LABEL: i64_mul_wide_u:
+; CHECK:       i64.mul_wide_u
+  %a128 = zext i64 %a to i128
+  %b128 = zext i64 %b to i128
+  %c = mul i128 %a128, %b128
+  ret i128 %c
+}
+
+define i64 @mul_i128_only_lo(i128 %a, i128 %b) {
+; CHECK-LABEL:  mul_i128_only_lo:
+; CHECK-NOT:    i64.mul128
+; CHECK:        i64.mul
+  %c = mul i128 %a, %b
+  %d = trunc i128 %c to i64
+  ret i64 %d
+}

>From f8ffb4f6bcbe484c22cfc59dc0c3f8c34f7b9279 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex at alexcrichton.com>
Date: Tue, 8 Oct 2024 15:34:35 -0700
Subject: [PATCH 2/4] Add wide-arithmetic support to clang too

---
 clang/include/clang/Driver/Options.td          |  2 ++
 clang/lib/Basic/Targets/WebAssembly.cpp        | 12 ++++++++++++
 clang/lib/Basic/Targets/WebAssembly.h          |  1 +
 clang/test/Driver/wasm-features.c              |  6 ++++++
 clang/test/Preprocessor/wasm-target-features.c | 12 ++++++++++++
 5 files changed, 33 insertions(+)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 90f0c4f2df2130..ee8ba7238a99a5 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5098,6 +5098,8 @@ def msimd128 : Flag<["-"], "msimd128">, Group<m_wasm_Features_Group>;
 def mno_simd128 : Flag<["-"], "mno-simd128">, Group<m_wasm_Features_Group>;
 def mtail_call : Flag<["-"], "mtail-call">, Group<m_wasm_Features_Group>;
 def mno_tail_call : Flag<["-"], "mno-tail-call">, Group<m_wasm_Features_Group>;
+def mwide_arithmetic : Flag<["-"], "mwide-arithmetic">, Group<m_wasm_Features_Group>;
+def mno_wide_arithmetic : Flag<["-"], "mno-wide-arithmetic">, Group<m_wasm_Features_Group>;
 def mexec_model_EQ : Joined<["-"], "mexec-model=">, Group<m_wasm_Features_Driver_Group>,
                      Values<"command,reactor">,
                      HelpText<"Execution model (WebAssembly only)">,
diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
index 5ac9421663adea..4c9df6007b7823 100644
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/clang/lib/Basic/Targets/WebAssembly.cpp
@@ -59,6 +59,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
       .Case("sign-ext", HasSignExt)
       .Case("simd128", SIMDLevel >= SIMD128)
       .Case("tail-call", HasTailCall)
+      .Case("wide-arithmetic", HasWideArithmetic)
       .Default(false);
 }
 
@@ -102,6 +103,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
     Builder.defineMacro("__wasm_simd128__");
   if (HasTailCall)
     Builder.defineMacro("__wasm_tail_call__");
+  if (HasWideArithmetic)
+    Builder.defineMacro("__wasm_wide_arithmetic__");
 
   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
@@ -166,6 +169,7 @@ bool WebAssemblyTargetInfo::initFeatureMap(
     Features["multimemory"] = true;
     Features["nontrapping-fptoint"] = true;
     Features["tail-call"] = true;
+    Features["wide-arithmetic"] = true;
     setSIMDLevel(Features, RelaxedSIMD, true);
   };
   if (CPU == "generic") {
@@ -293,6 +297,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
       HasTailCall = false;
       continue;
     }
+    if (Feature == "+wide-arithmetic") {
+      HasWideArithmetic = true;
+      continue;
+    }
+    if (Feature == "-wide-arithmetic") {
+      HasWideArithmetic = false;
+      continue;
+    }
 
     Diags.Report(diag::err_opt_not_valid_with_opt)
         << Feature << "-target-feature";
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 213ec42ca84bb7..c8e93c79bb656f 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -65,6 +65,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
   bool HasReferenceTypes = false;
   bool HasSignExt = false;
   bool HasTailCall = false;
+  bool HasWideArithmetic = false;
 
   std::string ABI;
 
diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c
index 57f0fc4ef36b6b..746bd7b8dfcba4 100644
--- a/clang/test/Driver/wasm-features.c
+++ b/clang/test/Driver/wasm-features.c
@@ -94,3 +94,9 @@
 
 // TAIL-CALL: "-target-feature" "+tail-call"
 // NO-TAIL-CALL: "-target-feature" "-tail-call"
+
+// RUN: %clang --target=wasm32-unknown-unknown -### %s -mwide-arithmetic 2>&1 | FileCheck %s -check-prefix=WIDE-ARITH
+// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-wide-arithmetic 2>&1 | FileCheck %s -check-prefix=NO-WIDE-ARITH
+
+// WIDE-ARITH: "-target-feature" "+wide-arithmetic"
+// NO-WIDE-ARITH: "-target-feature" "-wide-arithmetic"
diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c
index c64d3a0aa22825..14d2fbf4423d32 100644
--- a/clang/test/Preprocessor/wasm-target-features.c
+++ b/clang/test/Preprocessor/wasm-target-features.c
@@ -154,6 +154,7 @@
 // MVP-NOT: #define __wasm_sign_ext__ 1{{$}}
 // MVP-NOT: #define __wasm_simd128__ 1{{$}}
 // MVP-NOT: #define __wasm_tail_call__ 1{{$}}
+// MVP-NOT: #define __wasm_wide_arithmetic__ 1{{$}}
 
 // RUN: %clang -E -dM %s -o - 2>&1 \
 // RUN:     -target wasm32-unknown-unknown -mcpu=generic \
@@ -184,6 +185,7 @@
 // GENERIC-NOT: #define __wasm_relaxed_simd__ 1{{$}}
 // GENERIC-NOT: #define __wasm_simd128__ 1{{$}}
 // GENERIC-NOT: #define __wasm_tail_call__ 1{{$}}
+// GENERIC-NOT: #define __wasm_wide_arithmetic__ 1{{$}}
 
 // RUN: %clang -E -dM %s -o - 2>&1 \
 // RUN:     -target wasm32-unknown-unknown -mcpu=bleeding-edge \
@@ -206,6 +208,7 @@
 // BLEEDING-EDGE-INCLUDE-DAG: #define __wasm_sign_ext__ 1{{$}}
 // BLEEDING-EDGE-INCLUDE-DAG: #define __wasm_simd128__ 1{{$}}
 // BLEEDING-EDGE-INCLUDE-DAG: #define __wasm_tail_call__ 1{{$}}
+// BLEEDING-EDGE-INCLUDE-DAG: #define __wasm_wide_arithmetic__ 1{{$}}
 
 // RUN: %clang -E -dM %s -o - 2>&1 \
 // RUN:     -target wasm32-unknown-unknown -mcpu=bleeding-edge -mno-simd128 \
@@ -215,3 +218,12 @@
 // RUN:   | FileCheck %s -check-prefix=BLEEDING-EDGE-NO-SIMD128
 //
 // BLEEDING-EDGE-NO-SIMD128-NOT: #define __wasm_simd128__ 1{{$}}
+
+// RUN: %clang -E -dM %s -o - 2>&1 \
+// RUN:     -target wasm32-unknown-unknown -mwide-arithmetic \
+// RUN:   | FileCheck %s -check-prefix=WIDE-ARITHMETIC
+// RUN: %clang -E -dM %s -o - 2>&1 \
+// RUN:     -target wasm64-unknown-unknown -mwide-arithmetic \
+// RUN:   | FileCheck %s -check-prefix=WIDE-ARITHMETIC
+//
+// WIDE-ARITHMETIC: #define __wasm_wide_arithmetic__ 1{{$}}

>From f2901b3d065e1a4150a13caab59ade059fc7a4f8 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex at alexcrichton.com>
Date: Tue, 8 Oct 2024 15:35:16 -0700
Subject: [PATCH 3/4] Format code

---
 llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 465e72ff8c82c5..df9619ae9faa39 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -1649,10 +1649,10 @@ SDValue WebAssemblyTargetLowering::LowerMUL_LOHI(SDValue Op,
   }
   SDValue LHS = Op.getOperand(0);
   SDValue RHS = Op.getOperand(1);
-  SDValue Hi = DAG.getNode(Opcode, DL,
-                           DAG.getVTList(MVT::i64, MVT::i64), LHS, RHS);
+  SDValue Hi =
+      DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64), LHS, RHS);
   SDValue Lo(Hi.getNode(), 1);
-  SDValue Ops[] = { Hi, Lo };
+  SDValue Ops[] = {Hi, Lo};
   return DAG.getMergeValues(Ops, DL);
 }
 
@@ -1683,7 +1683,7 @@ SDValue WebAssemblyTargetLowering::Replace128Op(SDNode *N,
   SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C0);
   SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C1);
   SDValue Result_LO = DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64),
-      LHS_0, LHS_1, RHS_0, RHS_1);
+                                  LHS_0, LHS_1, RHS_0, RHS_1);
   SDValue Result_HI(Result_LO.getNode(), 1);
   return DAG.getNode(ISD::BUILD_PAIR, DL, N->getVTList(), Result_LO, Result_HI);
 }

>From 0b8a9c3d906dc5efb2a0f0a1c4d4412c0bd89f9e Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex at alexcrichton.com>
Date: Wed, 16 Oct 2024 15:15:50 -0700
Subject: [PATCH 4/4] Use `update_llc_test_checks.py` with new test

---
 .../CodeGen/WebAssembly/wide-arithmetic.ll    | 103 ++++++++++++++++--
 1 file changed, 92 insertions(+), 11 deletions(-)

diff --git a/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll b/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll
index fdc5da6926e2a9..deff551d0eabd3 100644
--- a/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll
+++ b/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll
@@ -1,31 +1,95 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
 ; RUN: llc -mattr=+wide-arithmetic < %s | FileCheck %s
 
 target triple = "wasm32-unknown-unknown"
 
 define i128 @add_i128(i128 %a, i128 %b) {
-; CHECK-LABEL:  add_i128:
-; CHECK:        i64.add128
+; CHECK-LABEL: add_i128:
+; CHECK:         .functype add_i128 (i32, i64, i64, i64, i64) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    local.get 3
+; CHECK-NEXT:    local.get 4
+; CHECK-NEXT:    i64.add128
+; CHECK-NEXT:    local.set 3
+; CHECK-NEXT:    local.set 4
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 3
+; CHECK-NEXT:    i64.store 8
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 4
+; CHECK-NEXT:    i64.store 0
+; CHECK-NEXT:    # fallthrough-return
   %c = add i128 %a, %b
   ret i128 %c
 }
 
 define i128 @sub_i128(i128 %a, i128 %b) {
-; CHECK-LABEL:  sub_i128:
-; CHECK:        i64.sub128
+; CHECK-LABEL: sub_i128:
+; CHECK:         .functype sub_i128 (i32, i64, i64, i64, i64) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    local.get 3
+; CHECK-NEXT:    local.get 4
+; CHECK-NEXT:    i64.sub128
+; CHECK-NEXT:    local.set 3
+; CHECK-NEXT:    local.set 4
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 3
+; CHECK-NEXT:    i64.store 8
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 4
+; CHECK-NEXT:    i64.store 0
+; CHECK-NEXT:    # fallthrough-return
   %c = sub i128 %a, %b
   ret i128 %c
 }
 
 define i128 @mul_i128(i128 %a, i128 %b) {
-; CHECK-LABEL:  mul_i128:
-; CHECK:        i64.mul_wide_u
+; CHECK-LABEL: mul_i128:
+; CHECK:         .functype mul_i128 (i32, i64, i64, i64, i64) -> ()
+; CHECK-NEXT:    .local i64
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 3
+; CHECK-NEXT:    i64.mul_wide_u
+; CHECK-NEXT:    local.set 5
+; CHECK-NEXT:    i64.store 0
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 5
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 4
+; CHECK-NEXT:    i64.mul
+; CHECK-NEXT:    i64.add
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    local.get 3
+; CHECK-NEXT:    i64.mul
+; CHECK-NEXT:    i64.add
+; CHECK-NEXT:    i64.store 8
+; CHECK-NEXT:    # fallthrough-return
   %c = mul i128 %a, %b
   ret i128 %c
 }
 
 define i128 @i64_mul_wide_s(i64 %a, i64 %b) {
 ; CHECK-LABEL: i64_mul_wide_s:
-; CHECK:       i64.mul_wide_s
+; CHECK:         .functype i64_mul_wide_s (i32, i64, i64) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i64.mul_wide_s
+; CHECK-NEXT:    local.set 1
+; CHECK-NEXT:    local.set 2
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i64.store 8
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i64.store 0
+; CHECK-NEXT:    # fallthrough-return
   %a128 = sext i64 %a to i128
   %b128 = sext i64 %b to i128
   %c = mul i128 %a128, %b128
@@ -34,7 +98,20 @@ define i128 @i64_mul_wide_s(i64 %a, i64 %b) {
 
 define i128 @i64_mul_wide_u(i64 %a, i64 %b) {
 ; CHECK-LABEL: i64_mul_wide_u:
-; CHECK:       i64.mul_wide_u
+; CHECK:         .functype i64_mul_wide_u (i32, i64, i64) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i64.mul_wide_u
+; CHECK-NEXT:    local.set 1
+; CHECK-NEXT:    local.set 2
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i64.store 8
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i64.store 0
+; CHECK-NEXT:    # fallthrough-return
   %a128 = zext i64 %a to i128
   %b128 = zext i64 %b to i128
   %c = mul i128 %a128, %b128
@@ -42,9 +119,13 @@ define i128 @i64_mul_wide_u(i64 %a, i64 %b) {
 }
 
 define i64 @mul_i128_only_lo(i128 %a, i128 %b) {
-; CHECK-LABEL:  mul_i128_only_lo:
-; CHECK-NOT:    i64.mul128
-; CHECK:        i64.mul
+; CHECK-LABEL: mul_i128_only_lo:
+; CHECK:         .functype mul_i128_only_lo (i64, i64, i64, i64) -> (i64)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i64.mul
+; CHECK-NEXT:    # fallthrough-return
   %c = mul i128 %a, %b
   %d = trunc i128 %c to i64
   ret i64 %d



More information about the llvm-commits mailing list