Skip to content

Commit fb7ecdd

Browse files
c-rhodesLukacma
authored andcommitted
[ValueTracking] Teach isGuaranteedNotToBeUndefOrPoison about splats (llvm#163570)
Splats include two poison values, but only the poison-ness of the splatted value actually matters.
1 parent bb93f53 commit fb7ecdd

File tree

5 files changed

+59
-25
lines changed

5 files changed

+59
-25
lines changed

clang/test/CodeGen/arm-mve-intrinsics/dup.c

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,7 @@ uint32x4_t test_vdupq_m_n_u32(uint32x4_t inactive, uint32_t a, mve_pred16_t p)
244244
// CHECK-NEXT: [[TMP1:%.*]] = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 [[TMP0]])
245245
// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <8 x half> poison, half [[A:%.*]], i64 0
246246
// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <8 x half> [[DOTSPLATINSERT]], <8 x half> poison, <8 x i32> zeroinitializer
247-
// CHECK-NEXT: [[TMP2:%.*]] = select <8 x i1> [[TMP1]], <8 x half> [[DOTSPLAT]], <8 x half> undef
248-
// CHECK-NEXT: ret <8 x half> [[TMP2]]
247+
// CHECK-NEXT: ret <8 x half> [[DOTSPLAT]]
249248
//
250249
float16x8_t test_vdupq_x_n_f16(float16_t a, mve_pred16_t p)
251250
{
@@ -258,8 +257,7 @@ float16x8_t test_vdupq_x_n_f16(float16_t a, mve_pred16_t p)
258257
// CHECK-NEXT: [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]])
259258
// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[A:%.*]], i64 0
260259
// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <4 x float> [[DOTSPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
261-
// CHECK-NEXT: [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x float> [[DOTSPLAT]], <4 x float> undef
262-
// CHECK-NEXT: ret <4 x float> [[TMP2]]
260+
// CHECK-NEXT: ret <4 x float> [[DOTSPLAT]]
263261
//
264262
float32x4_t test_vdupq_x_n_f32(float32_t a, mve_pred16_t p)
265263
{
@@ -272,8 +270,7 @@ float32x4_t test_vdupq_x_n_f32(float32_t a, mve_pred16_t p)
272270
// CHECK-NEXT: [[TMP1:%.*]] = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 [[TMP0]])
273271
// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <16 x i8> poison, i8 [[A:%.*]], i64 0
274272
// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <16 x i8> [[DOTSPLATINSERT]], <16 x i8> poison, <16 x i32> zeroinitializer
275-
// CHECK-NEXT: [[TMP2:%.*]] = select <16 x i1> [[TMP1]], <16 x i8> [[DOTSPLAT]], <16 x i8> undef
276-
// CHECK-NEXT: ret <16 x i8> [[TMP2]]
273+
// CHECK-NEXT: ret <16 x i8> [[DOTSPLAT]]
277274
//
278275
int8x16_t test_vdupq_x_n_s8(int8_t a, mve_pred16_t p)
279276
{
@@ -286,8 +283,7 @@ int8x16_t test_vdupq_x_n_s8(int8_t a, mve_pred16_t p)
286283
// CHECK-NEXT: [[TMP1:%.*]] = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 [[TMP0]])
287284
// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <8 x i16> poison, i16 [[A:%.*]], i64 0
288285
// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <8 x i16> [[DOTSPLATINSERT]], <8 x i16> poison, <8 x i32> zeroinitializer
289-
// CHECK-NEXT: [[TMP2:%.*]] = select <8 x i1> [[TMP1]], <8 x i16> [[DOTSPLAT]], <8 x i16> undef
290-
// CHECK-NEXT: ret <8 x i16> [[TMP2]]
286+
// CHECK-NEXT: ret <8 x i16> [[DOTSPLAT]]
291287
//
292288
int16x8_t test_vdupq_x_n_s16(int16_t a, mve_pred16_t p)
293289
{
@@ -300,8 +296,7 @@ int16x8_t test_vdupq_x_n_s16(int16_t a, mve_pred16_t p)
300296
// CHECK-NEXT: [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]])
301297
// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <4 x i32> poison, i32 [[A:%.*]], i64 0
302298
// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <4 x i32> [[DOTSPLATINSERT]], <4 x i32> poison, <4 x i32> zeroinitializer
303-
// CHECK-NEXT: [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[DOTSPLAT]], <4 x i32> undef
304-
// CHECK-NEXT: ret <4 x i32> [[TMP2]]
299+
// CHECK-NEXT: ret <4 x i32> [[DOTSPLAT]]
305300
//
306301
int32x4_t test_vdupq_x_n_s32(int32_t a, mve_pred16_t p)
307302
{
@@ -314,8 +309,7 @@ int32x4_t test_vdupq_x_n_s32(int32_t a, mve_pred16_t p)
314309
// CHECK-NEXT: [[TMP1:%.*]] = call <16 x i1> @llvm.arm.mve.pred.i2v.v16i1(i32 [[TMP0]])
315310
// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <16 x i8> poison, i8 [[A:%.*]], i64 0
316311
// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <16 x i8> [[DOTSPLATINSERT]], <16 x i8> poison, <16 x i32> zeroinitializer
317-
// CHECK-NEXT: [[TMP2:%.*]] = select <16 x i1> [[TMP1]], <16 x i8> [[DOTSPLAT]], <16 x i8> undef
318-
// CHECK-NEXT: ret <16 x i8> [[TMP2]]
312+
// CHECK-NEXT: ret <16 x i8> [[DOTSPLAT]]
319313
//
320314
uint8x16_t test_vdupq_x_n_u8(uint8_t a, mve_pred16_t p)
321315
{
@@ -328,8 +322,7 @@ uint8x16_t test_vdupq_x_n_u8(uint8_t a, mve_pred16_t p)
328322
// CHECK-NEXT: [[TMP1:%.*]] = call <8 x i1> @llvm.arm.mve.pred.i2v.v8i1(i32 [[TMP0]])
329323
// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <8 x i16> poison, i16 [[A:%.*]], i64 0
330324
// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <8 x i16> [[DOTSPLATINSERT]], <8 x i16> poison, <8 x i32> zeroinitializer
331-
// CHECK-NEXT: [[TMP2:%.*]] = select <8 x i1> [[TMP1]], <8 x i16> [[DOTSPLAT]], <8 x i16> undef
332-
// CHECK-NEXT: ret <8 x i16> [[TMP2]]
325+
// CHECK-NEXT: ret <8 x i16> [[DOTSPLAT]]
333326
//
334327
uint16x8_t test_vdupq_x_n_u16(uint16_t a, mve_pred16_t p)
335328
{
@@ -342,8 +335,7 @@ uint16x8_t test_vdupq_x_n_u16(uint16_t a, mve_pred16_t p)
342335
// CHECK-NEXT: [[TMP1:%.*]] = call <4 x i1> @llvm.arm.mve.pred.i2v.v4i1(i32 [[TMP0]])
343336
// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <4 x i32> poison, i32 [[A:%.*]], i64 0
344337
// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <4 x i32> [[DOTSPLATINSERT]], <4 x i32> poison, <4 x i32> zeroinitializer
345-
// CHECK-NEXT: [[TMP2:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[DOTSPLAT]], <4 x i32> undef
346-
// CHECK-NEXT: ret <4 x i32> [[TMP2]]
338+
// CHECK-NEXT: ret <4 x i32> [[DOTSPLAT]]
347339
//
348340
uint32x4_t test_vdupq_x_n_u32(uint32_t a, mve_pred16_t p)
349341
{

clang/test/Headers/wasm.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ v128_t test_f64x2_const_splat(void) {
612612
return wasm_f64x2_const_splat(42);
613613
}
614614

615-
// CHECK-LABEL: define hidden <4 x i32> @test_i8x16_splat(
615+
// CHECK-LABEL: define hidden noundef <4 x i32> @test_i8x16_splat(
616616
// CHECK-SAME: i8 noundef signext [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
617617
// CHECK-NEXT: [[ENTRY:.*:]]
618618
// 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) {
624624
return wasm_i8x16_splat(a);
625625
}
626626

627-
// CHECK-LABEL: define hidden <4 x i32> @test_u8x16_splat(
627+
// CHECK-LABEL: define hidden noundef <4 x i32> @test_u8x16_splat(
628628
// CHECK-SAME: i8 noundef zeroext [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
629629
// CHECK-NEXT: [[ENTRY:.*:]]
630630
// 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) {
682682
return wasm_u8x16_replace_lane(a, 15, b);
683683
}
684684

685-
// CHECK-LABEL: define hidden <4 x i32> @test_i16x8_splat(
685+
// CHECK-LABEL: define hidden noundef <4 x i32> @test_i16x8_splat(
686686
// CHECK-SAME: i16 noundef signext [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
687687
// CHECK-NEXT: [[ENTRY:.*:]]
688688
// 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) {
694694
return wasm_i16x8_splat(a);
695695
}
696696

697-
// CHECK-LABEL: define hidden <4 x i32> @test_u16x8_splat(
697+
// CHECK-LABEL: define hidden noundef <4 x i32> @test_u16x8_splat(
698698
// CHECK-SAME: i16 noundef zeroext [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
699699
// CHECK-NEXT: [[ENTRY:.*:]]
700700
// 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) {
752752
return wasm_u16x8_replace_lane(a, 7, b);
753753
}
754754

755-
// CHECK-LABEL: define hidden <4 x i32> @test_i32x4_splat(
755+
// CHECK-LABEL: define hidden noundef <4 x i32> @test_i32x4_splat(
756756
// CHECK-SAME: i32 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
757757
// CHECK-NEXT: [[ENTRY:.*:]]
758758
// 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) {
763763
return wasm_i32x4_splat(a);
764764
}
765765

766-
// CHECK-LABEL: define hidden <4 x i32> @test_u32x4_splat(
766+
// CHECK-LABEL: define hidden noundef <4 x i32> @test_u32x4_splat(
767767
// CHECK-SAME: i32 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
768768
// CHECK-NEXT: [[ENTRY:.*:]]
769769
// 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) {
814814
return wasm_u32x4_replace_lane(a, 3, b);
815815
}
816816

817-
// CHECK-LABEL: define hidden <4 x i32> @test_i64x2_splat(
817+
// CHECK-LABEL: define hidden noundef <4 x i32> @test_i64x2_splat(
818818
// CHECK-SAME: i64 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
819819
// CHECK-NEXT: [[ENTRY:.*:]]
820820
// 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) {
826826
return wasm_i64x2_splat(a);
827827
}
828828

829-
// CHECK-LABEL: define hidden <4 x i32> @test_u64x2_splat(
829+
// CHECK-LABEL: define hidden noundef <4 x i32> @test_u64x2_splat(
830830
// CHECK-SAME: i64 noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
831831
// CHECK-NEXT: [[ENTRY:.*:]]
832832
// 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) {
919919
return wasm_f32x4_replace_lane(a, 3, b);
920920
}
921921

922-
// CHECK-LABEL: define hidden <4 x i32> @test_f64x2_splat(
922+
// CHECK-LABEL: define hidden noundef <4 x i32> @test_f64x2_splat(
923923
// CHECK-SAME: double noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
924924
// CHECK-NEXT: [[ENTRY:.*:]]
925925
// CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <2 x double> poison, double [[A]], i64 0

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7695,6 +7695,11 @@ static bool isGuaranteedNotToBeUndefOrPoison(
76957695
}
76967696
if (IsWellDefined)
76977697
return true;
7698+
} else if (auto *Splat = isa<ShuffleVectorInst>(Opr) ? getSplatValue(Opr)
7699+
: nullptr) {
7700+
// For splats we only need to check the value being splatted.
7701+
if (OpCheck(Splat))
7702+
return true;
76987703
} else if (all_of(Opr->operands(), OpCheck))
76997704
return true;
77007705
}

