[InstSimplify] Add more poison folding optimizations

This adds more poison folding optimizations to InstSimplify.

Since all binary operators propagate poison, these are fine.

Also, the precondition of `select cond, undef, x` -> `x` is relaxed to allow the case when `x` is undef.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D104661
This commit is contained in:
Juneyoung Lee committed 2021-06-23 20:25:24 +09:00
1 parent 1b1c8e4a98
commit 5af8bacc94
13 files changed
+74 -59

No files matched your search

+50 -10
View File
@@ -734,6 +734,11 @@ static Value *SimplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
if (Constant *C = foldOrCommuteConstant(Instruction::Sub, Op0, Op1, Q))
return C;
// X - poison -> poison
// poison - X -> poison
if (isa<PoisonValue>(Op0) || isa<PoisonValue>(Op1))
return PoisonValue::get(Op0->getType());
// X - undef -> undef
// undef - X -> undef
if (Q.isUndefValue(Op0) || Q.isUndefValue(Op1))
@@ -869,6 +874,10 @@ static Value *SimplifyMulInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
if (Constant *C = foldOrCommuteConstant(Instruction::Mul, Op0, Op1, Q))
return C;
// X * poison -> poison
if (isa<PoisonValue>(Op1))
return Op1;
// X * undef -> 0
// X * 0 -> 0
if (Q.isUndefValue(Op1) || match(Op1, m_Zero()))
@@ -955,6 +964,11 @@ static Value *simplifyDivRem(Instruction::BinaryOps Opcode, Value *Op0,
}
}
// poison / X -> poison
// poison % X -> poison
if (isa<PoisonValue>(Op0))
return Op0;
// undef / X -> 0
// undef % X -> 0
if (Q.isUndefValue(Op0))
@@ -1241,6 +1255,10 @@ static Value *SimplifyShift(Instruction::BinaryOps Opcode, Value *Op0,
if (Constant *C = foldOrCommuteConstant(Opcode, Op0, Op1, Q))
return C;
// poison shift by X -> poison
if (isa<PoisonValue>(Op0))
return Op0;
// 0 shift by X -> 0
if (match(Op0, m_Zero()))
return Constant::getNullValue(Op0->getType());
@@ -1984,6 +2002,10 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
if (Constant *C = foldOrCommuteConstant(Instruction::And, Op0, Op1, Q))
return C;
// X & poison -> poison
if (isa<PoisonValue>(Op1))
return Op1;
// X & undef -> 0
if (Q.isUndefValue(Op1))
return Constant::getNullValue(Op0->getType());
@@ -2152,6 +2174,10 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
if (Constant *C = foldOrCommuteConstant(Instruction::Or, Op0, Op1, Q))
return C;
// X | poison -> poison
if (isa<PoisonValue>(Op1))
return Op1;
// X | undef -> -1
// X | -1 = -1
// Do not return Op1 because it may contain undef elements if it's a vector.
@@ -3689,6 +3715,11 @@ static Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
if (match(RHS, m_NaN()))
return ConstantInt::get(RetTy, CmpInst::isUnordered(Pred));
// fcmp pred x, poison and fcmp pred poison, x
// fold to poison
if (isa<PoisonValue>(LHS) || isa<PoisonValue>(RHS))
return PoisonValue::get(RetTy);
// fcmp pred x, undef and fcmp pred undef, x
// fold to true if unordered, false if ordered
if (Q.isUndefValue(LHS) || Q.isUndefValue(RHS)) {
@@ -4156,6 +4187,10 @@ static Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
if (auto *FalseC = dyn_cast<Constant>(FalseVal))
return ConstantFoldSelectInstruction(CondC, TrueC, FalseC);
// select poison, X, Y -> poison
if (isa<PoisonValue>(CondC))
return PoisonValue::get(TrueVal->getType());
// select undef, X, Y -> X or Y
if (Q.isUndefValue(CondC))
return isa<Constant>(FalseVal) ? FalseVal : TrueVal;
@@ -4183,15 +4218,20 @@ static Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
if (TrueVal == FalseVal)
return TrueVal;
// If the true or false value is poison, we can fold to the other value.
// If the true or false value is undef, we can fold to the other value as
// long as the other value isn't poison.
// select ?, undef, X -> X
if (Q.isUndefValue(TrueVal) &&
isGuaranteedNotToBeUndefOrPoison(FalseVal, Q.AC, Q.CxtI, Q.DT))
// select ?, poison, X -> X
// select ?, undef, X -> X
if (isa<PoisonValue>(TrueVal) ||
(Q.isUndefValue(TrueVal) &&
isGuaranteedNotToBePoison(FalseVal, Q.AC, Q.CxtI, Q.DT)))
return FalseVal;
// select ?, X, undef -> X
if (Q.isUndefValue(FalseVal) &&
isGuaranteedNotToBeUndefOrPoison(TrueVal, Q.AC, Q.CxtI, Q.DT))
// select ?, X, poison -> X
// select ?, X, undef -> X
if (isa<PoisonValue>(FalseVal) ||
(Q.isUndefValue(FalseVal) &&
isGuaranteedNotToBePoison(TrueVal, Q.AC, Q.CxtI, Q.DT)))
return TrueVal;
// Deal with partial undef vector constants: select ?, VecC, VecC' --> VecC''
@@ -4213,11 +4253,11 @@ static Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
// one element is undef, choose the defined element as the safe result.
if (TEltC == FEltC)
NewC.push_back(TEltC);
else if (Q.isUndefValue(TEltC) &&
isGuaranteedNotToBeUndefOrPoison(FEltC))
else if (isa<PoisonValue>(TEltC) ||
(Q.isUndefValue(TEltC) && isGuaranteedNotToBePoison(FEltC)))
NewC.push_back(FEltC);
else if (Q.isUndefValue(FEltC) &&
isGuaranteedNotToBeUndefOrPoison(TEltC))
else if (isa<PoisonValue>(FEltC) ||
(Q.isUndefValue(FEltC) && isGuaranteedNotToBePoison(TEltC)))
NewC.push_back(TEltC);
else
break;
@@ -177,7 +177,7 @@ define <2 x i16> @zext_lshr_vec_overshift(<2 x i8> %x) {
define <2 x i16> @zext_lshr_vec_undef(<2 x i8> %x) {
; CHECK-LABEL: @zext_lshr_vec_undef(
; CHECK-NEXT: ret <2 x i16> zeroinitializer
; CHECK-NEXT: ret <2 x i16> poison
;
%z = zext <2 x i8> %x to <2 x i16>
%b = lshr <2 x i16> %z, undef
@@ -202,7 +202,7 @@ define <2 x i16> @zext_shl_vec_overshift(<2 x i8> %x) {
define <2 x i16> @zext_shl_vec_undef(<2 x i8> %x) {
; CHECK-LABEL: @zext_shl_vec_undef(
; CHECK-NEXT: ret <2 x i16> zeroinitializer
; CHECK-NEXT: ret <2 x i16> poison
;
%z = zext <2 x i8> %x to <2 x i16>
%b = shl <2 x i16> %z, undef
@@ -496,7 +496,7 @@ define void @test25() {
; CHECK-LABEL: @test25(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i64 poison, i64* null, align 536870912
; CHECK-NEXT: tail call void @foo25(i32 0, i64 0)
; CHECK-NEXT: tail call void @foo25(i32 0, i64 poison)
; CHECK-NEXT: unreachable
;
entry:
@@ -31,7 +31,7 @@ define i32 @select_xor_icmp2(i32 %x, i32 %y, i32 %z) {
define i32 @select_xor_icmp_meta(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_xor_icmp_meta(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]], !prof !0
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[Z:%.*]], i32 [[Y:%.*]], !prof [[PROF0:![0-9]+]]
; CHECK-NEXT: ret i32 [[C]]
;
%A = icmp eq i32 %x, 0
@@ -1267,12 +1267,10 @@ define i32 @select_replace_udiv_speculatable(i32 %x, i32 %y) {
}
; We can't replace %x by 0 here, because that would cause UB. However,
; replacing the udiv result by poisong is fine.
; replacing the udiv result by poison is fine.
define i32 @select_replace_udiv_non_speculatable(i32 %x, i32 %y) {
; CHECK-LABEL: @select_replace_udiv_non_speculatable(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i32 poison, i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[S]]
; CHECK-NEXT: ret i32 [[Y:%.*]]
;
%c = icmp eq i32 %x, 0
%div = udiv i32 %y, %x
@@ -115,10 +115,9 @@ define void @other_ops(i8 %x) {
ret void
}
; TODO: these must be folded into poison; D92270
define void @logicalops_i1(i1 %x) {
; CHECK-LABEL: @logicalops_i1(
; CHECK-NEXT: call void (...) @use(i1 true, i1 false)
; CHECK-NEXT: call void (...) @use(i1 poison, i1 poison)
; CHECK-NEXT: ret void
;
%i1 = or i1 %x, poison
+1 -3
View File
@@ -1,11 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -instsimplify -S | FileCheck %s
; TODO: this should be poison
define i32 @poison(i32 %x) {
; CHECK-LABEL: @poison(
; CHECK-NEXT: ret i32 0
; CHECK-NEXT: ret i32 poison
;
%v = and i32 %x, poison
ret i32 %v
+2 -3
View File
@@ -1,10 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -instsimplify -S | FileCheck %s
; TODO: these should be poison
define i1 @poison(float %x) {
; CHECK-LABEL: @poison(
; CHECK-NEXT: ret i1 false
; CHECK-NEXT: ret i1 poison
;
%v = fcmp oeq float %x, poison
ret i1 %v
@@ -12,7 +11,7 @@ define i1 @poison(float %x) {
define i1 @poison2(float %x) {
; CHECK-LABEL: @poison2(
; CHECK-NEXT: ret i1 true
; CHECK-NEXT: ret i1 poison
;
%v = fcmp ueq float %x, poison
ret i1 %v
+1 -3
View File
@@ -42,11 +42,9 @@ define <2 x i8> @mul_by_0_vec_undef_elt(<2 x i8> %a) {
ret <2 x i8> %b
}
; TODO: this should be poison
define i32 @poison(i32 %x) {
; CHECK-LABEL: @poison(
; CHECK-NEXT: ret i32 0
; CHECK-NEXT: ret i32 poison
;
%v = mul i32 %x, poison
ret i32 %v
+1 -3
View File
@@ -292,11 +292,9 @@ define <2 x i1> @or_with_not_op_commute4(<2 x i1> %a, <2 x i1> %b) {
ret <2 x i1> %r
}
; TODO: this should be poison
define i32 @poison(i32 %x) {
; CHECK-LABEL: @poison(
; CHECK-NEXT: ret i32 -1
; CHECK-NEXT: ret i32 poison
;
%v = or i32 %x, poison
ret i32 %v
@@ -965,8 +965,6 @@ define <vscale x 2 x i1> @ignore_scalable_undef(<vscale x 2 x i1> %cond) {
ret <vscale x 2 x i1> %s
}
; TODO: these can be optimized more
define i32 @poison(i32 %x, i32 %y) {
; CHECK-LABEL: @poison(
; CHECK-NEXT: ret i32 [[X:%.*]]
@@ -977,8 +975,7 @@ define i32 @poison(i32 %x, i32 %y) {
define i32 @poison2(i1 %cond, i32 %x) {
; CHECK-LABEL: @poison2(
; CHECK-NEXT: [[V:%.*]] = select i1 [[COND:%.*]], i32 poison, i32 [[X:%.*]]
; CHECK-NEXT: ret i32 [[V]]
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%v = select i1 %cond, i32 poison, i32 %x
ret i32 %v
@@ -986,8 +983,7 @@ define i32 @poison2(i1 %cond, i32 %x) {
define i32 @poison3(i1 %cond, i32 %x) {
; CHECK-LABEL: @poison3(
; CHECK-NEXT: [[V:%.*]] = select i1 [[COND:%.*]], i32 [[X:%.*]], i32 poison
; CHECK-NEXT: ret i32 [[V]]
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%v = select i1 %cond, i32 %x, i32 poison
ret i32 %v
@@ -995,8 +991,7 @@ define i32 @poison3(i1 %cond, i32 %x) {
define <2 x i32> @poison4(<2 x i1> %cond, <2 x i32> %x) {
; CHECK-LABEL: @poison4(
; CHECK-NEXT: [[V:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i32> [[X:%.*]], <2 x i32> poison
; CHECK-NEXT: ret <2 x i32> [[V]]
; CHECK-NEXT: ret <2 x i32> [[X:%.*]]
;
%v = select <2 x i1> %cond, <2 x i32> %x, <2 x i32> poison
ret <2 x i32> %v
+4 -10
View File
@@ -957,8 +957,7 @@ declare i32 @llvm.cttz.i32(i32, i1 immarg)
; Partial undef scalable vectors should be ignored.
define <vscale x 2 x i1> @ignore_scalable_undef(<vscale x 2 x i1> %cond) {
; CHECK-LABEL: @ignore_scalable_undef(
; CHECK-NEXT: [[S:%.*]] = select <vscale x 2 x i1> [[COND:%.*]], <vscale x 2 x i1> undef, <vscale x 2 x i1> insertelement (<vscale x 2 x i1> undef, i1 true, i32 0)
; CHECK-NEXT: ret <vscale x 2 x i1> [[S]]
; CHECK-NEXT: ret <vscale x 2 x i1> insertelement (<vscale x 2 x i1> undef, i1 true, i32 0)
;
%vec = insertelement <vscale x 2 x i1> undef, i1 true, i32 0
%s = select <vscale x 2 x i1> %cond, <vscale x 2 x i1> undef, <vscale x 2 x i1> %vec
@@ -1036,8 +1035,6 @@ define <2 x i32> @vec_select_no_equivalence(<2 x i32> %x, <2 x i32> %y) {
ret <2 x i32> %s
}
; TODO: these can be optimized more
define i32 @poison(i32 %x, i32 %y) {
; CHECK-LABEL: @poison(
; CHECK-NEXT: ret i32 [[X:%.*]]
@@ -1048,8 +1045,7 @@ define i32 @poison(i32 %x, i32 %y) {
define i32 @poison2(i1 %cond, i32 %x) {
; CHECK-LABEL: @poison2(
; CHECK-NEXT: [[V:%.*]] = select i1 [[COND:%.*]], i32 poison, i32 [[X:%.*]]
; CHECK-NEXT: ret i32 [[V]]
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%v = select i1 %cond, i32 poison, i32 %x
ret i32 %v
@@ -1057,8 +1053,7 @@ define i32 @poison2(i1 %cond, i32 %x) {
define i32 @poison3(i1 %cond, i32 %x) {
; CHECK-LABEL: @poison3(
; CHECK-NEXT: [[V:%.*]] = select i1 [[COND:%.*]], i32 [[X:%.*]], i32 poison
; CHECK-NEXT: ret i32 [[V]]
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%v = select i1 %cond, i32 %x, i32 poison
ret i32 %v
@@ -1066,8 +1061,7 @@ define i32 @poison3(i1 %cond, i32 %x) {
define <2 x i32> @poison4(<2 x i1> %cond, <2 x i32> %x) {
; CHECK-LABEL: @poison4(
; CHECK-NEXT: [[V:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i32> [[X:%.*]], <2 x i32> poison
; CHECK-NEXT: ret <2 x i32> [[V]]
; CHECK-NEXT: ret <2 x i32> [[X:%.*]]
;
%v = select <2 x i1> %cond, <2 x i32> %x, <2 x i32> poison
ret <2 x i32> %v
+3 -5
View File
@@ -262,11 +262,9 @@ define i32 @poison3(i32 %x) {
ret i32 %v
}
; TODO: these should be poison
define i32 @poison4(i32 %x) {
; CHECK-LABEL: @poison4(
; CHECK-NEXT: ret i32 0
; CHECK-NEXT: ret i32 poison
;
%v = lshr i32 poison, %x
ret i32 %v
@@ -274,7 +272,7 @@ define i32 @poison4(i32 %x) {
define i32 @poison5(i32 %x) {
; CHECK-LABEL: @poison5(
; CHECK-NEXT: ret i32 0
; CHECK-NEXT: ret i32 poison
;
%v = ashr i32 poison, %x
ret i32 %v
@@ -282,7 +280,7 @@ define i32 @poison5(i32 %x) {
define i32 @poison6(i32 %x) {
; CHECK-LABEL: @poison6(
; CHECK-NEXT: ret i32 0
; CHECK-NEXT: ret i32 poison
;
%v = shl i32 poison, %x
ret i32 %v
+2 -4
View File
@@ -51,11 +51,9 @@ define <2 x i32> @neg_neg_vec(<2 x i32> %A) {
ret <2 x i32> %C
}
; TODO: these should be poison
define i32 @poison1(i32 %x) {
; CHECK-LABEL: @poison1(
; CHECK-NEXT: ret i32 undef
; CHECK-NEXT: ret i32 poison
;
%v = sub i32 %x, poison
ret i32 %v
@@ -63,7 +61,7 @@ define i32 @poison1(i32 %x) {
define i32 @poison2(i32 %x) {
; CHECK-LABEL: @poison2(
; CHECK-NEXT: ret i32 undef
; CHECK-NEXT: ret i32 poison
;
%v = sub i32 poison, %x
ret i32 %v