Index: lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -1028,8 +1028,9 @@ // Expand mask indices to byte indices and materialize them as operands for (size_t I = 0, Lanes = Mask.size(); I < Lanes; ++I) { for (size_t J = 0; J < LaneBytes; ++J) { - Ops[OpIdx++] = - DAG.getConstant((uint64_t)Mask[I] * LaneBytes + J, DL, MVT::i32); + // Lower undefs to zero + uint64_t MaskVal = Mask[I] == -1 ? 0 : (uint64_t)Mask[I] * LaneBytes + J; + Ops[OpIdx++] = DAG.getConstant(MaskVal, DL, MVT::i32); } } Index: lib/Target/WebAssembly/WebAssemblyInstrSIMD.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -189,6 +189,26 @@ def : Pat<(i32 (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx))), (EXTRACT_LANE_v8i16_u V128:$vec, (i32 LaneIdx8:$idx))>; +// Lower undef lane indices to zero +def : Pat<(and (i32 (vector_extract (v16i8 V128:$vec), undef)), (i32 0xff)), + (EXTRACT_LANE_v16i8_u V128:$vec, 0)>; +def : Pat<(and (i32 (vector_extract (v8i16 V128:$vec), undef)), (i32 0xffff)), + (EXTRACT_LANE_v8i16_u V128:$vec, 0)>; +def : Pat<(i32 (vector_extract (v16i8 V128:$vec), undef)), + (EXTRACT_LANE_v16i8_u V128:$vec, 0)>; +def : Pat<(i32 (vector_extract (v8i16 V128:$vec), undef)), + (EXTRACT_LANE_v8i16_u V128:$vec, 0)>; +def : Pat<(sext_inreg (i32 (vector_extract (v16i8 V128:$vec), undef)), i8), + (EXTRACT_LANE_v16i8_s V128:$vec, 0)>; +def : Pat<(sext_inreg (i32 (vector_extract (v8i16 V128:$vec), undef)), i16), + (EXTRACT_LANE_v8i16_s V128:$vec, 0)>; +def : Pat<(vector_extract (v4i32 V128:$vec), undef), + (EXTRACT_LANE_v4i32 V128:$vec, 0)>; +def : Pat<(vector_extract (v2i64 V128:$vec), undef), + (EXTRACT_LANE_v2i64 V128:$vec, 0)>; +def : Pat<(vector_extract (v4f32 V128:$vec), undef), + (EXTRACT_LANE_v4f32 V128:$vec, 0)>; + // Replace lane value: replace_lane multiclass ReplaceLane; defm "" : ReplaceLane; +// Lower undef lane indices to zero +def : Pat<(vector_extract (v2f64 V128:$vec), undef), + (EXTRACT_LANE_v2f64 V128:$vec, 0)>; +def : Pat<(vector_insert (v16i8 V128:$vec), I32:$x, undef), + (REPLACE_LANE_v16i8 V128:$vec, 0, I32:$x)>; +def : Pat<(vector_insert (v8i16 V128:$vec), I32:$x, undef), + (REPLACE_LANE_v8i16 V128:$vec, 0, I32:$x)>; +def : Pat<(vector_insert (v4i32 V128:$vec), I32:$x, undef), + (REPLACE_LANE_v4i32 V128:$vec, 0, I32:$x)>; +def : Pat<(vector_insert (v2i64 V128:$vec), I64:$x, undef), + (REPLACE_LANE_v2i64 V128:$vec, 0, I64:$x)>; +def : Pat<(vector_insert (v4f32 V128:$vec), F32:$x, undef), + (REPLACE_LANE_v4f32 V128:$vec, 0, F32:$x)>; +def : Pat<(vector_insert (v2f64 V128:$vec), F64:$x, undef), + (REPLACE_LANE_v2f64 V128:$vec, 0, F64:$x)>; + // Arbitrary other BUILD_VECTOR patterns def : Pat<(v16i8 (build_vector (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3), Index: test/CodeGen/WebAssembly/simd.ll =================================================================== --- test/CodeGen/WebAssembly/simd.ll +++ test/CodeGen/WebAssembly/simd.ll @@ -54,6 +54,18 @@ ret i32 %a } +; CHECK-LABEL: extract_undef_v16i8_s: +; NO-SIMD128-NOT: i8x16 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result i32{{$}} +; SIMD128-NEXT: i8x16.extract_lane_s $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define i32 @extract_undef_v16i8_s(<16 x i8> %v) { + %elem = extractelement <16 x i8> %v, i8 undef + %a = sext i8 %elem to i32 + ret i32 %a +} + ; CHECK-LABEL: extract_v16i8_u: ; NO-SIMD128-NOT: i8x16 ; SIMD128-NEXT: .param v128{{$}} @@ -66,6 +78,18 @@ ret i32 %a } +; CHECK-LABEL: extract_undef_v16i8_u: +; NO-SIMD128-NOT: i8x16 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result i32{{$}} +; SIMD128-NEXT: i8x16.extract_lane_u $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define i32 @extract_undef_v16i8_u(<16 x i8> %v) { + %elem = extractelement <16 x i8> %v, i8 undef + %a = zext i8 %elem to i32 + ret i32 %a +} + ; CHECK-LABEL: extract_v16i8: ; NO-SIMD128-NOT: i8x16 ; SIMD128-NEXT: .param v128{{$}} @@ -77,6 +101,17 @@ ret i8 %elem } +; CHECK-LABEL: extract_undef_v16i8: +; NO-SIMD128-NOT: i8x16 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result i32{{$}} +; SIMD128-NEXT: i8x16.extract_lane_u $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define i8 @extract_undef_v16i8(<16 x i8> %v) { + %elem = extractelement <16 x i8> %v, i8 undef + ret i8 %elem +} + ; CHECK-LABEL: replace_v16i8: ; NO-SIMD128-NOT: i8x16 ; SIMD128-NEXT: .param v128, i32{{$}} @@ -88,6 +123,17 @@ ret <16 x i8> %res } +; CHECK-LABEL: replace_undef_v16i8: +; NO-SIMD128-NOT: i8x16 +; SIMD128-NEXT: .param v128, i32{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: i8x16.replace_lane $push[[R:[0-9]+]]=, $0, 0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <16 x i8> @replace_undef_v16i8(<16 x i8> %v, i8 %x) { + %res = insertelement <16 x i8> %v, i8 %x, i32 0 + ret <16 x i8> %res +} + ; CHECK-LABEL: shuffle_v16i8: ; NO-SIMD128-NOT: v8x16 ; SIMD128-NEXT: .param v128, v128{{$}} @@ -102,6 +148,22 @@ ret <16 x i8> %res } +; CHECK-LABEL: shuffle_undef_v16i8: +; NO-SIMD128-NOT: v8x16 +; SIMD128-NEXT: .param v128, v128{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: v8x16.shuffle $push[[R:[0-9]+]]=, $0, $0, +; SIMD128-SAME: 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <16 x i8> @shuffle_undef_v16i8(<16 x i8> %x, <16 x i8> %y) { + %res = shufflevector <16 x i8> %x, <16 x i8> %y, + <16 x i32> + ret <16 x i8> %res +} + ; CHECK-LABEL: build_v16i8: ; NO-SIMD128-NOT: i8x16 ; SIMD128-NEXT: .param i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32{{$}} @@ -190,6 +252,18 @@ ret i32 %a } +; CHECK-LABEL: extract_undef_v8i16_s: +; NO-SIMD128-NOT: i16x8 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result i32{{$}} +; SIMD128-NEXT: i16x8.extract_lane_s $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define i32 @extract_undef_v8i16_s(<8 x i16> %v) { + %elem = extractelement <8 x i16> %v, i16 undef + %a = sext i16 %elem to i32 + ret i32 %a +} + ; CHECK-LABEL: extract_v8i16_u: ; NO-SIMD128-NOT: i16x8 ; SIMD128-NEXT: .param v128{{$}} @@ -202,6 +276,18 @@ ret i32 %a } +; CHECK-LABEL: extract_undef_v8i16_u: +; NO-SIMD128-NOT: i16x8 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result i32{{$}} +; SIMD128-NEXT: i16x8.extract_lane_u $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define i32 @extract_undef_v8i16_u(<8 x i16> %v) { + %elem = extractelement <8 x i16> %v, i16 undef + %a = zext i16 %elem to i32 + ret i32 %a +} + ; CHECK-LABEL: extract_v8i16: ; NO-SIMD128-NOT: i16x8 ; SIMD128-NEXT: .param v128{{$}} @@ -213,6 +299,17 @@ ret i16 %elem } +; CHECK-LABEL: extract_undef_v8i16: +; NO-SIMD128-NOT: i16x8 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result i32{{$}} +; SIMD128-NEXT: i16x8.extract_lane_u $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define i16 @extract_undef_v8i16(<8 x i16> %v) { + %elem = extractelement <8 x i16> %v, i16 undef + ret i16 %elem +} + ; CHECK-LABEL: replace_v8i16: ; NO-SIMD128-NOT: i16x8 ; SIMD128-NEXT: .param v128, i32{{$}} @@ -224,6 +321,17 @@ ret <8 x i16> %res } +; CHECK-LABEL: replace_undef_v8i16: +; NO-SIMD128-NOT: i16x8 +; SIMD128-NEXT: .param v128, i32{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: i16x8.replace_lane $push[[R:[0-9]+]]=, $0, 0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <8 x i16> @replace_undef_v8i16(<8 x i16> %v, i16 %x) { + %res = insertelement <8 x i16> %v, i16 %x, i32 0 + ret <8 x i16> %res +} + ; CHECK-LABEL: shuffle_v8i16: ; NO-SIMD128-NOT: v8x16 ; SIMD128-NEXT: .param v128, v128{{$}} @@ -237,6 +345,20 @@ ret <8 x i16> %res } +; CHECK-LABEL: shuffle_undef_v8i16: +; NO-SIMD128-NOT: v8x16 +; SIMD128-NEXT: .param v128, v128{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: v8x16.shuffle $push[[R:[0-9]+]]=, $0, $0, +; SIMD128-SAME: 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <8 x i16> @shuffle_undef_v8i16(<8 x i16> %x, <8 x i16> %y) { + %res = shufflevector <8 x i16> %x, <8 x i16> %y, + <8 x i32> + ret <8 x i16> %res +} + ; CHECK-LABEL: build_v8i16: ; NO-SIMD128-NOT: i16x8 ; SIMD128-NEXT: .param i32, i32, i32, i32, i32, i32, i32, i32{{$}} @@ -305,6 +427,17 @@ ret i32 %elem } +; CHECK-LABEL: extract_undef_v4i32: +; NO-SIMD128-NOT: i32x4 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result i32{{$}} +; SIMD128-NEXT: i32x4.extract_lane $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define i32 @extract_undef_v4i32(<4 x i32> %v) { + %elem = extractelement <4 x i32> %v, i32 undef + ret i32 %elem +} + ; CHECK-LABEL: replace_v4i32: ; NO-SIMD128-NOT: i32x4 ; SIMD128-NEXT: .param v128, i32{{$}} @@ -316,6 +449,17 @@ ret <4 x i32> %res } +; CHECK-LABEL: replace_undef_v4i32: +; NO-SIMD128-NOT: i32x4 +; SIMD128-NEXT: .param v128, i32{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: i32x4.replace_lane $push[[R:[0-9]+]]=, $0, 0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <4 x i32> @replace_undef_v4i32(<4 x i32> %v, i32 %x) { + %res = insertelement <4 x i32> %v, i32 %x, i32 0 + ret <4 x i32> %res +} + ; CHECK-LABEL: shuffle_v4i32: ; NO-SIMD128-NOT: v8x16 ; SIMD128-NEXT: .param v128, v128{{$}} @@ -329,6 +473,19 @@ ret <4 x i32> %res } +; CHECK-LABEL: shuffle_undef_v4i32: +; NO-SIMD128-NOT: v8x16 +; SIMD128-NEXT: .param v128, v128{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: v8x16.shuffle $push[[R:[0-9]+]]=, $0, $0, +; SIMD128-SAME: 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <4 x i32> @shuffle_undef_v4i32(<4 x i32> %x, <4 x i32> %y) { + %res = shufflevector <4 x i32> %x, <4 x i32> %y, + <4 x i32> + ret <4 x i32> %res +} + ; CHECK-LABEL: build_v4i32: ; NO-SIMD128-NOT: i32x4 ; SIMD128-NEXT: .param i32, i32, i32, i32{{$}} @@ -390,6 +547,18 @@ ret i64 %elem } +; CHECK-LABEL: extract_undef_v2i64: +; NO-SIMD128-NOT: i64x2 +; SIMD128-VM-NOT: i64x2 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result i64{{$}} +; SIMD128-NEXT: i64x2.extract_lane $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define i64 @extract_undef_v2i64(<2 x i64> %v) { + %elem = extractelement <2 x i64> %v, i64 undef + ret i64 %elem +} + ; CHECK-LABEL: replace_v2i64: ; NO-SIMD128-NOT: i64x2 ; SIMD128-VM-NOT: i64x2 @@ -402,6 +571,18 @@ ret <2 x i64> %res } +; CHECK-LABEL: replace_undef_v2i64: +; NO-SIMD128-NOT: i64x2 +; SIMD128-VM-NOT: i64x2 +; SIMD128-NEXT: .param v128, i64{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: i64x2.replace_lane $push[[R:[0-9]+]]=, $0, 0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <2 x i64> @replace_undef_v2i64(<2 x i64> %v, i64 %x) { + %res = insertelement <2 x i64> %v, i64 %x, i32 0 + ret <2 x i64> %res +} + ; CHECK-LABEL: shuffle_v2i64: ; NO-SIMD128-NOT: v8x16 ; SIMD128-NEXT: .param v128, v128{{$}} @@ -414,6 +595,19 @@ ret <2 x i64> %res } +; CHECK-LABEL: shuffle_undef_v2i64: +; NO-SIMD128-NOT: v8x16 +; SIMD128-NEXT: .param v128, v128{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: v8x16.shuffle $push[[R:[0-9]+]]=, $0, $0, +; SIMD128-SAME: 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <2 x i64> @shuffle_undef_v2i64(<2 x i64> %x, <2 x i64> %y) { + %res = shufflevector <2 x i64> %x, <2 x i64> %y, + <2 x i32> + ret <2 x i64> %res +} + ; CHECK-LABEL: build_v2i64: ; NO-SIMD128-NOT: i64x2 ; SIMD128-VM-NOT: i64x2 @@ -472,6 +666,17 @@ ret float %elem } +; CHECK-LABEL: extract_undef_v4f32: +; NO-SIMD128-NOT: f32x4 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result f32{{$}} +; SIMD128-NEXT: f32x4.extract_lane $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define float @extract_undef_v4f32(<4 x float> %v) { + %elem = extractelement <4 x float> %v, i32 undef + ret float %elem +} + ; CHECK-LABEL: replace_v4f32: ; NO-SIMD128-NOT: f32x4 ; SIMD128-NEXT: .param v128, f32{{$}} @@ -483,6 +688,17 @@ ret <4 x float> %res } +; CHECK-LABEL: replace_undef_v4f32: +; NO-SIMD128-NOT: f32x4 +; SIMD128-NEXT: .param v128, f32{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: f32x4.replace_lane $push[[R:[0-9]+]]=, $0, 0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <4 x float> @replace_undef_v4f32(<4 x float> %v, float %x) { + %res = insertelement <4 x float> %v, float %x, i32 0 + ret <4 x float> %res +} + ; CHECK-LABEL: shuffle_v4f32: ; NO-SIMD128-NOT: v8x16 ; SIMD128-NEXT: .param v128, v128{{$}} @@ -496,6 +712,19 @@ ret <4 x float> %res } +; CHECK-LABEL: shuffle_undef_v4f32: +; NO-SIMD128-NOT: v8x16 +; SIMD128-NEXT: .param v128, v128{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: v8x16.shuffle $push[[R:[0-9]+]]=, $0, $0, +; SIMD128-SAME: 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <4 x float> @shuffle_undef_v4f32(<4 x float> %x, <4 x float> %y) { + %res = shufflevector <4 x float> %x, <4 x float> %y, + <4 x i32> + ret <4 x float> %res +} + ; CHECK-LABEL: build_v4f32: ; NO-SIMD128-NOT: f32x4 ; SIMD128-NEXT: .param f32, f32, f32, f32{{$}} @@ -556,6 +785,18 @@ ret double %elem } +; CHECK-LABEL: extract_undef_v2f64: +; NO-SIMD128-NOT: f64x2 +; SIMD128-VM-NOT: f64x2 +; SIMD128-NEXT: .param v128{{$}} +; SIMD128-NEXT: .result f64{{$}} +; SIMD128-NEXT: f64x2.extract_lane $push[[R:[0-9]+]]=, $0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define double @extract_undef_v2f64(<2 x double> %v) { + %elem = extractelement <2 x double> %v, i32 undef + ret double %elem +} + ; CHECK-LABEL: replace_v2f64: ; NO-SIMD128-NOT: f64x2 ; SIMD128-VM-NOT: f64x2 @@ -568,6 +809,18 @@ ret <2 x double> %res } +; CHECK-LABEL: replace_undef_v2f64: +; NO-SIMD128-NOT: f64x2 +; SIMD128-VM-NOT: f64x2 +; SIMD128-NEXT: .param v128, f64{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: f64x2.replace_lane $push[[R:[0-9]+]]=, $0, 0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <2 x double> @replace_undef_v2f64(<2 x double> %v, double %x) { + %res = insertelement <2 x double> %v, double %x, i32 0 + ret <2 x double> %res +} + ; CHECK-LABEL: shuffle_v2f64: ; NO-SIMD128-NOT: v8x16 ; SIMD128-NEXT: .param v128, v128{{$}} @@ -581,6 +834,19 @@ ret <2 x double> %res } +; CHECK-LABEL: shuffle_undef_v2f64: +; NO-SIMD128-NOT: v8x16 +; SIMD128-NEXT: .param v128, v128{{$}} +; SIMD128-NEXT: .result v128{{$}} +; SIMD128-NEXT: v8x16.shuffle $push[[R:[0-9]+]]=, $0, $0, +; SIMD128-SAME: 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +define <2 x double> @shuffle_undef_v2f64(<2 x double> %x, <2 x double> %y) { + %res = shufflevector <2 x double> %x, <2 x double> %y, + <2 x i32> + ret <2 x double> %res +} + ; CHECK-LABEL: build_v2f64: ; NO-SIMD128-NOT: f64x2 ; SIMD128-VM-NOT: f64x2