[llvm] [Attributor] Don't specialize an indirect call for a callee that reaches it (PR #217079)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 18 09:51:38 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Larry Meadows (lfmeadow)
<details>
<summary>Changes</summary>
Stacked on #<!-- -->217077, which removes the other kind of arm `manifest()` can build that the indirect call could not have performed. Only the last commit belongs to this PR.
Specializing an indirect call for a callee that can reach the function holding the call site turns an edge that existed only through the function pointer into a direct one, and nothing downstream undoes it.
That is enough to defeat `alwaysinline`. A dispatcher marked `alwaysinline` is written that way so every caller gets its own copy and folds the dispatch away; once it sits in a call graph cycle it cannot be inlined and survives to code generation as a recursive function. On a target without a dynamically sized stack there is then no stack size to state for it — the AMDGPU kernel descriptor carries one fixed per-lane scratch size — so the recursion runs off the end of its scratch slice. In the OpenMP device runtime, where `__kmpc_parallel_60` dispatches to outlined regions and is `alwaysinline` for exactly this reason, nested parallel regions fault with
```
HSA_STATUS_ERROR_MEMORY_APERTURE_VIOLATION: The agent attempted to access
memory beyond the largest legal address.
```
In the new test, `@<!-- -->dispatch` is called with `@<!-- -->outer`, which calls `@<!-- -->dispatch`, and with `@<!-- -->inner`, which does not. Today both become direct calls, closing the cycle:
```llvm
define internal void @<!-- -->dispatch(ptr %fn) {
%1 = icmp eq ptr %fn, @<!-- -->outer
...
call void @<!-- -->outer()
...
call void @<!-- -->inner()
```
With this change only the callee that cannot reach the dispatcher is specialized, and the other stays behind the fallback:
```llvm
define internal void @<!-- -->dispatch(ptr %fn) {
%1 = icmp eq ptr %fn, @<!-- -->inner
...
call void @<!-- -->inner()
...
call void %fn(), !callees !0
```
### Where the question is asked, and of what
It is asked in `updateImpl` and recorded in the AA's state, because queries made during manifestation are forced to pessimistic fixpoints and cannot register a new dependency.
The walk is over `AACallEdges`' optimistic edges, which include callback edges and edges the solver resolved that no user list in the IR spells out. `AAInterFnReachability` answers a broader question — whether control can get from one function to another at all, conservatively true for everything downstream of an unknown callee — and using it here suppressed specialization far past the cycles this is about: `@<!-- -->foo2` in `nounwind.ll` calls a declaration, so it "reaches" every function in the module. Only an edge the call graph agrees is direct can produce the recursion the inliner and the backend then have to live with.
The second half of the new test is a cycle whose only path back to the dispatcher is a callback edge, which an IR walk over direct callers would miss and the solver's edges do not.
`check-llvm` is clean: 46669 passed, 77 expectedly failed, no unexpected failures.
cc @<!-- -->jdoerfert
---
Patch is 42.95 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/217079.diff
5 Files Affected:
- (modified) llvm/lib/Transforms/IPO/AttributorAttributes.cpp (+70-27)
- (modified) llvm/test/Transforms/Attributor/callgraph.ll (+81-326)
- (added) llvm/test/Transforms/Attributor/indirect_call_cycle.ll (+134)
- (added) llvm/test/Transforms/Attributor/indirect_call_signature_mismatch.ll (+57)
- (modified) llvm/test/Transforms/Attributor/nounwind.ll (+49-48)
``````````diff
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 050bc32355253..1d43a479599a1 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -12495,11 +12495,51 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
AllCalleesKnownNow = false;
}
+ // A direct call to a callee that can reach the function holding this call
+ // site closes a call graph cycle that previously existed only through the
+ // function pointer, and nothing downstream undoes that: an alwaysinline
+ // dispatcher stops being inlinable once it is in a cycle, and on a target
+ // without a dynamically sized stack the recursion it leaves behind has no
+ // statically known stack size. Record which callees those are so manifest()
+ // can leave them to the indirect call. The question has to be asked here,
+ // because the solver no longer answers once manifestation starts.
+ //
+ // Only edges the call graph agrees are direct can close such a cycle, so
+ // walk the solver's known edges rather than asking AAInterFnReachability,
+ // which conservatively reaches everything downstream of an unknown callee
+ // and would suppress far more than this.
+ SmallPtrSet<Function *, 4> CalleesReachingCallerNow;
+ if (Function *Caller = CB->getFunction()) {
+ auto KnownEdgesReach = [&](Function *From) {
+ SmallPtrSet<Function *, 16> Visited;
+ SmallVector<Function *, 16> Worklist = {From};
+ while (!Worklist.empty()) {
+ Function *Fn = Worklist.pop_back_val();
+ if (Fn == Caller)
+ return true;
+ if (!Visited.insert(Fn).second)
+ continue;
+ const auto *EdgesAA = A.getAAFor<AACallEdges>(
+ *this, IRPosition::function(*Fn), DepClassTy::REQUIRED);
+ if (!EdgesAA)
+ continue;
+ for (Function *Next : EdgesAA->getOptimisticEdges())
+ Worklist.push_back(Next);
+ }
+ return false;
+ };
+ for (Function *Callee : AssumedCalleesNow)
+ if (Callee == Caller || KnownEdgesReach(Callee))
+ CalleesReachingCallerNow.insert(Callee);
+ }
+
if (AssumedCalleesNow == AssumedCallees &&
- AllCalleesKnown == AllCalleesKnownNow)
+ AllCalleesKnown == AllCalleesKnownNow &&
+ CalleesReachingCallerNow == CalleesReachingCaller)
return ChangeStatus::UNCHANGED;
std::swap(AssumedCallees, AssumedCalleesNow);
+ std::swap(CalleesReachingCaller, CalleesReachingCallerNow);
AllCalleesKnown = AllCalleesKnownNow;
return ChangeStatus::CHANGED;
}
@@ -12524,8 +12564,6 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
bool CBIsVoid = CB->getType()->isVoidTy();
BasicBlock::iterator IP = CB->getIterator();
- FunctionType *CSFT = CB->getFunctionType();
- SmallVector<Value *> CSArgs(CB->args());
// If we know all callees and there are none, the call site is (effectively)
// dead (or UB).
@@ -12536,20 +12574,18 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
return ChangeStatus::CHANGED;
}
+ // Callees that can reach the function holding this call site were recorded
+ // during the update; see there for why they are left to the indirect call.
+ auto ReachesCaller = [&](Function *Callee) {
+ return CalleesReachingCaller.contains(Callee);
+ };
+
// Special handling for the single callee case.
- if (AllCalleesKnown && AssumedCallees.size() == 1) {
- auto *NewCallee = AssumedCallees.front();
- if (isLegalToPromote(*CB, NewCallee)) {
- promoteCall(*CB, NewCallee, nullptr);
- NumIndirectCallsPromoted++;
- return ChangeStatus::CHANGED;
- }
- Instruction *NewCall =
- CallInst::Create(FunctionCallee(CSFT, NewCallee), CSArgs,
- CB->getName(), CB->getIterator());
- if (!CBIsVoid)
- A.changeAfterManifest(IRPosition::callsite_returned(*CB), *NewCall);
- A.deleteAfterManifest(*CB);
+ if (AllCalleesKnown && AssumedCallees.size() == 1 &&
+ isLegalToPromote(*CB, AssumedCallees.front()) &&
+ !ReachesCaller(AssumedCallees.front())) {
+ promoteCall(*CB, AssumedCallees.front(), nullptr);
+ NumIndirectCallsPromoted++;
return ChangeStatus::CHANGED;
}
@@ -12566,7 +12602,13 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
SmallVector<Function *, 8> SkippedAssumedCallees;
SmallVector<std::pair<CallInst *, Instruction *>> NewCalls;
for (Function *NewCallee : AssumedCallees) {
- if (!A.shouldSpecializeCallSiteForCallee(*this, *CB, *NewCallee,
+ // A callee the call site cannot be promoted to is one it can only reach
+ // in ways that are undefined, so a direct call built from the call site's
+ // own operands would not be the call the indirect call performs. Leave it
+ // to the indirect fallback, which the !callees metadata below still
+ // names.
+ if (!isLegalToPromote(*CB, NewCallee) || ReachesCaller(NewCallee) ||
+ !A.shouldSpecializeCallSiteForCallee(*this, *CB, *NewCallee,
AssumedCallees.size())) {
SkippedAssumedCallees.push_back(NewCallee);
SpecializedForAllCallees = false;
@@ -12593,16 +12635,11 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
ThenTI->replaceUsesOfWith(ElseBB, CBBB);
}
CastInst *RetBC = nullptr;
- CallInst *NewCall = nullptr;
- if (isLegalToPromote(*CB, NewCallee)) {
- auto *CBClone = cast<CallBase>(CB->clone());
- CBClone->insertBefore(ThenTI->getIterator());
- NewCall = &cast<CallInst>(promoteCall(*CBClone, NewCallee, &RetBC));
- NumIndirectCallsPromoted++;
- } else {
- NewCall = CallInst::Create(FunctionCallee(CSFT, NewCallee), CSArgs,
- CB->getName(), ThenTI->getIterator());
- }
+ auto *CBClone = cast<CallBase>(CB->clone());
+ CBClone->insertBefore(ThenTI->getIterator());
+ CallInst *NewCall =
+ &cast<CallInst>(promoteCall(*CBClone, NewCallee, &RetBC));
+ NumIndirectCallsPromoted++;
NewCalls.push_back({NewCall, RetBC});
}
@@ -12691,6 +12728,12 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
/// time.
SmallSetVector<Function *, 4> AssumedCallees;
+ /// The subset of the assumed callees that can reach the function holding this
+ /// call site, so that specializing for them would make a call graph cycle
+ /// explicit. Determined during the update, where reachability can still be
+ /// queried, and only read when manifesting.
+ SmallPtrSet<Function *, 4> CalleesReachingCaller;
+
/// Flag to indicate if all possible callees are in the AssumedCallees set or
/// if there could be others.
bool AllCalleesKnown = true;
diff --git a/llvm/test/Transforms/Attributor/callgraph.ll b/llvm/test/Transforms/Attributor/callgraph.ll
index 84e2c54bd832d..0dd6ac64158d6 100644
--- a/llvm/test/Transforms/Attributor/callgraph.ll
+++ b/llvm/test/Transforms/Attributor/callgraph.ll
@@ -128,61 +128,23 @@ declare float @retFloatTakeFloatFloatNoundef(float, float noundef)
declare void @void()
define i32 @non_matching_fp1(i1 %c1, i1 %c2, i1 %c) {
-; UNLIM-LABEL: @non_matching_fp1(
-; UNLIM-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
-; UNLIM-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, 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 [[TMP15:%.*]]
-; 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 [[TMP15]]
-; UNLIM: 6:
-; UNLIM-NEXT: [[TMP7:%.*]] = icmp eq ptr [[FP]], @void
-; UNLIM-NEXT: br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP9:%.*]]
-; UNLIM: 8:
-; UNLIM-NEXT: [[CALL3:%.*]] = call i32 @void(i32 42)
-; UNLIM-NEXT: br label [[TMP15]]
-; UNLIM: 9:
-; UNLIM-NEXT: br i1 true, label [[TMP10:%.*]], label [[TMP14:%.*]]
-; UNLIM: 10:
-; UNLIM-NEXT: [[TMP11:%.*]] = bitcast i32 42 to float
-; UNLIM-NEXT: [[TMP12:%.*]] = call float @retFloatTakeFloat(float [[TMP11]])
-; UNLIM-NEXT: [[TMP13:%.*]] = bitcast float [[TMP12]] to i32
-; UNLIM-NEXT: br label [[TMP15]]
-; UNLIM: 14:
-; UNLIM-NEXT: unreachable
-; UNLIM: 15:
-; UNLIM-NEXT: [[CALL_PHI:%.*]] = phi i32 [ [[CALL1]], [[TMP2]] ], [ [[CALL2]], [[TMP5]] ], [ [[CALL3]], [[TMP8]] ], [ [[TMP13]], [[TMP10]] ]
-; UNLIM-NEXT: ret i32 [[CALL_PHI]]
-;
-; LIMI2-LABEL: @non_matching_fp1(
-; LIMI2-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
-; LIMI2-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, 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 [[META0:![0-9]+]]
-; 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]]
+; UPTO2-LABEL: @non_matching_fp1(
+; UPTO2-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
+; UPTO2-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr @void
+; UPTO2-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
+; UPTO2-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @retFloatTakeFloat
+; UPTO2-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP6:%.*]]
+; UPTO2: 2:
+; UPTO2-NEXT: [[TMP3:%.*]] = bitcast i32 42 to float
+; UPTO2-NEXT: [[TMP4:%.*]] = call float @retFloatTakeFloat(float [[TMP3]])
+; UPTO2-NEXT: [[TMP5:%.*]] = bitcast float [[TMP4]] to i32
+; UPTO2-NEXT: br label [[TMP7:%.*]]
+; UPTO2: 6:
+; UPTO2-NEXT: [[CALL1:%.*]] = call i32 [[FP]](i32 42), !callees [[META0:![0-9]+]]
+; UPTO2-NEXT: br label [[TMP7]]
+; UPTO2: 7:
+; UPTO2-NEXT: [[CALL_PHI:%.*]] = phi i32 [ [[TMP5]], [[TMP2]] ], [ [[CALL1]], [[TMP6]] ]
+; UPTO2-NEXT: ret i32 [[CALL_PHI]]
;
; LIMI0-LABEL: @non_matching_fp1(
; LIMI0-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
@@ -199,53 +161,12 @@ define i32 @non_matching_fp1(i1 %c1, i1 %c2, i1 %c) {
}
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 [[META1:![0-9]+]]
-; 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]]
+; UPTO2-LABEL: @non_matching_fp1_noundef(
+; UPTO2-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
+; UPTO2-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloatFloatNoundef, ptr @void
+; UPTO2-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
+; UPTO2-NEXT: [[CALL:%.*]] = call i32 [[FP]](i32 42), !callees [[META0]]
+; UPTO2-NEXT: ret i32 [[CALL]]
;
; LIMI0-LABEL: @non_matching_fp1_noundef(
; LIMI0-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
@@ -262,108 +183,38 @@ define i32 @non_matching_fp1_noundef(i1 %c1, i1 %c2, i1 %c) {
}
define void @non_matching_fp2(i1 %c1, i1 %c2, i1 %c, ptr %unknown) {
-; OUNLM-LABEL: @non_matching_fp2(
-; OUNLM-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
-; OUNLM-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr [[UNKNOWN:%.*]]
-; OUNLM-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
-; OUNLM-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @takeI32
-; OUNLM-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
-; OUNLM: 2:
-; OUNLM-NEXT: call void @takeI32()
-; OUNLM-NEXT: br label [[TMP10:%.*]]
-; OUNLM: 3:
-; OUNLM-NEXT: [[TMP4:%.*]] = icmp eq ptr [[FP]], @retI32
-; OUNLM-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP6:%.*]]
-; OUNLM: 5:
-; OUNLM-NEXT: call void @retI32()
-; OUNLM-NEXT: br label [[TMP10]]
-; OUNLM: 6:
-; OUNLM-NEXT: [[TMP7:%.*]] = icmp eq ptr [[FP]], @retFloatTakeFloat
-; OUNLM-NEXT: br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP9:%.*]]
-; OUNLM: 8:
-; OUNLM-NEXT: call void @retFloatTakeFloat()
-; OUNLM-NEXT: br label [[TMP10]]
-; OUNLM: 9:
-; OUNLM-NEXT: call void [[FP]]()
-; OUNLM-NEXT: br label [[TMP10]]
-; OUNLM: 10:
-; OUNLM-NEXT: ret void
-;
-; LIMI2-LABEL: @non_matching_fp2(
-; LIMI2-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
-; LIMI2-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr [[UNKNOWN:%.*]]
-; 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: call void @takeI32()
-; 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: call void @retI32()
-; LIMI2-NEXT: br label [[TMP7]]
-; LIMI2: 6:
-; LIMI2-NEXT: call void [[FP]]()
-; LIMI2-NEXT: br label [[TMP7]]
-; LIMI2: 7:
-; LIMI2-NEXT: ret void
-;
-; LIMI0-LABEL: @non_matching_fp2(
-; LIMI0-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
-; LIMI0-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr [[UNKNOWN:%.*]]
-; LIMI0-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
-; LIMI0-NEXT: call void [[FP]]()
-; LIMI0-NEXT: ret void
+; OWRDL-LABEL: @non_matching_fp2(
+; OWRDL-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
+; OWRDL-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr [[UNKNOWN:%.*]]
+; OWRDL-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
+; OWRDL-NEXT: call void [[FP]]()
+; OWRDL-NEXT: ret void
;
; CWRLD-LABEL: @non_matching_fp2(
; CWRLD-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
; CWRLD-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr [[UNKNOWN:%.*]]
; CWRLD-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
-; CWRLD-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @takeI32
+; CWRLD-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @func3
; CWRLD-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
; CWRLD: 2:
-; CWRLD-NEXT: call void @takeI32()
+; CWRLD-NEXT: call void @func3()
; CWRLD-NEXT: br label [[TMP21:%.*]]
; CWRLD: 3:
-; CWRLD-NEXT: [[TMP4:%.*]] = icmp eq ptr [[FP]], @retI32
+; CWRLD-NEXT: [[TMP4:%.*]] = icmp eq ptr [[FP]], @func4
; CWRLD-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP6:%.*]]
; CWRLD: 5:
-; CWRLD-NEXT: call void @retI32()
+; CWRLD-NEXT: call void @func4()
; CWRLD-NEXT: br label [[TMP21]]
; CWRLD: 6:
-; CWRLD-NEXT: [[TMP7:%.*]] = icmp eq ptr [[FP]], @func3
+; CWRLD-NEXT: [[TMP7:%.*]] = icmp eq ptr [[FP]], @void
; CWRLD-NEXT: br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP9:%.*]]
; CWRLD: 8:
-; CWRLD-NEXT: call void @func3()
+; CWRLD-NEXT: call void @void()
; CWRLD-NEXT: br label [[TMP21]]
; CWRLD: 9:
-; CWRLD-NEXT: [[TMP10:%.*]] = icmp eq ptr [[FP]], @func4
-; CWRLD-NEXT: br i1 [[TMP10]], label [[TMP11:%.*]], label [[TMP12:%.*]]
-; CWRLD: 11:
-; CWRLD-NEXT: call void @func4()
+; CWRLD-NEXT: call void [[FP]](), !callees [[META1:![0-9]+]]
; CWRLD-NEXT: br label [[TMP21]]
-; CWRLD: 12:
-; CWRLD-NEXT: [[TMP13:%.*]] = icmp eq ptr [[FP]], @retFloatTakeFloat
-; CWRLD-NEXT: br i1 [[TMP13]], label [[TMP14:%.*]], label [[TMP15:%.*]]
-; CWRLD: 14:
-; CWRLD-NEXT: call void @retFloatTakeFloat()
-; CWRLD-NEXT: br label [[TMP21]]
-; CWRLD: 15:
-; CWRLD-NEXT: [[TMP16:%.*]] = icmp eq ptr [[FP]], @retFloatTakeFloatFloatNoundef
-; CWRLD-NEXT: br i1 [[TMP16]], label [[TMP17:%.*]], label [[TMP18:%.*]]
-; CWRLD: 17:
-; CWRLD-NEXT: call void @retFloatTakeFloatFloatNoundef()
-; CWRLD-NEXT: br label [[TMP21]]
-; CWRLD: 18:
-; CWRLD-NEXT: br i1 true, label [[TMP19:%.*]], label [[TMP20:%.*]]
-; CWRLD: 19:
-; CWRLD-NEXT: call void @void()
-; CWRLD-NEXT: br label [[TMP21]]
-; CWRLD: 20:
-; CWRLD-NEXT: unreachable
-; CWRLD: 21:
+; CWRLD: 10:
; CWRLD-NEXT: ret void
;
%fp1 = select i1 %c1, ptr @retI32, ptr @takeI32
@@ -374,87 +225,25 @@ define void @non_matching_fp2(i1 %c1, i1 %c2, i1 %c, ptr %unknown) {
}
define i32 @non_matching_unknown(i1 %c, ptr %fn) {
-; OUNLM-LABEL: @non_matching_unknown(
-; OUNLM-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr @retI32, ptr [[FN:%.*]]
-; OUNLM-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @retI32
-; OUNLM-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
-; OUNLM: 2:
-; OUNLM-NEXT: [[CALL1:%.*]] = call i32 @retI32(i32 42)
-; OUNLM-NEXT: br label [[TMP4:%.*]]
-; OUNLM: ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/217079
More information about the llvm-commits
mailing list