[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:
1 parent
1b1c8e4a98
commit
5af8bacc94
13 files changed
+74
-59
No files matched your search
@@ -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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user