[llvm] [ValueTracking][NFC] Early exit when enumerating guaranteed well-defined/non-poison operands. (PR #82812)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sun Feb 25 09:35:21 PST 2024
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/82812
>From 2b55f513c1b6dd2732cb79a25f3eaf6c5e4d6619 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 23 Feb 2024 19:49:14 +0800
Subject: [PATCH 1/3] [ValueTracking] Early exit when enumerating guaranteed
well-defined/non-poison operands
---
llvm/lib/Analysis/ValueTracking.cpp | 96 ++++++++++++++++++-----------
1 file changed, 60 insertions(+), 36 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 04f317228b3ea7..41ab63dcacfc2b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7211,84 +7211,108 @@ bool llvm::propagatesPoison(const Use &PoisonOp) {
}
}
-void llvm::getGuaranteedWellDefinedOps(
- const Instruction *I, SmallVectorImpl<const Value *> &Operands) {
+/// Enumerates all operands of \p I that are guaranteed to not be undef or
+/// poison. If the callback \p Handle returns true, stop iterating and return
+/// true. Otherwise, return false.
+template <typename CallableT>
+bool foreachGuaranteedWellDefinedOps(const Instruction *I,
+ const CallableT &Handle) {
switch (I->getOpcode()) {
case Instruction::Store:
- Operands.push_back(cast<StoreInst>(I)->getPointerOperand());
+ if (Handle(cast<StoreInst>(I)->getPointerOperand()))
+ return true;
break;
case Instruction::Load:
- Operands.push_back(cast<LoadInst>(I)->getPointerOperand());
+ if (Handle(cast<LoadInst>(I)->getPointerOperand()))
+ return true;
break;
// Since dereferenceable attribute imply noundef, atomic operations
// also implicitly have noundef pointers too
case Instruction::AtomicCmpXchg:
- Operands.push_back(cast<AtomicCmpXchgInst>(I)->getPointerOperand());
+ if (Handle(cast<AtomicCmpXchgInst>(I)->getPointerOperand()))
+ return true;
break;
case Instruction::AtomicRMW:
- Operands.push_back(cast<AtomicRMWInst>(I)->getPointerOperand());
+ if (Handle(cast<AtomicRMWInst>(I)->getPointerOperand()))
+ return true;
break;
case Instruction::Call:
case Instruction::Invoke: {
const CallBase *CB = cast<CallBase>(I);
- if (CB->isIndirectCall())
- Operands.push_back(CB->getCalledOperand());
- for (unsigned i = 0; i < CB->arg_size(); ++i) {
- if (CB->paramHasAttr(i, Attribute::NoUndef) ||
- CB->paramHasAttr(i, Attribute::Dereferenceable) ||
- CB->paramHasAttr(i, Attribute::DereferenceableOrNull))
- Operands.push_back(CB->getArgOperand(i));
- }
+ if (CB->isIndirectCall() && Handle(CB->getCalledOperand()))
+ return true;
+ for (unsigned i = 0; i < CB->arg_size(); ++i)
+ if ((CB->paramHasAttr(i, Attribute::NoUndef) ||
+ CB->paramHasAttr(i, Attribute::Dereferenceable) ||
+ CB->paramHasAttr(i, Attribute::DereferenceableOrNull)) &&
+ Handle(CB->getArgOperand(i)))
+ return true;
break;
}
case Instruction::Ret:
- if (I->getFunction()->hasRetAttribute(Attribute::NoUndef))
- Operands.push_back(I->getOperand(0));
+ if (I->getFunction()->hasRetAttribute(Attribute::NoUndef) &&
+ Handle(I->getOperand(0)))
+ return true;
break;
case Instruction::Switch:
- Operands.push_back(cast<SwitchInst>(I)->getCondition());
+ if (Handle(cast<SwitchInst>(I)->getCondition()))
+ return true;
break;
case Instruction::Br: {
auto *BR = cast<BranchInst>(I);
- if (BR->isConditional())
- Operands.push_back(BR->getCondition());
+ if (BR->isConditional() && Handle(BR->getCondition()))
+ return true;
break;
}
default:
break;
}
+
+ return false;
}
-void llvm::getGuaranteedNonPoisonOps(const Instruction *I,
- SmallVectorImpl<const Value *> &Operands) {
- getGuaranteedWellDefinedOps(I, Operands);
+void llvm::getGuaranteedWellDefinedOps(
+ const Instruction *I, SmallVectorImpl<const Value *> &Operands) {
+ foreachGuaranteedWellDefinedOps(I, [&](const Value *V) {
+ Operands.push_back(V);
+ return false;
+ });
+}
+
+/// Enumerates all operands of \p I that are guaranteed to not be poison.
+template <typename CallableT>
+bool foreachGuaranteedNonPoisonOps(const Instruction *I,
+ const CallableT &Handle) {
+ if (foreachGuaranteedWellDefinedOps(I, Handle))
+ return true;
switch (I->getOpcode()) {
// Divisors of these operations are allowed to be partially undef.
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::URem:
case Instruction::SRem:
- Operands.push_back(I->getOperand(1));
- break;
+ return Handle(I->getOperand(1));
default:
- break;
+ return false;
}
}
+void llvm::getGuaranteedNonPoisonOps(const Instruction *I,
+ SmallVectorImpl<const Value *> &Operands) {
+ foreachGuaranteedNonPoisonOps(I, [&](const Value *V) {
+ Operands.push_back(V);
+ return false;
+ });
+}
+
bool llvm::mustTriggerUB(const Instruction *I,
const SmallPtrSetImpl<const Value *> &KnownPoison) {
- SmallVector<const Value *, 4> NonPoisonOps;
- getGuaranteedNonPoisonOps(I, NonPoisonOps);
-
- for (const auto *V : NonPoisonOps)
- if (KnownPoison.count(V))
- return true;
-
- return false;
+ return foreachGuaranteedNonPoisonOps(
+ I, [&](const Value *V) { return KnownPoison.count(V); });
}
static bool programUndefinedIfUndefOrPoison(const Value *V,
@@ -7331,9 +7355,9 @@ static bool programUndefinedIfUndefOrPoison(const Value *V,
if (--ScanLimit == 0)
break;
- SmallVector<const Value *, 4> WellDefinedOps;
- getGuaranteedWellDefinedOps(&I, WellDefinedOps);
- if (is_contained(WellDefinedOps, V))
+ if (foreachGuaranteedWellDefinedOps(&I, [V](const Value *WellDefinedOp) {
+ return WellDefinedOp == V;
+ }))
return true;
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
>From ec1035a6ad289c61fab16cdc13b4beec324b889c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 24 Feb 2024 03:33:53 +0800
Subject: [PATCH 2/3] [ValueTracking] Rename functions.
---
llvm/lib/Analysis/ValueTracking.cpp | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 41ab63dcacfc2b..fde521b76d7911 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7212,11 +7212,11 @@ bool llvm::propagatesPoison(const Use &PoisonOp) {
}
/// Enumerates all operands of \p I that are guaranteed to not be undef or
-/// poison. If the callback \p Handle returns true, stop iterating and return
+/// poison. If the callback \p Handle returns true, stop processing and return
/// true. Otherwise, return false.
template <typename CallableT>
-bool foreachGuaranteedWellDefinedOps(const Instruction *I,
- const CallableT &Handle) {
+bool handleGuaranteedWellDefinedOps(const Instruction *I,
+ const CallableT &Handle) {
switch (I->getOpcode()) {
case Instruction::Store:
if (Handle(cast<StoreInst>(I)->getPointerOperand()))
@@ -7277,7 +7277,7 @@ bool foreachGuaranteedWellDefinedOps(const Instruction *I,
void llvm::getGuaranteedWellDefinedOps(
const Instruction *I, SmallVectorImpl<const Value *> &Operands) {
- foreachGuaranteedWellDefinedOps(I, [&](const Value *V) {
+ handleGuaranteedWellDefinedOps(I, [&](const Value *V) {
Operands.push_back(V);
return false;
});
@@ -7285,9 +7285,9 @@ void llvm::getGuaranteedWellDefinedOps(
/// Enumerates all operands of \p I that are guaranteed to not be poison.
template <typename CallableT>
-bool foreachGuaranteedNonPoisonOps(const Instruction *I,
- const CallableT &Handle) {
- if (foreachGuaranteedWellDefinedOps(I, Handle))
+bool handleGuaranteedNonPoisonOps(const Instruction *I,
+ const CallableT &Handle) {
+ if (handleGuaranteedWellDefinedOps(I, Handle))
return true;
switch (I->getOpcode()) {
// Divisors of these operations are allowed to be partially undef.
@@ -7303,7 +7303,7 @@ bool foreachGuaranteedNonPoisonOps(const Instruction *I,
void llvm::getGuaranteedNonPoisonOps(const Instruction *I,
SmallVectorImpl<const Value *> &Operands) {
- foreachGuaranteedNonPoisonOps(I, [&](const Value *V) {
+ handleGuaranteedNonPoisonOps(I, [&](const Value *V) {
Operands.push_back(V);
return false;
});
@@ -7311,7 +7311,7 @@ void llvm::getGuaranteedNonPoisonOps(const Instruction *I,
bool llvm::mustTriggerUB(const Instruction *I,
const SmallPtrSetImpl<const Value *> &KnownPoison) {
- return foreachGuaranteedNonPoisonOps(
+ return handleGuaranteedNonPoisonOps(
I, [&](const Value *V) { return KnownPoison.count(V); });
}
@@ -7355,7 +7355,7 @@ static bool programUndefinedIfUndefOrPoison(const Value *V,
if (--ScanLimit == 0)
break;
- if (foreachGuaranteedWellDefinedOps(&I, [V](const Value *WellDefinedOp) {
+ if (handleGuaranteedWellDefinedOps(&I, [V](const Value *WellDefinedOp) {
return WellDefinedOp == V;
}))
return true;
>From b18204a682ca3affe8deffa398470ebcf4e5b331 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 26 Feb 2024 01:33:23 +0800
Subject: [PATCH 3/3] fixup! [ValueTracking] Early exit when enumerating
guaranteed well-defined/non-poison operands
---
llvm/lib/Analysis/ValueTracking.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index fde521b76d7911..c0fde209c00f84 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7215,8 +7215,8 @@ bool llvm::propagatesPoison(const Use &PoisonOp) {
/// poison. If the callback \p Handle returns true, stop processing and return
/// true. Otherwise, return false.
template <typename CallableT>
-bool handleGuaranteedWellDefinedOps(const Instruction *I,
- const CallableT &Handle) {
+static bool handleGuaranteedWellDefinedOps(const Instruction *I,
+ const CallableT &Handle) {
switch (I->getOpcode()) {
case Instruction::Store:
if (Handle(cast<StoreInst>(I)->getPointerOperand()))
@@ -7285,8 +7285,8 @@ void llvm::getGuaranteedWellDefinedOps(
/// Enumerates all operands of \p I that are guaranteed to not be poison.
template <typename CallableT>
-bool handleGuaranteedNonPoisonOps(const Instruction *I,
- const CallableT &Handle) {
+static bool handleGuaranteedNonPoisonOps(const Instruction *I,
+ const CallableT &Handle) {
if (handleGuaranteedWellDefinedOps(I, Handle))
return true;
switch (I->getOpcode()) {
More information about the llvm-commits
mailing list