Skip to content

Commit ca541aa

Browse files
committed
[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
1 parent 2d743af commit ca541aa

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2046,7 +2046,23 @@ SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
20462046
SmallVector<SDValue, 16> ConstLanes;
20472047
for (const SDValue &Lane : Op->op_values()) {
20482048
if (IsConstant(Lane)) {
2049-
ConstLanes.push_back(Lane);
2049+
// Values may need to be fixed so that they will sign extend to be
2050+
// within the expected range during ISel. Check whether the value is in
2051+
// bounds based on the lane bit width and if it is out of bounds, lop
2052+
// off the extra bits and subtract 2^n to reflect giving the high bit
2053+
// value -2^(n-1) rather than +2^(n-1). Skip the i64 case because it
2054+
// cannot possibly be out of range.
2055+
auto *Const = dyn_cast<ConstantSDNode>(Lane.getNode());
2056+
int64_t Val = Const ? Const->getSExtValue() : 0;
2057+
uint64_t LaneBits = 128 / Lanes;
2058+
assert((LaneT == MVT::i64 || Val >= -(1 << (LaneBits - 1))) &&
2059+
"Unexpected out of bounds negative value");
2060+
if (Const && LaneT != MVT::i64 && Val > (1 << (LaneBits - 1)) - 1) {
2061+
auto NewVal = ((uint64_t)Val % (1u << LaneBits)) - (1u << LaneBits);
2062+
ConstLanes.push_back(DAG.getConstant(NewVal, SDLoc(Lane), LaneT));
2063+
} else {
2064+
ConstLanes.push_back(Lane);
2065+
}
20502066
} else if (LaneT.isFloatingPoint()) {
20512067
ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
20522068
} else {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc < %s -verify-machineinstrs -mattr=+simd128 | FileCheck %s
3+
4+
; Regression test for an issue in which DAG combines created a constant i8x16
5+
; vector with lane values of 255, which was outside the -128 to 127 range
6+
; expected by our ISel patterns (and similar for the i16 version) and caused an
7+
; ISel failure. The fix was to adjust out-of-range values manually in
8+
; BUILD_VECTOR lowering.
9+
10+
target triple = "wasm32-unknown-unknown"
11+
12+
define <4 x i8> @test_i8(<4 x i8> %b) {
13+
; CHECK-LABEL: test_i8:
14+
; CHECK: .functype test_i8 (v128) -> (v128)
15+
; CHECK-NEXT: # %bb.0:
16+
; CHECK-NEXT: local.get 0
17+
; CHECK-NEXT: v128.const -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
18+
; CHECK-NEXT: v128.xor
19+
; CHECK-NEXT: v128.const 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
20+
; CHECK-NEXT: v128.and
21+
; CHECK-NEXT: # fallthrough-return
22+
%c = and <4 x i8> %b, <i8 1, i8 1, i8 1, i8 1>
23+
%d = xor <4 x i8> %c, <i8 1, i8 1, i8 1, i8 1>
24+
ret <4 x i8> %d
25+
}
26+
27+
define <4 x i16> @test_i16(<4 x i16> %b) {
28+
; CHECK-LABEL: test_i16:
29+
; CHECK: .functype test_i16 (v128) -> (v128)
30+
; CHECK-NEXT: # %bb.0:
31+
; CHECK-NEXT: local.get 0
32+
; CHECK-NEXT: v128.const -1, -1, -1, -1, 0, 0, 0, 0
33+
; CHECK-NEXT: v128.xor
34+
; CHECK-NEXT: v128.const 1, 1, 1, 1, 0, 0, 0, 0
35+
; CHECK-NEXT: v128.and
36+
; CHECK-NEXT: # fallthrough-return
37+
%c = and <4 x i16> %b, <i16 1, i16 1, i16 1, i16 1>
38+
%d = xor <4 x i16> %c, <i16 1, i16 1, i16 1, i16 1>
39+
ret <4 x i16> %d
40+
}

0 commit comments

Comments
 (0)