Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 8 additions & 16 deletions clang/test/CodeGen/arm-mve-intrinsics/dup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand Down
18 changes: 9 additions & 9 deletions clang/test/Headers/wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7695,6 +7695,11 @@ static bool isGuaranteedNotToBeUndefOrPoison(
}
if (IsWellDefined)
return true;
} else if (auto *Splat = isa<ShuffleVectorInst>(Opr) ? getSplatValue(Opr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious about how auto actually works here when selecting between two possibilities? It could choose nullptr, in which case it might be void * I presume? I can only assume it creates the type based on the first option, i.e. getSplatValue. I just wasn't sure whether the code compiles because of luck or an actual C++ specification based on ordering.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The precise rules for determining the result type of a ternary operator are exceedingly complicated, but the tl;dr is that nullptr is of type nullptr_t, which implicitly converts to all pointer types, and that's what makes this work.

: 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;
}
Expand Down
27 changes: 27 additions & 0 deletions llvm/test/Transforms/InstSimplify/freeze-noundef.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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> <i32 0, i32 1, i32 2, i32 poison>
; 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> <i32 0, i32 1, i32 2, i32 poison>
%splat.fr = freeze <4 x i32> %splat
ret <4 x i32> %splat.fr
}
10 changes: 10 additions & 0 deletions llvm/unittests/Analysis/ValueTrackingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading