forked from OSchip/llvm-project
[ValueTracking] Let isGuaranteedNotToBeUndefOrPoison use canCreateUndefOrPoison
This patch adds support more operations. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D83926
This commit is contained in:
parent
cf11050696
commit
30201d3b61
|
@ -607,7 +607,8 @@ class Value;
|
|||
bool canCreatePoison(const Operator *Op);
|
||||
|
||||
/// Return true if this function can prove that V is never undef value
|
||||
/// or poison value.
|
||||
/// or poison value. If V is an aggregate value or vector, check whether all
|
||||
/// elements (except padding) are not undef or poison.
|
||||
/// Note that this is different from canCreateUndefOrPoison because the
|
||||
/// function assumes Op's operands are not poison/undef.
|
||||
///
|
||||
|
|
|
@ -4779,23 +4779,13 @@ bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V,
|
|||
if (Depth >= MaxDepth)
|
||||
return false;
|
||||
|
||||
// If the value is a freeze instruction, then it can never
|
||||
// be undef or poison.
|
||||
if (isa<FreezeInst>(V))
|
||||
return true;
|
||||
// TODO: Some instructions are guaranteed to return neither undef
|
||||
// nor poison if their arguments are not poison/undef.
|
||||
|
||||
if (auto *A = dyn_cast<Argument>(V)) {
|
||||
// NoUndef does not guarantee that paddings are not undef.
|
||||
if (const auto *A = dyn_cast<Argument>(V)) {
|
||||
if (A->hasAttribute(Attribute::NoUndef))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto *C = dyn_cast<Constant>(V)) {
|
||||
// TODO: We can analyze ConstExpr by opcode to determine if there is any
|
||||
// possibility of poison.
|
||||
if (isa<UndefValue>(C) || isa<ConstantExpr>(C))
|
||||
if (isa<UndefValue>(C))
|
||||
return false;
|
||||
|
||||
if (isa<ConstantInt>(C) || isa<GlobalVariable>(C) || isa<ConstantFP>(V) ||
|
||||
|
@ -4804,9 +4794,6 @@ bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V,
|
|||
|
||||
if (C->getType()->isVectorTy())
|
||||
return !C->containsUndefElement() && !C->containsConstantExpression();
|
||||
|
||||
// TODO: Recursively analyze aggregates or other constants.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Strip cast operations from a pointer value.
|
||||
|
@ -4826,31 +4813,25 @@ bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V,
|
|||
return isGuaranteedNotToBeUndefOrPoison(V, CtxI, DT, Depth + 1);
|
||||
};
|
||||
|
||||
if (auto *I = dyn_cast<Instruction>(V)) {
|
||||
switch (I->getOpcode()) {
|
||||
case Instruction::GetElementPtr: {
|
||||
auto *GEPI = dyn_cast<GetElementPtrInst>(I);
|
||||
if (!GEPI->isInBounds() && llvm::all_of(GEPI->operands(), OpCheck))
|
||||
if (auto *Opr = dyn_cast<Operator>(V)) {
|
||||
// If the value is a freeze instruction, then it can never
|
||||
// be undef or poison.
|
||||
if (isa<FreezeInst>(V))
|
||||
return true;
|
||||
|
||||
if (const auto *CB = dyn_cast<CallBase>(V)) {
|
||||
if (CB->hasRetAttr(Attribute::NoUndef))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case Instruction::FCmp: {
|
||||
auto *FI = dyn_cast<FCmpInst>(I);
|
||||
if (FI->getFastMathFlags().none() &&
|
||||
llvm::all_of(FI->operands(), OpCheck))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case Instruction::BitCast:
|
||||
case Instruction::PHI:
|
||||
case Instruction::ICmp:
|
||||
if (llvm::all_of(I->operands(), OpCheck))
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (canCreateUndefOrPoison(Opr))
|
||||
return false;
|
||||
|
||||
if (all_of(Opr->operands(), OpCheck))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto *I = dyn_cast<Instruction>(V)) {
|
||||
if (programUndefinedIfPoison(I) && I->getType()->isIntegerTy(1))
|
||||
// Note: once we have an agreement that poison is a value-wise concept,
|
||||
// we can remove the isIntegerTy(1) constraint.
|
||||
|
|
|
@ -106,12 +106,11 @@ define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) {
|
|||
; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[T1]], [[T0_FROZEN]]
|
||||
; CHECK-NEXT: [[T3_DECOMPOSED:%.*]] = sub i32 [[X_FROZEN]], [[TMP1]]
|
||||
; CHECK-NEXT: [[T3_DECOMPOSED_FROZEN:%.*]] = freeze i32 [[T3_DECOMPOSED]]
|
||||
; CHECK-NEXT: [[Y_FROZEN:%.*]] = freeze i32 [[Y]]
|
||||
; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_DECOMPOSED_FROZEN]], [[Y_FROZEN]]
|
||||
; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_DECOMPOSED]], [[Y_FROZEN]]
|
||||
; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[T4]], [[Y_FROZEN]]
|
||||
; CHECK-NEXT: [[T6_DECOMPOSED:%.*]] = sub i32 [[T3_DECOMPOSED_FROZEN]], [[TMP2]]
|
||||
; CHECK-NEXT: [[T6_DECOMPOSED:%.*]] = sub i32 [[T3_DECOMPOSED]], [[TMP2]]
|
||||
; CHECK-NEXT: ret i32 [[T6_DECOMPOSED]]
|
||||
;
|
||||
%t0 = mul nsw i32 %Z, %Y
|
||||
|
|
|
@ -175,12 +175,11 @@ define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) {
|
|||
; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[T1]], [[T0_FROZEN]]
|
||||
; CHECK-NEXT: [[T3_DECOMPOSED:%.*]] = sub i32 [[X_FROZEN]], [[TMP1]]
|
||||
; CHECK-NEXT: [[T3_DECOMPOSED_FROZEN:%.*]] = freeze i32 [[T3_DECOMPOSED]]
|
||||
; CHECK-NEXT: [[Y_FROZEN:%.*]] = freeze i32 [[Y]]
|
||||
; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_DECOMPOSED_FROZEN]], [[Y_FROZEN]]
|
||||
; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_DECOMPOSED]], [[Y_FROZEN]]
|
||||
; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[T4]], [[Y_FROZEN]]
|
||||
; CHECK-NEXT: [[T6_DECOMPOSED:%.*]] = sub i32 [[T3_DECOMPOSED_FROZEN]], [[TMP2]]
|
||||
; CHECK-NEXT: [[T6_DECOMPOSED:%.*]] = sub i32 [[T3_DECOMPOSED]], [[TMP2]]
|
||||
; CHECK-NEXT: ret i32 [[T6_DECOMPOSED]]
|
||||
;
|
||||
%t0 = mul nsw i32 %Z, %Y
|
||||
|
|
|
@ -19,12 +19,10 @@ define i1 @icmp(i8 noundef %x, i8 noundef %y) {
|
|||
ret i1 %f
|
||||
}
|
||||
|
||||
; TODO: should look into binary operations
|
||||
define i1 @or(i1 noundef %x, i1 noundef %x2) {
|
||||
; CHECK-LABEL: @or(
|
||||
; CHECK-NEXT: [[Y:%.*]] = or i1 [[X:%.*]], [[X2:%.*]]
|
||||
; CHECK-NEXT: [[Z:%.*]] = freeze i1 [[Y]]
|
||||
; CHECK-NEXT: ret i1 [[Z]]
|
||||
; CHECK-NEXT: ret i1 [[Y]]
|
||||
;
|
||||
%y = or i1 %x, %x2
|
||||
%z = freeze i1 %y
|
||||
|
@ -42,12 +40,10 @@ define i1 @or2(i1 noundef %x, i1 %x2) {
|
|||
ret i1 %z
|
||||
}
|
||||
|
||||
; TODO: should look into binary operations
|
||||
define i8 @add(i8 noundef %x) {
|
||||
; CHECK-LABEL: @add(
|
||||
; CHECK-NEXT: [[Y:%.*]] = add i8 [[X:%.*]], 1
|
||||
; CHECK-NEXT: [[Z:%.*]] = freeze i8 [[Y]]
|
||||
; CHECK-NEXT: ret i8 [[Z]]
|
||||
; CHECK-NEXT: ret i8 [[Y]]
|
||||
;
|
||||
%y = add i8 %x, 1
|
||||
%z = freeze i8 %y
|
||||
|
@ -77,21 +73,18 @@ define {i8, i32} @aggr({i8, i32} noundef %x) {
|
|||
define i32 @extract({i8, i32} noundef %x) {
|
||||
; CHECK-LABEL: @extract(
|
||||
; CHECK-NEXT: [[Y:%.*]] = extractvalue { i8, i32 } [[X:%.*]], 1
|
||||
; CHECK-NEXT: [[Z:%.*]] = freeze i32 [[Y]]
|
||||
; CHECK-NEXT: ret i32 [[Z]]
|
||||
; CHECK-NEXT: ret i32 [[Y]]
|
||||
;
|
||||
%y = extractvalue {i8, i32} %x, 1
|
||||
%z = freeze i32 %y
|
||||
ret i32 %z
|
||||
}
|
||||
|
||||
; TODO: should look into extract operations
|
||||
define i32 @extract2({i8, {i8, i32}} noundef %x) {
|
||||
; CHECK-LABEL: @extract2(
|
||||
; CHECK-NEXT: [[Y:%.*]] = extractvalue { i8, { i8, i32 } } [[X:%.*]], 1
|
||||
; CHECK-NEXT: [[Z:%.*]] = extractvalue { i8, i32 } [[Y]], 1
|
||||
; CHECK-NEXT: [[W:%.*]] = freeze i32 [[Z]]
|
||||
; CHECK-NEXT: ret i32 [[W]]
|
||||
; CHECK-NEXT: ret i32 [[Z]]
|
||||
;
|
||||
%y = extractvalue {i8, {i8, i32}} %x, 1
|
||||
%z = extractvalue {i8, i32} %y, 1
|
||||
|
|
|
@ -116,13 +116,28 @@ define <2 x float> @constvector_FP_noopt() {
|
|||
|
||||
define float @constant_expr() {
|
||||
; CHECK-LABEL: @constant_expr(
|
||||
; CHECK-NEXT: [[R:%.*]] = freeze float bitcast (i32 ptrtoint (i16* @g to i32) to float)
|
||||
; CHECK-NEXT: ret float [[R]]
|
||||
; CHECK-NEXT: ret float bitcast (i32 ptrtoint (i16* @g to i32) to float)
|
||||
;
|
||||
%r = freeze float bitcast (i32 ptrtoint (i16* @g to i32) to float)
|
||||
ret float %r
|
||||
}
|
||||
|
||||
define i8* @constant_expr2() {
|
||||
; CHECK-LABEL: @constant_expr2(
|
||||
; CHECK-NEXT: ret i8* bitcast (i16* @g to i8*)
|
||||
;
|
||||
%r = freeze i8* bitcast (i16* @g to i8*)
|
||||
ret i8* %r
|
||||
}
|
||||
|
||||
define i32* @constant_expr3() {
|
||||
; CHECK-LABEL: @constant_expr3(
|
||||
; CHECK-NEXT: ret i32* getelementptr (i32, i32* @glb, i64 3)
|
||||
;
|
||||
%r = freeze i32* getelementptr (i32, i32* @glb, i64 3)
|
||||
ret i32* %r
|
||||
}
|
||||
|
||||
; Negative test
|
||||
|
||||
define <2 x i31> @vector_element_constant_expr() {
|
||||
|
@ -136,7 +151,7 @@ define <2 x i31> @vector_element_constant_expr() {
|
|||
|
||||
define void @alloca() {
|
||||
; CHECK-LABEL: @alloca(
|
||||
; CHECK-NEXT: [[P:%.*]] = alloca i8
|
||||
; CHECK-NEXT: [[P:%.*]] = alloca i8, align 1
|
||||
; CHECK-NEXT: call void @f3(i8* [[P]])
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
@ -148,7 +163,7 @@ define void @alloca() {
|
|||
|
||||
define i8* @gep() {
|
||||
; CHECK-LABEL: @gep(
|
||||
; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8]
|
||||
; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8], align 1
|
||||
; CHECK-NEXT: [[Q:%.*]] = getelementptr [4 x i8], [4 x i8]* [[P]], i32 0, i32 6
|
||||
; CHECK-NEXT: ret i8* [[Q]]
|
||||
;
|
||||
|
@ -171,7 +186,7 @@ define i8* @gep_noopt(i32 %arg) {
|
|||
|
||||
define i8* @gep_inbounds() {
|
||||
; CHECK-LABEL: @gep_inbounds(
|
||||
; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8]
|
||||
; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8], align 1
|
||||
; CHECK-NEXT: [[Q:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[P]], i32 0, i32 0
|
||||
; CHECK-NEXT: ret i8* [[Q]]
|
||||
;
|
||||
|
@ -183,7 +198,7 @@ define i8* @gep_inbounds() {
|
|||
|
||||
define i8* @gep_inbounds_noopt(i32 %arg) {
|
||||
; CHECK-LABEL: @gep_inbounds_noopt(
|
||||
; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8]
|
||||
; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8], align 1
|
||||
; CHECK-NEXT: [[Q:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[P]], i32 0, i32 [[ARG:%.*]]
|
||||
; CHECK-NEXT: [[Q2:%.*]] = freeze i8* [[Q]]
|
||||
; CHECK-NEXT: ret i8* [[Q2]]
|
||||
|
|
Loading…
Reference in New Issue