[llvm] ca541aa - [WebAssembly] Fix up out-of-range BUILD_VECTOR lane constants

Thomas Lively via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 24 17:24:10 PDT 2021


Author: Thomas Lively
Date: 2021-08-24T17:24:03-07:00
New Revision: ca541aa319cd927c117235053712a808886828f0

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

LOG: [WebAssembly] Fix up out-of-range BUILD_VECTOR lane constants

Fixes PR51605 in which a DAG combine and legalization sequence generated
out-of-range constants in BUILD_VECTOR lanes. In the v16i8 case, the constants
were 255, which would be in range if DAG ISel used unsigned constants, but it is
out of range because DAG ISel uses signed constants.

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

Added: 
    llvm/test/CodeGen/WebAssembly/simd-pr51605.ll

Modified: 
    llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 29f68d476e479..f0191c6f98df4 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -2046,7 +2046,23 @@ SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
     SmallVector<SDValue, 16> ConstLanes;
     for (const SDValue &Lane : Op->op_values()) {
       if (IsConstant(Lane)) {
-        ConstLanes.push_back(Lane);
+        // Values may need to be fixed so that they will sign extend to be
+        // within the expected range during ISel. Check whether the value is in
+        // bounds based on the lane bit width and if it is out of bounds, lop
+        // off the extra bits and subtract 2^n to reflect giving the high bit
+        // value -2^(n-1) rather than +2^(n-1). Skip the i64 case because it
+        // cannot possibly be out of range.
+        auto *Const = dyn_cast<ConstantSDNode>(Lane.getNode());
+        int64_t Val = Const ? Const->getSExtValue() : 0;
+        uint64_t LaneBits = 128 / Lanes;
+        assert((LaneT == MVT::i64 || Val >= -(1 << (LaneBits - 1))) &&
+               "Unexpected out of bounds negative value");
+        if (Const && LaneT != MVT::i64 && Val > (1 << (LaneBits - 1)) - 1) {
+          auto NewVal = ((uint64_t)Val % (1u << LaneBits)) - (1u << LaneBits);
+          ConstLanes.push_back(DAG.getConstant(NewVal, SDLoc(Lane), LaneT));
+        } else {
+          ConstLanes.push_back(Lane);
+        }
       } else if (LaneT.isFloatingPoint()) {
         ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
       } else {

diff  --git a/llvm/test/CodeGen/WebAssembly/simd-pr51605.ll b/llvm/test/CodeGen/WebAssembly/simd-pr51605.ll
new file mode 100644
index 0000000000000..ba89f70824bb4
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/simd-pr51605.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -verify-machineinstrs -mattr=+simd128 | FileCheck %s
+
+; Regression test for an issue in which DAG combines created a constant i8x16
+; vector with lane values of 255, which was outside the -128 to 127 range
+; expected by our ISel patterns (and similar for the i16 version) and caused an
+; ISel failure. The fix was to adjust out-of-range values manually in
+; BUILD_VECTOR lowering.
+
+target triple = "wasm32-unknown-unknown"
+
+define <4 x i8> @test_i8(<4 x i8> %b) {
+; CHECK-LABEL: test_i8:
+; CHECK:         .functype test_i8 (v128) -> (v128)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    v128.const -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+; CHECK-NEXT:    v128.xor
+; CHECK-NEXT:    v128.const 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+; CHECK-NEXT:    v128.and
+; CHECK-NEXT:    # fallthrough-return
+  %c = and <4 x i8> %b, <i8 1, i8 1, i8 1, i8 1>
+  %d = xor <4 x i8> %c, <i8 1, i8 1, i8 1, i8 1>
+  ret <4 x i8> %d
+}
+
+define <4 x i16> @test_i16(<4 x i16> %b) {
+; CHECK-LABEL: test_i16:
+; CHECK:         .functype test_i16 (v128) -> (v128)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    v128.const -1, -1, -1, -1, 0, 0, 0, 0
+; CHECK-NEXT:    v128.xor
+; CHECK-NEXT:    v128.const 1, 1, 1, 1, 0, 0, 0, 0
+; CHECK-NEXT:    v128.and
+; CHECK-NEXT:    # fallthrough-return
+  %c = and <4 x i16> %b, <i16 1, i16 1, i16 1, i16 1>
+  %d = xor <4 x i16> %c, <i16 1, i16 1, i16 1, i16 1>
+  ret <4 x i16> %d
+}


        


More information about the llvm-commits mailing list