Div/rem by zero is immediate undefined behavior and anything goes.
Currently we fold it to undef, this patch changes it to fold to
poison instead, which is slightly stronger.
Differential Revision: https://reviews.llvm.org/D93995
const SimplifyQuery &Q) {
Type *Ty = Op0->getType();
- // X / undef -> undef
- // X % undef -> undef
+ // X / undef -> poison
+ // X % undef -> poison
if (Q.isUndefValue(Op1))
- return Op1;
+ return PoisonValue::get(Ty);
- // X / 0 -> undef
- // X % 0 -> undef
+ // X / 0 -> poison
+ // X % 0 -> poison
// We don't need to preserve faults!
if (match(Op1, m_Zero()))
- return UndefValue::get(Ty);
+ return PoisonValue::get(Ty);
- // If any element of a constant divisor fixed width vector is zero or undef,
- // the whole op is undef.
+ // If any element of a constant divisor fixed width vector is zero or undef
+ // the behavior is undefined and we can fold the whole op to poison.
auto *Op1C = dyn_cast<Constant>(Op1);
auto *VTy = dyn_cast<FixedVectorType>(Ty);
if (Op1C && VTy) {
for (unsigned i = 0; i != NumElts; ++i) {
Constant *Elt = Op1C->getAggregateElement(i);
if (Elt && (Elt->isNullValue() || Q.isUndefValue(Elt)))
- return UndefValue::get(Ty);
+ return PoisonValue::get(Ty);
}
}
define <3 x i8> @add-shl-sdiv-3xi8-undef0(<3 x i8> %x) {
; CHECK-LABEL: @add-shl-sdiv-3xi8-undef0(
-; CHECK-NEXT: ret <3 x i8> [[X:%.*]]
+; CHECK-NEXT: ret <3 x i8> poison
;
%sd = sdiv <3 x i8> %x, <i8 -4, i8 undef, i8 -4>
%sl = shl <3 x i8> %sd, <i8 2, i8 2, i8 2>
define <2 x i64> @sdiv_by_minus1_vec_undef_elt(<2 x i64> %x) {
; CHECK-LABEL: @sdiv_by_minus1_vec_undef_elt(
-; CHECK-NEXT: ret <2 x i64> undef
+; CHECK-NEXT: ret <2 x i64> poison
;
%div = sdiv <2 x i64> %x, <i64 -1, i64 undef>
ret <2 x i64> %div
define <2 x i8> @sdiv_negated_dividend_constant_divisor_vec_undef(<2 x i8> %x) {
; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_vec_undef(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%neg = sub nsw <2 x i8> zeroinitializer, %x
%d = sdiv <2 x i8> %neg, <i8 -128, i8 undef>
define <2 x i64> @sdiv_negated_dividend_constant_divisor_vec(<2 x i64> %x) {
; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_vec(
-; CHECK-NEXT: [[DIV:%.*]] = sdiv <2 x i64> [[X:%.*]], <i64 -3, i64 -4>
-; CHECK-NEXT: ret <2 x i64> [[DIV]]
+; CHECK-NEXT: [[DIV1_NEG:%.*]] = sdiv <2 x i64> [[X:%.*]], <i64 -3, i64 -4>
+; CHECK-NEXT: ret <2 x i64> [[DIV1_NEG]]
;
%neg = sub nsw <2 x i64> zeroinitializer, %x
%div = sdiv <2 x i64> %neg, <i64 3, i64 4>
define <2 x i64> @sdiv_exact_negated_dividend_constant_divisor_vec(<2 x i64> %x) {
; CHECK-LABEL: @sdiv_exact_negated_dividend_constant_divisor_vec(
-; CHECK-NEXT: [[DIV:%.*]] = sdiv exact <2 x i64> [[X:%.*]], <i64 -3, i64 -4>
-; CHECK-NEXT: ret <2 x i64> [[DIV]]
+; CHECK-NEXT: [[DIV1_NEG:%.*]] = sdiv exact <2 x i64> [[X:%.*]], <i64 -3, i64 -4>
+; CHECK-NEXT: ret <2 x i64> [[DIV1_NEG]]
;
%neg = sub nsw <2 x i64> zeroinitializer, %x
%div = sdiv exact <2 x i64> %neg, <i64 3, i64 4>
define i32 @test_exact_nsw_exact(i32 %x) {
; CHECK-LABEL: @test_exact_nsw_exact(
-; CHECK-NEXT: [[NEG:%.*]] = sdiv exact i32 [[X:%.*]], -3
-; CHECK-NEXT: ret i32 [[NEG]]
+; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv exact i32 [[X:%.*]], -3
+; CHECK-NEXT: ret i32 [[DIV_NEG]]
;
%div = sdiv exact i32 %x, 3
%neg = sub nsw i32 0, %div
define <2 x i64> @test_exact_vec(<2 x i64> %x) {
; CHECK-LABEL: @test_exact_vec(
-; CHECK-NEXT: [[NEG:%.*]] = sdiv exact <2 x i64> [[X:%.*]], <i64 -3, i64 -4>
-; CHECK-NEXT: ret <2 x i64> [[NEG]]
+; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv exact <2 x i64> [[X:%.*]], <i64 -3, i64 -4>
+; CHECK-NEXT: ret <2 x i64> [[DIV_NEG]]
;
%div = sdiv exact <2 x i64> %x, <i64 3, i64 4>
%neg = sub nsw <2 x i64> zeroinitializer, %div
define <2 x i8> @negate_sdiv_vec_splat(<2 x i8> %x) {
; CHECK-LABEL: @negate_sdiv_vec_splat(
-; CHECK-NEXT: [[NEG:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 -42, i8 -42>
-; CHECK-NEXT: ret <2 x i8> [[NEG]]
+; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 -42, i8 -42>
+; CHECK-NEXT: ret <2 x i8> [[DIV_NEG]]
;
%div = sdiv <2 x i8> %x, <i8 42, i8 42>
%neg = sub <2 x i8> zeroinitializer, %div
define <2 x i8> @negate_sdiv_vec_undef_elt(<2 x i8> %x) {
; CHECK-LABEL: @negate_sdiv_vec_undef_elt(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%div = sdiv <2 x i8> %x, <i8 undef, i8 42>
%neg = sub <2 x i8> zeroinitializer, %div
define <2 x i8> @negate_sdiv_vec_splat_signed_min(<2 x i8> %x) {
; CHECK-LABEL: @negate_sdiv_vec_splat_signed_min(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 -128, i8 -128>
-; CHECK-NEXT: [[NEG:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i8>
-; CHECK-NEXT: ret <2 x i8> [[NEG]]
+; CHECK-NEXT: [[DIV_NEG:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i8>
+; CHECK-NEXT: ret <2 x i8> [[DIV_NEG]]
;
%div = sdiv <2 x i8> %x, <i8 -128, i8 -128>
%neg = sub <2 x i8> zeroinitializer, %div
define i32 @test_exact_nonsw_exact(i32 %x) {
; CHECK-LABEL: @test_exact_nonsw_exact(
-; CHECK-NEXT: [[NEG:%.*]] = sdiv exact i32 [[X:%.*]], -3
-; CHECK-NEXT: ret i32 [[NEG]]
+; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv exact i32 [[X:%.*]], -3
+; CHECK-NEXT: ret i32 [[DIV_NEG]]
;
%div = sdiv exact i32 %x, 3
%neg = sub i32 0, %div
define i32 @test_exact_nsw_noexact(i32 %x) {
; CHECK-LABEL: @test_exact_nsw_noexact(
-; CHECK-NEXT: [[NEG:%.*]] = sdiv i32 [[X:%.*]], -3
-; CHECK-NEXT: ret i32 [[NEG]]
+; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv i32 [[X:%.*]], -3
+; CHECK-NEXT: ret i32 [[DIV_NEG]]
;
%div = sdiv i32 %x, 3
%neg = sub nsw i32 0, %div
define i32 @test_exact_nonsw_noexact(i32 %x) {
; CHECK-LABEL: @test_exact_nonsw_noexact(
-; CHECK-NEXT: [[NEG:%.*]] = sdiv i32 [[X:%.*]], -3
-; CHECK-NEXT: ret i32 [[NEG]]
+; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv i32 [[X:%.*]], -3
+; CHECK-NEXT: ret i32 [[DIV_NEG]]
;
%div = sdiv i32 %x, 3
%neg = sub i32 0, %div
define i8 @test_exact_div_minSigned(i8 %x) {
; CHECK-LABEL: @test_exact_div_minSigned(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -128
-; CHECK-NEXT: [[NEG:%.*]] = sext i1 [[TMP1]] to i8
-; CHECK-NEXT: ret i8 [[NEG]]
+; CHECK-NEXT: [[DIV_NEG:%.*]] = sext i1 [[TMP1]] to i8
+; CHECK-NEXT: ret i8 [[DIV_NEG]]
;
%div = sdiv exact i8 %x, -128
%neg = sub nsw i8 0, %div
define <2 x i8> @sdiv_by_int_min_vec_splat_undef(<2 x i8> %x) {
; CHECK-LABEL: @sdiv_by_int_min_vec_splat_undef(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%d = sdiv <2 x i8> %x, <i8 -128, i8 undef>
ret <2 x i8> %d
; CHECK-NEXT: br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]]
; CHECK: then:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[C:%.*]], 0
-; CHECK-NEXT: [[PHITMP1:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT: [[PHI_BO:%.*]] = sext i1 [[CMP]] to i32
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHITMP1]], [[THEN]] ]
+; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHI_BO]], [[THEN]] ]
; CHECK-NEXT: ret i32 [[PHI]]
;
entry:
; CHECK: then:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ 0, [[THEN]] ]
-; CHECK-NEXT: ret i32 [[PHI]]
+; CHECK-NEXT: ret i32 -1
;
entry:
%tobool = icmp eq i16 %a, 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]]
; CHECK: then:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[C:%.*]], 0
-; CHECK-NEXT: [[PHITMP1:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT: [[PHI_BO:%.*]] = sext i1 [[CMP]] to i32
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHITMP1]], [[THEN]] ]
+; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHI_BO]], [[THEN]] ]
; CHECK-NEXT: ret i32 [[PHI]]
;
entry:
define <2 x i8> @urem_constant_op1(i8 %x) {
; CHECK-LABEL: @urem_constant_op1(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%ins = insertelement <2 x i8> poison, i8 %x, i32 1
%bo = urem <2 x i8> %ins, <i8 undef, i8 2>
define <2 x i8> @srem_constant_op1(i8 %x) {
; CHECK-LABEL: @srem_constant_op1(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%ins = insertelement <2 x i8> poison, i8 %x, i32 1
%bo = srem <2 x i8> %ins, <i8 undef, i8 2>
define <2 x i8> @udiv_constant_op1(i8 %x) {
; CHECK-LABEL: @udiv_constant_op1(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%ins = insertelement <2 x i8> poison, i8 %x, i32 1
%bo = udiv <2 x i8> %ins, <i8 undef, i8 2>
define <2 x i8> @sdiv_constant_op1(i8 %x) {
; CHECK-LABEL: @sdiv_constant_op1(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%ins = insertelement <2 x i8> poison, i8 %x, i32 1
%bo = sdiv exact <2 x i8> %ins, <i8 undef, i8 2>
define <2 x i8> @urem_constant_op1(i8 %x) {
; CHECK-LABEL: @urem_constant_op1(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%ins = insertelement <2 x i8> undef, i8 %x, i32 1
%bo = urem <2 x i8> %ins, <i8 undef, i8 2>
define <2 x i8> @srem_constant_op1(i8 %x) {
; CHECK-LABEL: @srem_constant_op1(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%ins = insertelement <2 x i8> undef, i8 %x, i32 1
%bo = srem <2 x i8> %ins, <i8 undef, i8 2>
define <2 x i8> @udiv_constant_op1(i8 %x) {
; CHECK-LABEL: @udiv_constant_op1(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%ins = insertelement <2 x i8> undef, i8 %x, i32 1
%bo = udiv <2 x i8> %ins, <i8 undef, i8 2>
define <2 x i8> @sdiv_constant_op1(i8 %x) {
; CHECK-LABEL: @sdiv_constant_op1(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%ins = insertelement <2 x i8> undef, i8 %x, i32 1
%bo = sdiv exact <2 x i8> %ins, <i8 undef, i8 2>
define i32 @test6(i32 %A) {
; CHECK-LABEL: @test6(
-; CHECK-NEXT: ret i32 undef
+; CHECK-NEXT: ret i32 poison
;
%B = srem i32 %A, 0 ;; undef
ret i32 %B
define <2 x i8> @n4_vec_undef(<2 x i8> %x) {
; CHECK-LABEL: @n4_vec_undef(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%div = sdiv exact <2 x i8> %x, <i8 -32, i8 undef>
ret <2 x i8> %div
define <2 x i8> @n5_vec_undef(<2 x i8> %x) {
; CHECK-LABEL: @n5_vec_undef(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%div = sdiv exact <2 x i8> %x, <i8 32, i8 undef>
ret <2 x i8> %div
define <2 x i32> @test38_undef(<2 x i32> %x) nounwind readnone {
; CHECK-LABEL: @test38_undef(
-; CHECK-NEXT: ret <2 x i32> undef
+; CHECK-NEXT: ret <2 x i32> poison
;
%rem = srem <2 x i32> %x, <i32 32, i32 undef>
%shl = shl <2 x i32> <i32 1, i32 1>, %rem
define <4 x i32> @test_v4i32_negconst_undef(<4 x i32> %a0) {
; CHECK-LABEL: @test_v4i32_negconst_undef(
-; CHECK-NEXT: ret <4 x i32> undef
+; CHECK-NEXT: ret <4 x i32> poison
;
%1 = udiv <4 x i32> %a0, <i32 -3, i32 -5, i32 -7, i32 undef>
ret <4 x i32> %1
define <4 x i32> @test_v4i32_const_pow2_undef(<4 x i32> %a0) {
; CHECK-LABEL: @test_v4i32_const_pow2_undef(
-; CHECK-NEXT: ret <4 x i32> undef
+; CHECK-NEXT: ret <4 x i32> poison
;
%1 = urem <4 x i32> %a0, <i32 1, i32 2, i32 4, i32 undef>
ret <4 x i32> %1
define <4 x i32> @test_v4i32_negconst_undef(<4 x i32> %a0) {
; CHECK-LABEL: @test_v4i32_negconst_undef(
-; CHECK-NEXT: ret <4 x i32> undef
+; CHECK-NEXT: ret <4 x i32> poison
;
%1 = urem <4 x i32> %a0, <i32 -3, i32 -5, i32 -7, i32 undef>
ret <4 x i32> %1
ret <2 x i8> %div
}
-; TODO: instsimplify should fold these to poison
define <2 x i8> @sdiv_zero_elt_vec(<2 x i8> %x) {
; CHECK-LABEL: @sdiv_zero_elt_vec(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%div = sdiv <2 x i8> %x, <i8 -42, i8 0>
ret <2 x i8> %div
define <2 x i8> @udiv_zero_elt_vec(<2 x i8> %x) {
; CHECK-LABEL: @udiv_zero_elt_vec(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%div = udiv <2 x i8> %x, <i8 0, i8 42>
ret <2 x i8> %div
define <2 x i8> @sdiv_undef_elt_vec(<2 x i8> %x) {
; CHECK-LABEL: @sdiv_undef_elt_vec(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%div = sdiv <2 x i8> %x, <i8 -42, i8 undef>
ret <2 x i8> %div
define <2 x i8> @udiv_undef_elt_vec(<2 x i8> %x) {
; CHECK-LABEL: @udiv_undef_elt_vec(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%div = udiv <2 x i8> %x, <i8 undef, i8 42>
ret <2 x i8> %div
ret i8 %v
}
-; TODO: these should be poison
define i32 @poison(i32 %x) {
; CHECK-LABEL: @poison(
; CHECK-NEXT: ret i32 poison
ret i32 %v
}
+; TODO: this should be poison
define i32 @poison2(i32 %x) {
; CHECK-LABEL: @poison2(
; CHECK-NEXT: ret i32 0
define <2 x i32> @poison3(<2 x i32> %x) {
; CHECK-LABEL: @poison3(
-; CHECK-NEXT: ret <2 x i32> undef
+; CHECK-NEXT: ret <2 x i32> poison
;
%v = udiv <2 x i32> %x, <i32 poison, i32 1>
ret <2 x i32> %v
ret <2 x i8> %rem
}
-; TODO: instsimplify should fold these to poison
define <2 x i8> @srem_zero_elt_vec(<2 x i8> %x) {
; CHECK-LABEL: @srem_zero_elt_vec(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%rem = srem <2 x i8> %x, <i8 -42, i8 0>
ret <2 x i8> %rem
define <2 x i8> @urem_zero_elt_vec(<2 x i8> %x) {
; CHECK-LABEL: @urem_zero_elt_vec(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%rem = urem <2 x i8> %x, <i8 0, i8 42>
ret <2 x i8> %rem
define <2 x i8> @srem_undef_elt_vec(<2 x i8> %x) {
; CHECK-LABEL: @srem_undef_elt_vec(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%rem = srem <2 x i8> %x, <i8 -42, i8 undef>
ret <2 x i8> %rem
define <2 x i8> @urem_undef_elt_vec(<2 x i8> %x) {
; CHECK-LABEL: @urem_undef_elt_vec(
-; CHECK-NEXT: ret <2 x i8> undef
+; CHECK-NEXT: ret <2 x i8> poison
;
%rem = urem <2 x i8> %x, <i8 undef, i8 42>
ret <2 x i8> %rem
define i32 @test20(i32 %a) {
; CHECK-LABEL: @test20(
-; CHECK-NEXT: ret i32 undef
+; CHECK-NEXT: ret i32 poison
;
%b = udiv i32 %a, 0
ret i32 %b
define <2 x i32> @test20vec(<2 x i32> %a) {
; CHECK-LABEL: @test20vec(
-; CHECK-NEXT: ret <2 x i32> undef
+; CHECK-NEXT: ret <2 x i32> poison
;
%b = udiv <2 x i32> %a, zeroinitializer
ret <2 x i32> %b
define i32 @test21(i32 %a) {
; CHECK-LABEL: @test21(
-; CHECK-NEXT: ret i32 undef
+; CHECK-NEXT: ret i32 poison
;
%b = sdiv i32 %a, 0
ret i32 %b
define <2 x i32> @test21vec(<2 x i32> %a) {
; CHECK-LABEL: @test21vec(
-; CHECK-NEXT: ret <2 x i32> undef
+; CHECK-NEXT: ret <2 x i32> poison
;
%b = sdiv <2 x i32> %a, zeroinitializer
ret <2 x i32> %b
define i32 @test38(i32 %a) {
; CHECK-LABEL: @test38(
-; CHECK-NEXT: ret i32 undef
+; CHECK-NEXT: ret i32 poison
;
%b = udiv i32 %a, undef
ret i32 %b
; CHECK-NEXT: [[AB5:%.*]] = sdiv i32 [[A5]], 4
; CHECK-NEXT: [[AB6:%.*]] = sdiv i32 [[A6]], 8
; CHECK-NEXT: [[AB7:%.*]] = sdiv i32 [[A7]], 16
-; CHECK-NEXT: [[TMP1:%.*]] = insertelement <8 x i32> <i32 undef, i32 poison, i32 poison, i32 poison, i32 undef, i32 poison, i32 poison, i32 poison>, i32 [[AB1]], i32 1
+; CHECK-NEXT: [[TMP1:%.*]] = insertelement <8 x i32> <i32 undef, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>, i32 [[AB1]], i32 1
; CHECK-NEXT: [[TMP2:%.*]] = insertelement <8 x i32> [[TMP1]], i32 [[AB2]], i32 2
; CHECK-NEXT: [[R4:%.*]] = insertelement <8 x i32> [[TMP2]], i32 [[AB3]], i32 3
; CHECK-NEXT: [[R5:%.*]] = insertelement <8 x i32> [[R4]], i32 [[AB5]], i32 5