Skip to content

Commit a134abf

Browse files
authored
[ValueTracking] Make isGuaranteedNotToBeUndef() more precise (#76160)
Currently isGuaranteedNotToBeUndef() is the same as isGuaranteedNotToBeUndefOrPoison(). This function is used in places where we only care about undef (due to multi-use issues), not poison. Make it more precise by only considering instructions that can create undef (like loads or call), and ignore those that can only create poison. In particular, we can ignore poison-generating flags. This means that inferring more flags has less chance to pessimize other transforms.
1 parent b8df88b commit a134abf

File tree

2 files changed

+52
-33
lines changed

2 files changed

+52
-33
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6560,10 +6560,25 @@ static bool shiftAmountKnownInRange(const Value *ShiftAmount) {
65606560
return Safe;
65616561
}
65626562

6563-
static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly,
6563+
enum class UndefPoisonKind {
6564+
PoisonOnly = (1 << 0),
6565+
UndefOnly = (1 << 1),
6566+
UndefOrPoison = PoisonOnly | UndefOnly,
6567+
};
6568+
6569+
static bool includesPoison(UndefPoisonKind Kind) {
6570+
return (unsigned(Kind) & unsigned(UndefPoisonKind::PoisonOnly)) != 0;
6571+
}
6572+
6573+
static bool includesUndef(UndefPoisonKind Kind) {
6574+
return (unsigned(Kind) & unsigned(UndefPoisonKind::UndefOnly)) != 0;
6575+
}
6576+
6577+
static bool canCreateUndefOrPoison(const Operator *Op, UndefPoisonKind Kind,
65646578
bool ConsiderFlagsAndMetadata) {
65656579

6566-
if (ConsiderFlagsAndMetadata && Op->hasPoisonGeneratingFlagsOrMetadata())
6580+
if (ConsiderFlagsAndMetadata && includesPoison(Kind) &&
6581+
Op->hasPoisonGeneratingFlagsOrMetadata())
65676582
return true;
65686583

65696584
unsigned Opcode = Op->getOpcode();
@@ -6573,7 +6588,7 @@ static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly,
65736588
case Instruction::Shl:
65746589
case Instruction::AShr:
65756590
case Instruction::LShr:
6576-
return !shiftAmountKnownInRange(Op->getOperand(1));
6591+
return includesPoison(Kind) && !shiftAmountKnownInRange(Op->getOperand(1));
65776592
case Instruction::FPToSI:
65786593
case Instruction::FPToUI:
65796594
// fptosi/ui yields poison if the resulting value does not fit in the
@@ -6614,7 +6629,8 @@ static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly,
66146629
return false;
66156630
case Intrinsic::sshl_sat:
66166631
case Intrinsic::ushl_sat:
6617-
return !shiftAmountKnownInRange(II->getArgOperand(1));
6632+
return includesPoison(Kind) &&
6633+
!shiftAmountKnownInRange(II->getArgOperand(1));
66186634
case Intrinsic::fma:
66196635
case Intrinsic::fmuladd:
66206636
case Intrinsic::sqrt:
@@ -6669,15 +6685,16 @@ static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly,
66696685
auto *VTy = cast<VectorType>(Op->getOperand(0)->getType());
66706686
unsigned IdxOp = Op->getOpcode() == Instruction::InsertElement ? 2 : 1;
66716687
auto *Idx = dyn_cast<ConstantInt>(Op->getOperand(IdxOp));
6672-
if (!Idx || Idx->getValue().uge(VTy->getElementCount().getKnownMinValue()))
6673-
return true;
6688+
if (includesPoison(Kind))
6689+
return !Idx ||
6690+
Idx->getValue().uge(VTy->getElementCount().getKnownMinValue());
66746691
return false;
66756692
}
66766693
case Instruction::ShuffleVector: {
66776694
ArrayRef<int> Mask = isa<ConstantExpr>(Op)
66786695
? cast<ConstantExpr>(Op)->getShuffleMask()
66796696
: cast<ShuffleVectorInst>(Op)->getShuffleMask();
6680-
return is_contained(Mask, PoisonMaskElem);
6697+
return includesPoison(Kind) && is_contained(Mask, PoisonMaskElem);
66816698
}
66826699
case Instruction::FNeg:
66836700
case Instruction::PHI:
@@ -6713,17 +6730,17 @@ static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly,
67136730

67146731
bool llvm::canCreateUndefOrPoison(const Operator *Op,
67156732
bool ConsiderFlagsAndMetadata) {
6716-
return ::canCreateUndefOrPoison(Op, /*PoisonOnly=*/false,
6733+
return ::canCreateUndefOrPoison(Op, UndefPoisonKind::UndefOrPoison,
67176734
ConsiderFlagsAndMetadata);
67186735
}
67196736

67206737
bool llvm::canCreatePoison(const Operator *Op, bool ConsiderFlagsAndMetadata) {
6721-
return ::canCreateUndefOrPoison(Op, /*PoisonOnly=*/true,
6738+
return ::canCreateUndefOrPoison(Op, UndefPoisonKind::PoisonOnly,
67226739
ConsiderFlagsAndMetadata);
67236740
}
67246741

6725-
static bool directlyImpliesPoison(const Value *ValAssumedPoison,
6726-
const Value *V, unsigned Depth) {
6742+
static bool directlyImpliesPoison(const Value *ValAssumedPoison, const Value *V,
6743+
unsigned Depth) {
67276744
if (ValAssumedPoison == V)
67286745
return true;
67296746

@@ -6775,14 +6792,11 @@ bool llvm::impliesPoison(const Value *ValAssumedPoison, const Value *V) {
67756792
return ::impliesPoison(ValAssumedPoison, V, /* Depth */ 0);
67766793
}
67776794

6778-
static bool programUndefinedIfUndefOrPoison(const Value *V,
6779-
bool PoisonOnly);
6795+
static bool programUndefinedIfUndefOrPoison(const Value *V, bool PoisonOnly);
67806796

6781-
static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
6782-
AssumptionCache *AC,
6783-
const Instruction *CtxI,
6784-
const DominatorTree *DT,
6785-
unsigned Depth, bool PoisonOnly) {
6797+
static bool isGuaranteedNotToBeUndefOrPoison(
6798+
const Value *V, AssumptionCache *AC, const Instruction *CtxI,
6799+
const DominatorTree *DT, unsigned Depth, UndefPoisonKind Kind) {
67866800
if (Depth >= MaxAnalysisRecursionDepth)
67876801
return false;
67886802

@@ -6797,16 +6811,19 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
67976811
}
67986812

67996813
if (auto *C = dyn_cast<Constant>(V)) {
6814+
if (isa<PoisonValue>(C))
6815+
return !includesPoison(Kind);
6816+
68006817
if (isa<UndefValue>(C))
6801-
return PoisonOnly && !isa<PoisonValue>(C);
6818+
return !includesUndef(Kind);
68026819

68036820
if (isa<ConstantInt>(C) || isa<GlobalVariable>(C) || isa<ConstantFP>(V) ||
68046821
isa<ConstantPointerNull>(C) || isa<Function>(C))
68056822
return true;
68066823

68076824
if (C->getType()->isVectorTy() && !isa<ConstantExpr>(C))
6808-
return (PoisonOnly ? !C->containsPoisonElement()
6809-
: !C->containsUndefOrPoisonElement()) &&
6825+
return (!includesUndef(Kind) ? !C->containsPoisonElement()
6826+
: !C->containsUndefOrPoisonElement()) &&
68106827
!C->containsConstantExpression();
68116828
}
68126829

@@ -6824,8 +6841,7 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
68246841
return true;
68256842

68266843
auto OpCheck = [&](const Value *V) {
6827-
return isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth + 1,
6828-
PoisonOnly);
6844+
return isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth + 1, Kind);
68296845
};
68306846

68316847
if (auto *Opr = dyn_cast<Operator>(V)) {
@@ -6847,14 +6863,16 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
68476863
for (unsigned i = 0; i < Num; ++i) {
68486864
auto *TI = PN->getIncomingBlock(i)->getTerminator();
68496865
if (!isGuaranteedNotToBeUndefOrPoison(PN->getIncomingValue(i), AC, TI,
6850-
DT, Depth + 1, PoisonOnly)) {
6866+
DT, Depth + 1, Kind)) {
68516867
IsWellDefined = false;
68526868
break;
68536869
}
68546870
}
68556871
if (IsWellDefined)
68566872
return true;
6857-
} else if (!canCreateUndefOrPoison(Opr) && all_of(Opr->operands(), OpCheck))
6873+
} else if (!::canCreateUndefOrPoison(Opr, Kind,
6874+
/*ConsiderFlagsAndMetadata*/ true) &&
6875+
all_of(Opr->operands(), OpCheck))
68586876
return true;
68596877
}
68606878