llvm/test/Transforms/InstSimplify/freeze-noundef.ll

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,30 @@ define {i8, i32} @noundef_metadata2(ptr %p) {
156156
%v.fr = freeze {i8, i32} %v
157157
ret {i8, i32} %v.fr
158158
}
159+
160+
; Splats have two poison values but only the poison-ness of the splatted value
161+
; matters.
162+
define <4 x i32> @splat(i32 noundef %x) {
163+
; CHECK-LABEL: @splat(
164+
; CHECK-NEXT: [[INS:%.*]] = insertelement <4 x i32> poison, i32 [[X:%.*]], i32 0
165+
; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[INS]], <4 x i32> poison, <4 x i32> zeroinitializer
166+
; CHECK-NEXT: ret <4 x i32> [[SPLAT]]
167+
;
168+
%ins = insertelement <4 x i32> poison, i32 %x, i32 0
169+
%splat = shufflevector <4 x i32> %ins, <4 x i32> poison, <4 x i32> zeroinitializer
170+
%splat.fr = freeze <4 x i32> %splat
171+
ret <4 x i32> %splat.fr
172+
}
173+
174+
define <4 x i32> @splat_poison_idx(i32 noundef %x) {
175+
; CHECK-LABEL: @splat_poison_idx(
176+
; CHECK-NEXT: [[INS:%.*]] = insertelement <4 x i32> poison, i32 [[X:%.*]], i32 0
177+
; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i32> [[INS]], <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 poison>
178+
; CHECK-NEXT: [[SPLAT_FR:%.*]] = freeze <4 x i32> [[SPLAT]]
179+
; CHECK-NEXT: ret <4 x i32> [[SPLAT_FR]]
180+
;
181+
%ins = insertelement <4 x i32> poison, i32 %x, i32 0
182+
%splat = shufflevector <4 x i32> %ins, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 poison>
183+
%splat.fr = freeze <4 x i32> %splat
184+
ret <4 x i32> %splat.fr
185+
}

llvm/unittests/Analysis/ValueTrackingTest.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,16 @@ TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison) {
10911091
}
10921092
}
10931093

1094+
TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison_splat) {
1095+
parseAssembly(
1096+
"define <4 x i32> @test(i32 noundef %x) {\n"
1097+
" %ins = insertelement <4 x i32> poison, i32 %x, i32 0\n"
1098+
" %A = shufflevector <4 x i32> %ins, <4 x i32> poison, <4 x i32> zeroinitializer\n"
1099+
" ret <4 x i32> %A\n"
1100+
"}");
1101+
EXPECT_TRUE(isGuaranteedNotToBeUndefOrPoison(A));
1102+
}
1103+
10941104
TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison_assume) {
10951105
parseAssembly("declare i1 @f_i1()\n"
10961106
"declare i32 @f_i32()\n"

0 commit comments

Comments
 (0)