diff --git a/clang/test/CodeGen/arm-mve-intrinsics/dup.c b/clang/test/CodeGen/arm-mve-intrinsics/dup.c index c2c7a9c278f67..e7113fdcba90a 100644 --- a/clang/test/CodeGen/arm-mve-intrinsics/dup.c +++ b/clang/test/CodeGen/arm-mve-intrinsics/dup.c @@ -244,8 +244,7 @@ uint32x4_t test_vdupq_m_n_u32(uint32x4_t inactive, uint32_t a, mve_pred16_t p) // CHECK-NEXT: [[TMP1:%.*]] = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 [[TMP0]]) // CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <8 x half> poison, half [[A:%.*]], i64 0 // CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <8 x half> [[DOTSPLATINSERT]], <8 x half> poison, <8 x i32> zeroinitializer -// CHECK-NEXT: [[TMP2:%.*]] = select <8 x i1> [[TMP1]], <8 x half> [[DOTSPLAT]], <8 x half> undef -// CHECK-NEXT: ret <8 x half> [[TMP2]] +// CHECK-NEXT: ret <8 x half> [[DOTSPLAT]] // float16x8_t test_vdupq_x_n_f16(float16_t a, mve_pred16_t p) { @@ -258,8 +257,7 @@ float16x8_t test_vdupq_x_n_f16(float16_t a, mve_pred16_t p) // CHECK-NEXT: [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]]) // CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[A:%.*]], i64 0 // CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <4 x float> [[DOTSPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer -// CHECK-NEXT: [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x float> [[DOTSPLAT]], <4 x float> undef -// CHECK-NEXT: ret <4 x float> [[TMP2]] +// CHECK-NEXT: ret <4 x float> [[DOTSPLAT]] // float32x4_t test_vdupq_x_n_f32(float32_t a, mve_pred16_t p) { @@ -272,8 +270,7 @@ float32x4_t test_vdupq_x_n_f32(float32_t a, mve_pred16_t p) // CHECK-NEXT: [[TMP1:%.*]] = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 [[TMP0]]) // CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <16 x i8> poison, i8 [[A:%.*]], i64 0 // CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <16 x i8> [[DOTSPLATINSERT]], <16 x i8> poison, <16 x i32> zeroinitializer -// CHECK-NEXT: [[TMP2:%.*]] = select <16 x i1> [[TMP1]], <16 x i8> [[DOTSPLAT]], <16 x i8> undef -// CHECK-NEXT: ret <16 x i8> [[TMP2]] +// CHECK-NEXT: ret <16 x i8> [[DOTSPLAT]] // int8x16_t test_vdupq_x_n_s8(int8_t a, mve_pred16_t p) { @@ -286,8 +283,7 @@ int8x16_t test_vdupq_x_n_s8(int8_t a, mve_pred16_t p) // CHECK-NEXT: [[TMP1:%.*]] = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 [[TMP0]]) // CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <8 x i16> poison, i16 [[A:%.*]], i64 0 // CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <8 x i16> [[DOTSPLATINSERT]], <8 x i16> poison, <8 x i32> zeroinitializer -// CHECK-NEXT: [[TMP2:%.*]] = select <8 x i1> [[TMP1]], <8 x i16> [[DOTSPLAT]], <8 x i16> undef -// CHECK-NEXT: ret <8 x i16> [[TMP2]] +// CHECK-NEXT: ret <8 x i16> [[DOTSPLAT]] // int16x8_t test_vdupq_x_n_s16(int16_t a, mve_pred16_t p) { @@ -300,8 +296,7 @@ int16x8_t test_vdupq_x_n_s16(int16_t a, mve_pred16_t p) // CHECK-NEXT: [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]]) // CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <4 x i32> poison, i32 [[A:%.*]], i64 0 // CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <4 x i32> [[DOTSPLATINSERT]], <4 x i32> poison, <4 x i32> zeroinitializer -// CHECK-NEXT: [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[DOTSPLAT]], <4 x i32> undef -// CHECK-NEXT: ret <4 x i32> [[TMP2]] +// CHECK-NEXT: ret <4 x i32> [[DOTSPLAT]] // int32x4_t test_vdupq_x_n_s32(int32_t a, mve_pred16_t p) { @@ -314,8 +309,7 @@ int32x4_t test_vdupq_x_n_s32(int32_t a, mve_pred16_t p) // CHECK-NEXT: [[TMP1:%.*]] = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 [[TMP0]]) // CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <16 x i8> poison, i8 [[A:%.*]], i64 0 // CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <16 x i8> [[DOTSPLATINSERT]], <16 x i8> poison, <16 x i32> zeroinitializer -// CHECK-NEXT: [[TMP2:%.*]] = select <16 x i1> [[TMP1]], <16 x i8> [[DOTSPLAT]], <16 x i8> undef -// CHECK-NEXT: ret <16 x i8> [[TMP2]] +// CHECK-NEXT: ret <16 x i8> [[DOTSPLAT]] // uint8x16_t test_vdupq_x_n_u8(uint8_t a, mve_pred16_t p) { @@ -328,8 +322,7 @@ uint8x16_t test_vdupq_x_n_u8(uint8_t a, mve_pred16_t p) // CHECK-NEXT: [[TMP1:%.*]] = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 [[TMP0]]) // CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <8 x i16> poison, i16 [[A:%.*]], i64 0 // CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <8 x i16> [[DOTSPLATINSERT]], <8 x i16> poison, <8 x i32> zeroinitializer -// CHECK-NEXT: [[TMP2:%.*]] = select <8 x i1> [[TMP1]], <8 x i16> [[DOTSPLAT]], <8 x i16> undef -// CHECK-NEXT: ret <8 x i16> [[TMP2]] +// CHECK-NEXT: ret <8 x i16> [[DOTSPLAT]] // uint16x8_t test_vdupq_x_n_u16(uint16_t a, mve_pred16_t p) { @@ -342,8 +335,7 @@ uint16x8_t test_vdupq_x_n_u16(uint16_t a, mve_pred16_t p) // CHECK-NEXT: [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]]) // CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <4 x i32> poison, i32 [[A:%.*]], i64 0 // CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <4 x i32> [[DOTSPLATINSERT]], <4 x i32> poison, <4 x i32> zeroinitializer -// CHECK-NEXT: [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[DOTSPLAT]], <4 x i32> undef -// CHECK-NEXT: ret <4 x i32> [[TMP2]] +// CHECK-NEXT: ret <4 x i32> [[DOTSPLAT]] // uint32x4_t test_vdupq_x_n_u32(uint32_t a, mve_pred16_t p) { diff --git a/clang/test/Headers/wasm.c b/clang/test/Headers/wasm.c index 7f427ca313ddc..03f20c5988268 100644 --- a/clang/test/Headers/wasm.c +++ b/clang/test/Headers/wasm.c @@ -612,7 +612,7 @@ v128_t test_f64x2_const_splat(void) { return wasm_f64x2_const_splat(42); } -// CHECK-LABEL: define hidden <4 x i32> @test_i8x16_splat( +// CHECK-LABEL: define hidden noundef <4 x i32> @test_i8x16_splat( // CHECK-SAME: i8 noundef signext [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <16 x i8> poison, i8 [[A]], i64 0 @@ -624,7 +624,7 @@ v128_t test_i8x16_splat(int8_t a) { return wasm_i8x16_splat(a); } -// CHECK-LABEL: define hidden <4 x i32> @test_u8x16_splat( +// CHECK-LABEL: define hidden noundef <4 x i32> @test_u8x16_splat( // CHECK-SAME: i8 noundef zeroext [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <16 x i8> poison, i8 [[A]], i64 0 @@ -682,7 +682,7 @@ v128_t test_u8x16_replace_lane(v128_t a, uint8_t b) { return wasm_u8x16_replace_lane(a, 15, b); } -// CHECK-LABEL: define hidden <4 x i32> @test_i16x8_splat( +// CHECK-LABEL: define hidden noundef <4 x i32> @test_i16x8_splat( // CHECK-SAME: i16 noundef signext [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 @@ -694,7 +694,7 @@ v128_t test_i16x8_splat(int16_t a) { return wasm_i16x8_splat(a); } -// CHECK-LABEL: define hidden <4 x i32> @test_u16x8_splat( +// CHECK-LABEL: define hidden noundef <4 x i32> @test_u16x8_splat( // CHECK-SAME: i16 noundef zeroext [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <8 x i16> poison, i16 [[A]], i64 0 @@ -752,7 +752,7 @@ v128_t test_u16x8_replace_lane(v128_t a, uint16_t b) { return wasm_u16x8_replace_lane(a, 7, b); } -// CHECK-LABEL: define hidden <4 x i32> @test_i32x4_splat( +// CHECK-LABEL: define hidden noundef <4 x i32> @test_i32x4_splat( // CHECK-SAME: i32 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 @@ -763,7 +763,7 @@ v128_t test_i32x4_splat(int32_t a) { return wasm_i32x4_splat(a); } -// CHECK-LABEL: define hidden <4 x i32> @test_u32x4_splat( +// CHECK-LABEL: define hidden noundef <4 x i32> @test_u32x4_splat( // CHECK-SAME: i32 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <4 x i32> poison, i32 [[A]], i64 0 @@ -814,7 +814,7 @@ v128_t test_u32x4_replace_lane(v128_t a, uint32_t b) { return wasm_u32x4_replace_lane(a, 3, b); } -// CHECK-LABEL: define hidden <4 x i32> @test_i64x2_splat( +// CHECK-LABEL: define hidden noundef <4 x i32> @test_i64x2_splat( // CHECK-SAME: i64 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <2 x i64> poison, i64 [[A]], i64 0 @@ -826,7 +826,7 @@ v128_t test_i64x2_splat(int64_t a) { return wasm_i64x2_splat(a); } -// CHECK-LABEL: define hidden <4 x i32> @test_u64x2_splat( +// CHECK-LABEL: define hidden noundef <4 x i32> @test_u64x2_splat( // CHECK-SAME: i64 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <2 x i64> poison, i64 [[A]], i64 0 @@ -919,7 +919,7 @@ v128_t test_f32x4_replace_lane(v128_t a, float b) { return wasm_f32x4_replace_lane(a, 3, b); } -// CHECK-LABEL: define hidden <4 x i32> @test_f64x2_splat( +// CHECK-LABEL: define hidden noundef <4 x i32> @test_f64x2_splat( // CHECK-SAME: double noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <2 x double> poison, double [[A]], i64 0 diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 9655c886f4441..0a72076f51824 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -7695,6 +7695,11 @@ static bool isGuaranteedNotToBeUndefOrPoison( } if (IsWellDefined) return true; + } else if (auto *Splat = isa(Opr) ? getSplatValue(Opr) + : nullptr) { + // For splats we only need to check the value being splatted. + if (OpCheck(Splat)) + return true; } else if (all_of(Opr->operands(), OpCheck)) return true; } diff --git a/llvm/test/Transforms/InstSimplify/freeze-noundef.ll b/llvm/test/Transforms/InstSimplify/freeze-noundef.ll index e6c296994cf6a..728e813c8c813 100644 --- a/llvm/test/Transforms/InstSimplify/freeze-noundef.ll +++ b/llvm/test/Transforms/InstSimplify/freeze-noundef.ll @@ -156,3 +156,30 @@ define {i8, i32} @noundef_metadata2(ptr %p) { %v.fr = freeze {i8, i32} %v ret {i8, i32} %v.fr } + +; Splats have two poison values but only the poison-ness of the splatted value +; matters. +define <4 x i32> @splat(i32 noundef %x) { +; CHECK-LABEL: @splat( +; CHECK-NEXT: [[INS:%.*]] = insertelement <4 x i32> poison, i32 [[X:%.*]], i32 0 +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[INS]], <4 x i32> poison, <4 x i32> zeroinitializer +; CHECK-NEXT: ret <4 x i32> [[SPLAT]] +; + %ins = insertelement <4 x i32> poison, i32 %x, i32 0 + %splat = shufflevector <4 x i32> %ins, <4 x i32> poison, <4 x i32> zeroinitializer + %splat.fr = freeze <4 x i32> %splat + ret <4 x i32> %splat.fr +} + +define <4 x i32> @splat_poison_idx(i32 noundef %x) { +; CHECK-LABEL: @splat_poison_idx( +; CHECK-NEXT: [[INS:%.*]] = insertelement <4 x i32> poison, i32 [[X:%.*]], i32 0 +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[INS]], <4 x i32> poison, <4 x i32> +; CHECK-NEXT: [[SPLAT_FR:%.*]] = freeze <4 x i32> [[SPLAT]] +; CHECK-NEXT: ret <4 x i32> [[SPLAT_FR]] +; + %ins = insertelement <4 x i32> poison, i32 %x, i32 0 + %splat = shufflevector <4 x i32> %ins, <4 x i32> poison, <4 x i32> + %splat.fr = freeze <4 x i32> %splat + ret <4 x i32> %splat.fr +} diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp index 559a0b724f383..bb0280ee69cfd 100644 --- a/llvm/unittests/Analysis/ValueTrackingTest.cpp +++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -1091,6 +1091,16 @@ TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison) { } } +TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison_splat) { + parseAssembly( + "define <4 x i32> @test(i32 noundef %x) {\n" + " %ins = insertelement <4 x i32> poison, i32 %x, i32 0\n" + " %A = shufflevector <4 x i32> %ins, <4 x i32> poison, <4 x i32> zeroinitializer\n" + " ret <4 x i32> %A\n" + "}"); + EXPECT_TRUE(isGuaranteedNotToBeUndefOrPoison(A)); +} + TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison_assume) { parseAssembly("declare i1 @f_i1()\n" "declare i32 @f_i32()\n"