[llvm] e5313ef - [Attributor] Filter potential callees based on `noundef` arguments
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 25 14:36:58 PDT 2023
Author: Johannes Doerfert
Date: 2023-08-25T14:36:43-07:00
New Revision: e5313ef55fc25b74cb9d3cd2bd74eb452274a2f2
URL: https://github.com/llvm/llvm-project/commit/e5313ef55fc25b74cb9d3cd2bd74eb452274a2f2
DIFF: https://github.com/llvm/llvm-project/commit/e5313ef55fc25b74cb9d3cd2bd74eb452274a2f2.diff
LOG: [Attributor] Filter potential callees based on `noundef` arguments
If a potential callee has more arguments than the call site, the values
passed will be `poison`. If the potential callee would exhibit UB for
such `undef` argument, e.g., they are marked `noundef`, we can rule the
potential callee out.
Added:
Modified:
llvm/lib/Analysis/ValueTracking.cpp
llvm/lib/Transforms/IPO/AttributorAttributes.cpp
llvm/test/Transforms/Attributor/callgraph.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 06162c6c3c1823..90b4abe2664427 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7167,6 +7167,8 @@ static bool programUndefinedIfUndefOrPoison(const Value *V,
Begin = Inst->getIterator();
Begin++;
} else if (const auto *Arg = dyn_cast<Argument>(V)) {
+ if (Arg->getParent()->isDeclaration())
+ return false;
BB = &Arg->getParent()->getEntryBlock();
Begin = BB->begin();
} else {
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 8c6fa1ab53082e..79f216bedbc505 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -10230,7 +10230,8 @@ struct AANoUndefFloating : public AANoUndefImpl {
/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A) override {
AANoUndefImpl::initialize(A);
- if (!getState().isAtFixpoint())
+ if (!getState().isAtFixpoint() && getAnchorScope() &&
+ !getAnchorScope()->isDeclaration())
if (Instruction *CtxI = getCtxI())
followUsesInMBEC(*this, A, getState(), *CtxI);
}
@@ -12091,6 +12092,36 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
AssumedCalleesNow.set_union(PotentialCallees);
}
+ // Try to find a reason for \p Fn not to be a potential callee. If none was
+ // found, add it to the assumed callees set.
+ auto CheckPotentialCallee = [&](Function &Fn) {
+ if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))
+ return false;
+
+ auto &CachedResult = FilterResults[&Fn];
+ if (CachedResult.has_value())
+ return CachedResult.value();
+
+ int NumFnArgs = Fn.arg_size();
+ int NumCBArgs = CB->arg_size();
+
+ // Check if any excess argument (which we fill up with poison) is known to
+ // be UB on undef.
+ for (int I = NumCBArgs; I < NumFnArgs; ++I) {
+ bool IsKnown = false;
+ if (AA::hasAssumedIRAttr<Attribute::NoUndef>(
+ A, this, IRPosition::argument(*Fn.getArg(I)),
+ DepClassTy::OPTIONAL, IsKnown)) {
+ if (IsKnown)
+ CachedResult = false;
+ return false;
+ }
+ }
+
+ CachedResult = true;
+ return true;
+ };
+
// Check simplification result, prune known UB callees, also restrict it to
// the !callees set, if present.
for (auto &VAC : Values) {
@@ -12101,7 +12132,7 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
continue;
// TODO: Check for known UB, e.g., poison + noundef.
if (auto *VACFn = dyn_cast<Function>(VAC.getValue())) {
- if (PotentialCallees.empty() || PotentialCallees.count(VACFn))
+ if (CheckPotentialCallee(*VACFn))
AssumedCalleesNow.insert(VACFn);
continue;
}
@@ -12283,6 +12314,9 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
}
private:
+ /// Map to remember filter results.
+ DenseMap<Function *, std::optional<bool>> FilterResults;
+
/// If the !callee metadata was present, this set will contain all potential
/// callees (superset).
SmallSetVector<Function *, 4> PotentialCallees;
diff --git a/llvm/test/Transforms/Attributor/callgraph.ll b/llvm/test/Transforms/Attributor/callgraph.ll
index 5904fc364e6e1c..bc14ac342aeabb 100644
--- a/llvm/test/Transforms/Attributor/callgraph.ll
+++ b/llvm/test/Transforms/Attributor/callgraph.ll
@@ -85,6 +85,8 @@ define i32 @musttailCall(i32 %0) {
declare i32 @retI32()
declare void @takeI32(i32)
declare float @retFloatTakeFloat(float)
+; This callee is always filtered out because of the noundef argument
+declare float @retFloatTakeFloatFloatNoundef(float, float noundef)
declare void @void()
define i32 @non_matching_fp1(i1 %c1, i1 %c2, i1 %c) {
@@ -158,6 +160,69 @@ define i32 @non_matching_fp1(i1 %c1, i1 %c2, i1 %c) {
ret i32 %call
}
+define i32 @non_matching_fp1_noundef(i1 %c1, i1 %c2, i1 %c) {
+; UNLIM-LABEL: @non_matching_fp1_noundef(
+; UNLIM-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
+; UNLIM-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloatFloatNoundef, ptr @void
+; UNLIM-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
+; UNLIM-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @takeI32
+; UNLIM-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
+; UNLIM: 2:
+; UNLIM-NEXT: [[CALL1:%.*]] = call i32 @takeI32(i32 42)
+; UNLIM-NEXT: br label [[TMP9:%.*]]
+; UNLIM: 3:
+; UNLIM-NEXT: [[TMP4:%.*]] = icmp eq ptr [[FP]], @retI32
+; UNLIM-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP6:%.*]]
+; UNLIM: 5:
+; UNLIM-NEXT: [[CALL2:%.*]] = call i32 @retI32(i32 42)
+; UNLIM-NEXT: br label [[TMP9]]
+; UNLIM: 6:
+; UNLIM-NEXT: br i1 true, label [[TMP7:%.*]], label [[TMP8:%.*]]
+; UNLIM: 7:
+; UNLIM-NEXT: [[CALL3:%.*]] = call i32 @void(i32 42)
+; UNLIM-NEXT: br label [[TMP9]]
+; UNLIM: 8:
+; UNLIM-NEXT: unreachable
+; UNLIM: 9:
+; UNLIM-NEXT: [[CALL_PHI:%.*]] = phi i32 [ [[CALL1]], [[TMP2]] ], [ [[CALL2]], [[TMP5]] ], [ [[CALL3]], [[TMP7]] ]
+; UNLIM-NEXT: ret i32 [[CALL_PHI]]
+;
+; LIMI2-LABEL: @non_matching_fp1_noundef(
+; LIMI2-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
+; LIMI2-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloatFloatNoundef, ptr @void
+; LIMI2-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
+; LIMI2-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @takeI32
+; LIMI2-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
+; LIMI2: 2:
+; LIMI2-NEXT: [[CALL1:%.*]] = call i32 @takeI32(i32 42)
+; LIMI2-NEXT: br label [[TMP7:%.*]]
+; LIMI2: 3:
+; LIMI2-NEXT: [[TMP4:%.*]] = icmp eq ptr [[FP]], @retI32
+; LIMI2-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP6:%.*]]
+; LIMI2: 5:
+; LIMI2-NEXT: [[CALL2:%.*]] = call i32 @retI32(i32 42)
+; LIMI2-NEXT: br label [[TMP7]]
+; LIMI2: 6:
+; LIMI2-NEXT: [[CALL3:%.*]] = call i32 [[FP]](i32 42), !callees !1
+; LIMI2-NEXT: br label [[TMP7]]
+; LIMI2: 7:
+; LIMI2-NEXT: [[CALL_PHI:%.*]] = phi i32 [ [[CALL1]], [[TMP2]] ], [ [[CALL2]], [[TMP5]] ], [ [[CALL3]], [[TMP6]] ]
+; LIMI2-NEXT: ret i32 [[CALL_PHI]]
+;
+; LIMI0-LABEL: @non_matching_fp1_noundef(
+; LIMI0-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
+; LIMI0-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloatFloatNoundef, ptr @void
+; LIMI0-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
+; LIMI0-NEXT: [[CALL:%.*]] = call i32 [[FP]](i32 42), !callees !2
+; LIMI0-NEXT: ret i32 [[CALL]]
+;
+ %fp1 = select i1 %c1, ptr @retI32, ptr @takeI32
+ %fp2 = select i1 %c2, ptr @retFloatTakeFloatFloatNoundef, ptr @void
+ %fp = select i1 %c, ptr %fp1, ptr %fp2
+ %call = call i32 %fp(i32 42)
+ ret i32 %call
+}
+
define void @non_matching_fp2(i1 %c1, i1 %c2, i1 %c, ptr %unknown) {
; UNLIM-LABEL: @non_matching_fp2(
; UNLIM-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
@@ -298,12 +363,12 @@ define void @undef_in_callees() {
;
; LIMI2-LABEL: @undef_in_callees(
; LIMI2-NEXT: cond.end.i:
-; LIMI2-NEXT: call void undef(ptr undef, i32 undef, ptr undef), !callees !3
+; LIMI2-NEXT: call void undef(ptr undef, i32 undef, ptr undef), !callees !4
; LIMI2-NEXT: ret void
;
; LIMI0-LABEL: @undef_in_callees(
; LIMI0-NEXT: cond.end.i:
-; LIMI0-NEXT: call void undef(ptr undef, i32 undef, ptr undef), !callees !4
+; LIMI0-NEXT: call void undef(ptr undef, i32 undef, ptr undef), !callees !5
; LIMI0-NEXT: ret void
;
cond.end.i:
@@ -347,15 +412,17 @@ cond.end.i:
; UNLIM: [[META2:![0-9]+]] = distinct !{ptr undef, ptr null}
;.
; LIMI2: [[META0:![0-9]+]] = !{ptr @void, ptr @retFloatTakeFloat}
-; LIMI2: [[META1:![0-9]+]] = !{!2}
-; LIMI2: [[META2:![0-9]+]] = !{i64 0, i1 false}
-; LIMI2: [[META3:![0-9]+]] = distinct !{ptr undef, ptr null}
+; LIMI2: [[META1:![0-9]+]] = !{ptr @void}
+; LIMI2: [[META2:![0-9]+]] = !{!3}
+; LIMI2: [[META3:![0-9]+]] = !{i64 0, i1 false}
+; LIMI2: [[META4:![0-9]+]] = distinct !{ptr undef, ptr null}
;.
; LIMI0: [[META0:![0-9]+]] = !{ptr @func3, ptr @func4}
; LIMI0: [[META1:![0-9]+]] = !{ptr @takeI32, ptr @retI32, ptr @void, ptr @retFloatTakeFloat}
-; LIMI0: [[META2:![0-9]+]] = !{!3}
-; LIMI0: [[META3:![0-9]+]] = !{i64 0, i1 false}
-; LIMI0: [[META4:![0-9]+]] = distinct !{ptr undef, ptr null}
+; LIMI0: [[META2:![0-9]+]] = !{ptr @takeI32, ptr @retI32, ptr @void}
+; LIMI0: [[META3:![0-9]+]] = !{!4}
+; LIMI0: [[META4:![0-9]+]] = !{i64 0, i1 false}
+; LIMI0: [[META5:![0-9]+]] = distinct !{ptr undef, ptr null}
;.
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; DOT: {{.*}}
More information about the llvm-commits
mailing list