@@ -6864,7 +6882,7 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
68646882
I->hasMetadata(LLVMContext::MD_dereferenceable_or_null))
68656883
return true;
68666884

6867-
if (programUndefinedIfUndefOrPoison(V, PoisonOnly))
6885+
if (programUndefinedIfUndefOrPoison(V, !includesUndef(Kind)))
68686886
return true;
68696887

68706888
// CxtI may be null or a cloned instruction.
@@ -6896,7 +6914,7 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
68966914
if (Cond) {
68976915
if (Cond == V)
68986916
return true;
6899-
else if (PoisonOnly && isa<Operator>(Cond)) {
6917+
else if (!includesUndef(Kind) && isa<Operator>(Cond)) {
69006918
// For poison, we can analyze further
69016919
auto *Opr = cast<Operator>(Cond);
69026920
if (any_of(Opr->operands(),
@@ -6918,20 +6936,22 @@ bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC,
69186936
const Instruction *CtxI,
69196937
const DominatorTree *DT,
69206938
unsigned Depth) {
6921-
return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth, false);
6939+
return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth,
6940+
UndefPoisonKind::UndefOrPoison);
69226941
}
69236942

69246943
bool llvm::isGuaranteedNotToBePoison(const Value *V, AssumptionCache *AC,
69256944
const Instruction *CtxI,
69266945
const DominatorTree *DT, unsigned Depth) {
6927-
return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth, true);
6946+
return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth,
6947+
UndefPoisonKind::PoisonOnly);
69286948
}
69296949

69306950
bool llvm::isGuaranteedNotToBeUndef(const Value *V, AssumptionCache *AC,
69316951
const Instruction *CtxI,
69326952
const DominatorTree *DT, unsigned Depth) {
6933-
// TODO: This is currently equivalent to isGuaranteedNotToBeUndefOrPoison().
6934-
return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth, false);
6953+
return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth,
6954+
UndefPoisonKind::UndefOnly);
69356955
}
69366956

69376957
/// Return true if undefined behavior would provably be executed on the path to

llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,9 +571,8 @@ define i16 @cond_value_may_not_well_defined(i16 %x) {
571571
define i16 @and_elide_poison_flags(i16 noundef %a) {
572572
; CHECK-LABEL: @and_elide_poison_flags(
573573
; CHECK-NEXT: [[X:%.*]] = add nuw i16 [[A:%.*]], 1
574-
; CHECK-NEXT: [[AND:%.*]] = and i16 [[X]], 7
575574
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[X]], 8
576-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i16 [[AND]], i16 24
575+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i16 [[X]], i16 24
577576
; CHECK-NEXT: ret i16 [[SEL]]
578577
;
579578
%x = add nuw i16 %a, 1

0 commit comments

Comments
 (0)