[llvm] d0b5523 - [Attributor] Introduce limit for indirect call specialization
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 25 14:36:57 PDT 2023
Author: Johannes Doerfert
Date: 2023-08-25T14:36:42-07:00
New Revision: d0b5523632202c52b29a0b4802e918d6f75e12b2
URL: https://github.com/llvm/llvm-project/commit/d0b5523632202c52b29a0b4802e918d6f75e12b2
DIFF: https://github.com/llvm/llvm-project/commit/d0b5523632202c52b29a0b4802e918d6f75e12b2.diff
LOG: [Attributor] Introduce limit for indirect call specialization
The user can now limit the number of indirect calls specialized for a
given call site with `-attributor-max-specializations-per-call-base=N`
or the AttributorConfig callback. We further attach the `!callee`
metadata if all remaining callees are known.
Added:
Modified:
llvm/include/llvm/Transforms/IPO/Attributor.h
llvm/lib/Transforms/IPO/Attributor.cpp
llvm/lib/Transforms/IPO/AttributorAttributes.cpp
llvm/test/Transforms/Attributor/callgraph.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 0deb91fe02c306..004570344af2f6 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -1417,6 +1417,11 @@ struct AttributorConfig {
std::function<void(Attributor &A, const Function &F)> InitializationCallback =
nullptr;
+ /// Callback function to determine if an indirect call targets should be made
+ /// direct call targets (with an if-cascade).
+ std::function<bool(Attributor &A, CallBase &CB, Function &AssummedCallee)>
+ IndirectCalleeSpecializationCallback = nullptr;
+
/// Helper to update an underlying call graph and to delete functions.
CallGraphUpdater &CGUpdater;
@@ -1688,6 +1693,15 @@ struct Attributor {
/// Return true if this is a module pass, false otherwise.
bool isModulePass() const { return Configuration.IsModulePass; }
+ /// Return true if we should specialize the call site \b CB for the potential
+ /// callee \p Fn.
+ bool shouldSpecializeCallSiteForCallee(CallBase &CB, Function &Callee) {
+ return Configuration.IndirectCalleeSpecializationCallback
+ ? Configuration.IndirectCalleeSpecializationCallback(*this, CB,
+ Callee)
+ : true;
+ }
+
/// Return true if we derive attributes for \p Fn
bool isRunOn(Function &Fn) const { return isRunOn(&Fn); }
bool isRunOn(Function *Fn) const {
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 892502ac034a52..52d2921fd11a95 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CallGraph.h"
@@ -50,6 +51,7 @@
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Local.h"
#include <cstdint>
+#include <memory>
#ifdef EXPENSIVE_CHECKS
#include "llvm/IR/Verifier.h"
@@ -93,6 +95,13 @@ static cl::opt<unsigned>
cl::desc("Maximal number of fixpoint iterations."),
cl::init(32));
+static cl::opt<unsigned>
+ MaxSpecializationPerCB("attributor-max-specializations-per-call-base",
+ cl::Hidden,
+ cl::desc("Maximal number of callees specialized for "
+ "a call base"),
+ cl::init(UINT32_MAX));
+
static cl::opt<unsigned, true> MaxInitializationChainLengthX(
"attributor-max-initialization-chain-length", cl::Hidden,
cl::desc(
@@ -3738,6 +3747,25 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache,
AttributorConfig AC(CGUpdater);
AC.IsModulePass = IsModulePass;
AC.DeleteFns = DeleteFns;
+
+ /// Tracking callback for specialization of indirect calls.
+ DenseMap<CallBase *, std::unique_ptr<SmallPtrSet<Function *, 8>>>
+ IndirectCalleeTrackingMap;
+ if (MaxSpecializationPerCB.getNumOccurrences()) {
+ AC.IndirectCalleeSpecializationCallback = [&](Attributor &, CallBase &CB,
+ Function &Callee) {
+ if (MaxSpecializationPerCB == 0)
+ return false;
+ auto &Set = IndirectCalleeTrackingMap[&CB];
+ if (!Set)
+ Set = std::make_unique<SmallPtrSet<Function *, 8>>();
+ if (Set->size() >= MaxSpecializationPerCB)
+ return Set->contains(&Callee);
+ Set->insert(&Callee);
+ return true;
+ };
+ }
+
Attributor A(Functions, InfoCache, AC);
// Create shallow wrappers for all functions that are not IPO amendable
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 0669772af40435..8c6fa1ab53082e 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/IR/MDBuilder.h"
#include "llvm/Transforms/IPO/Attributor.h"
#include "llvm/ADT/APInt.h"
@@ -12167,9 +12168,19 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
// else ...
// ```
//
+ bool SpecializedForAnyCallees = false;
+ bool SpecializedForAllCallees = AllCalleesKnown;
ICmpInst *LastCmp = nullptr;
+ SmallVector<Function *, 8> SkippedAssumedCallees;
SmallVector<std::pair<CallInst *, Instruction *>> NewCalls;
for (Function *NewCallee : AssumedCallees) {
+ if (!A.shouldSpecializeCallSiteForCallee(*CB, *NewCallee)) {
+ SkippedAssumedCallees.push_back(NewCallee);
+ SpecializedForAllCallees = false;
+ continue;
+ }
+ SpecializedForAnyCallees = true;
+
LastCmp = new ICmpInst(IP, llvm::CmpInst::ICMP_EQ, FP, NewCallee);
Instruction *ThenTI =
SplitBlockAndInsertIfThen(LastCmp, IP, /* Unreachable */ false);
@@ -12198,8 +12209,20 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
NewCalls.push_back({NewCall, RetBC});
}
+ auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {
+ if (!AllCalleesKnown)
+ return ChangeStatus::UNCHANGED;
+ MDBuilder MDB(IndirectCB.getContext());
+ MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);
+ IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);
+ return ChangeStatus::CHANGED;
+ };
+
+ if (!SpecializedForAnyCallees)
+ return AttachCalleeMetadata(*CB);
+
// Check if we need the fallback indirect call still.
- if (AllCalleesKnown) {
+ if (SpecializedForAllCallees) {
LastCmp->replaceAllUsesWith(ConstantInt::getTrue(LastCmp->getContext()));
LastCmp->eraseFromParent();
new UnreachableInst(IP->getContext(), IP);
@@ -12209,6 +12232,7 @@ struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {
CBClone->setName(CB->getName());
CBClone->insertBefore(IP);
NewCalls.push_back({CBClone, nullptr});
+ AttachCalleeMetadata(*CBClone);
}
// Check if we need a PHI to merge the results.
diff --git a/llvm/test/Transforms/Attributor/callgraph.ll b/llvm/test/Transforms/Attributor/callgraph.ll
index 492c17a4aeb341..5904fc364e6e1c 100644
--- a/llvm/test/Transforms/Attributor/callgraph.ll
+++ b/llvm/test/Transforms/Attributor/callgraph.ll
@@ -1,6 +1,8 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -passes=attributor -S < %s | FileCheck %s --check-prefixes=CHECK
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; RUN: opt -passes=attributor -S < %s | FileCheck %s --check-prefixes=CHECK,UPTO2,UNLIM
; RUN: opt -passes=attributor -attributor-print-call-graph -S -disable-output < %s | FileCheck %s --check-prefixes=DOT
+; RUN: opt -passes=attributor --attributor-max-specializations-per-call-base=2 -S < %s | FileCheck %s --check-prefixes=CHECK,UPTO2,LIMI2
+; RUN: opt -passes=attributor --attributor-max-specializations-per-call-base=0 -S < %s | FileCheck %s --check-prefixes=CHECK,LIMI0
define dso_local void @func1() {
; CHECK-LABEL: @func1(
@@ -37,23 +39,29 @@ define dso_local void @func2() {
define void @func5(i32 %0) {
-; CHECK-LABEL: @func5(
-; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP0:%.*]], 0
-; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], ptr @func4, ptr @func3
-; CHECK-NEXT: [[TMP4:%.*]] = icmp eq ptr [[TMP3]], @func3
-; CHECK-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP6:%.*]]
-; CHECK: 5:
-; CHECK-NEXT: call void @func3()
-; CHECK-NEXT: br label [[TMP9:%.*]]
-; CHECK: 6:
-; CHECK-NEXT: br i1 true, label [[TMP7:%.*]], label [[TMP8:%.*]]
-; CHECK: 7:
-; CHECK-NEXT: call void @func4()
-; CHECK-NEXT: br label [[TMP9]]
-; CHECK: 8:
-; CHECK-NEXT: unreachable
-; CHECK: 9:
-; CHECK-NEXT: ret void
+; UPTO2-LABEL: @func5(
+; UPTO2-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP0:%.*]], 0
+; UPTO2-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], ptr @func4, ptr @func3
+; UPTO2-NEXT: [[TMP4:%.*]] = icmp eq ptr [[TMP3]], @func3
+; UPTO2-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP6:%.*]]
+; UPTO2: 5:
+; UPTO2-NEXT: call void @func3()
+; UPTO2-NEXT: br label [[TMP9:%.*]]
+; UPTO2: 6:
+; UPTO2-NEXT: br i1 true, label [[TMP7:%.*]], label [[TMP8:%.*]]
+; UPTO2: 7:
+; UPTO2-NEXT: call void @func4()
+; UPTO2-NEXT: br label [[TMP9]]
+; UPTO2: 8:
+; UPTO2-NEXT: unreachable
+; UPTO2: 9:
+; UPTO2-NEXT: ret void
+;
+; LIMI0-LABEL: @func5(
+; LIMI0-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP0:%.*]], 0
+; LIMI0-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], ptr @func4, ptr @func3
+; LIMI0-NEXT: call void [[TMP3]](), !callees !0
+; LIMI0-NEXT: ret void
;
%2 = icmp ne i32 %0, 0
%3 = select i1 %2, ptr @func4, ptr @func3
@@ -80,39 +88,68 @@ declare float @retFloatTakeFloat(float)
declare void @void()
define i32 @non_matching_fp1(i1 %c1, i1 %c2, i1 %c) {
-; CHECK-LABEL: @non_matching_fp1(
-; CHECK-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
-; CHECK-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr @void
-; CHECK-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
-; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @takeI32
-; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
-; CHECK: 2:
-; CHECK-NEXT: [[CALL1:%.*]] = call i32 @takeI32(i32 42)
-; CHECK-NEXT: br label [[TMP15:%.*]]
-; CHECK: 3:
-; CHECK-NEXT: [[TMP4:%.*]] = icmp eq ptr [[FP]], @retI32
-; CHECK-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP6:%.*]]
-; CHECK: 5:
-; CHECK-NEXT: [[CALL2:%.*]] = call i32 @retI32(i32 42)
-; CHECK-NEXT: br label [[TMP15]]
-; CHECK: 6:
-; CHECK-NEXT: [[TMP7:%.*]] = icmp eq ptr [[FP]], @void
-; CHECK-NEXT: br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP9:%.*]]
-; CHECK: 8:
-; CHECK-NEXT: [[CALL3:%.*]] = call i32 @void(i32 42)
-; CHECK-NEXT: br label [[TMP15]]
-; CHECK: 9:
-; CHECK-NEXT: br i1 true, label [[TMP10:%.*]], label [[TMP14:%.*]]
-; CHECK: 10:
-; CHECK-NEXT: [[TMP11:%.*]] = bitcast i32 42 to float
-; CHECK-NEXT: [[TMP12:%.*]] = call float @retFloatTakeFloat(float [[TMP11]])
-; CHECK-NEXT: [[TMP13:%.*]] = bitcast float [[TMP12]] to i32
-; CHECK-NEXT: br label [[TMP15]]
-; CHECK: 14:
-; CHECK-NEXT: unreachable
-; CHECK: 15:
-; CHECK-NEXT: [[CALL_PHI:%.*]] = phi i32 [ [[CALL1]], [[TMP2]] ], [ [[CALL2]], [[TMP5]] ], [ [[CALL3]], [[TMP8]] ], [ [[TMP13]], [[TMP10]] ]
-; CHECK-NEXT: ret i32 [[CALL_PHI]]
+; 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 !0
+; 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(
+; LIMI0-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
+; LIMI0-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr @void
+; LIMI0-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
+; LIMI0-NEXT: [[CALL:%.*]] = call i32 [[FP]](i32 42), !callees !1
+; LIMI0-NEXT: ret i32 [[CALL]]
;
%fp1 = select i1 %c1, ptr @retI32, ptr @takeI32
%fp2 = select i1 %c2, ptr @retFloatTakeFloat, ptr @void
@@ -122,32 +159,60 @@ define i32 @non_matching_fp1(i1 %c1, i1 %c2, i1 %c) {
}
define void @non_matching_fp2(i1 %c1, i1 %c2, i1 %c, ptr %unknown) {
-; CHECK-LABEL: @non_matching_fp2(
-; CHECK-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
-; CHECK-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr [[UNKNOWN:%.*]]
-; CHECK-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr [[FP1]], ptr [[FP2]]
-; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @takeI32
-; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
-; CHECK: 2:
-; CHECK-NEXT: call void @takeI32()
-; CHECK-NEXT: br label [[TMP10:%.*]]
-; CHECK: 3:
-; CHECK-NEXT: [[TMP4:%.*]] = icmp eq ptr [[FP]], @retI32
-; CHECK-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP6:%.*]]
-; CHECK: 5:
-; CHECK-NEXT: call void @retI32()
-; CHECK-NEXT: br label [[TMP10]]
-; CHECK: 6:
-; CHECK-NEXT: [[TMP7:%.*]] = icmp eq ptr [[FP]], @retFloatTakeFloat
-; CHECK-NEXT: br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP9:%.*]]
-; CHECK: 8:
-; CHECK-NEXT: call void @retFloatTakeFloat()
-; CHECK-NEXT: br label [[TMP10]]
-; CHECK: 9:
-; CHECK-NEXT: call void [[FP]]()
-; CHECK-NEXT: br label [[TMP10]]
-; CHECK: 10:
-; CHECK-NEXT: ret void
+; UNLIM-LABEL: @non_matching_fp2(
+; UNLIM-NEXT: [[FP1:%.*]] = select i1 [[C1:%.*]], ptr @retI32, ptr @takeI32
+; UNLIM-NEXT: [[FP2:%.*]] = select i1 [[C2:%.*]], ptr @retFloatTakeFloat, ptr [[UNKNOWN:%.*]]
+; 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: call void @takeI32()
+; UNLIM-NEXT: br label [[TMP10:%.*]]
+; UNLIM: 3:
+; UNLIM-NEXT: [[TMP4:%.*]] = icmp eq ptr [[FP]], @retI32
+; UNLIM-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP6:%.*]]
+; UNLIM: 5:
+; UNLIM-NEXT: call void @retI32()
+; UNLIM-NEXT: br label [[TMP10]]
+; UNLIM: 6:
+; UNLIM-NEXT: [[TMP7:%.*]] = icmp eq ptr [[FP]], @retFloatTakeFloat
+; UNLIM-NEXT: br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP9:%.*]]
+; UNLIM: 8:
+; UNLIM-NEXT: call void @retFloatTakeFloat()
+; UNLIM-NEXT: br label [[TMP10]]
+; UNLIM: 9:
+; UNLIM-NEXT: call void [[FP]]()
+; UNLIM-NEXT: br label [[TMP10]]
+; UNLIM: 10:
+; UNLIM-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
;
%fp1 = select i1 %c1, ptr @retI32, ptr @takeI32
%fp2 = select i1 %c2, ptr @retFloatTakeFloat, ptr %unknown
@@ -157,19 +222,24 @@ define void @non_matching_fp2(i1 %c1, i1 %c2, i1 %c, ptr %unknown) {
}
define i32 @non_matching_unknown(i1 %c, ptr %fn) {
-; CHECK-LABEL: @non_matching_unknown(
-; CHECK-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr @retI32, ptr [[FN:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @retI32
-; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
-; CHECK: 2:
-; CHECK-NEXT: [[CALL1:%.*]] = call i32 @retI32(i32 42)
-; CHECK-NEXT: br label [[TMP4:%.*]]
-; CHECK: 3:
-; CHECK-NEXT: [[CALL2:%.*]] = call i32 [[FP]](i32 42)
-; CHECK-NEXT: br label [[TMP4]]
-; CHECK: 4:
-; CHECK-NEXT: [[CALL_PHI:%.*]] = phi i32 [ [[CALL1]], [[TMP2]] ], [ [[CALL2]], [[TMP3]] ]
-; CHECK-NEXT: ret i32 [[CALL_PHI]]
+; UPTO2-LABEL: @non_matching_unknown(
+; UPTO2-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr @retI32, ptr [[FN:%.*]]
+; UPTO2-NEXT: [[TMP1:%.*]] = icmp eq ptr [[FP]], @retI32
+; UPTO2-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
+; UPTO2: 2:
+; UPTO2-NEXT: [[CALL1:%.*]] = call i32 @retI32(i32 42)
+; UPTO2-NEXT: br label [[TMP4:%.*]]
+; UPTO2: 3:
+; UPTO2-NEXT: [[CALL2:%.*]] = call i32 [[FP]](i32 42)
+; UPTO2-NEXT: br label [[TMP4]]
+; UPTO2: 4:
+; UPTO2-NEXT: [[CALL_PHI:%.*]] = phi i32 [ [[CALL1]], [[TMP2]] ], [ [[CALL2]], [[TMP3]] ]
+; UPTO2-NEXT: ret i32 [[CALL_PHI]]
+;
+; LIMI0-LABEL: @non_matching_unknown(
+; LIMI0-NEXT: [[FP:%.*]] = select i1 [[C:%.*]], ptr @retI32, ptr [[FN:%.*]]
+; LIMI0-NEXT: [[CALL:%.*]] = call i32 [[FP]](i32 42)
+; LIMI0-NEXT: ret i32 [[CALL]]
;
%fp = select i1 %c, ptr @retI32, ptr %fn
%call = call i32 %fp(i32 42)
@@ -195,21 +265,25 @@ define void @func6() {
}
define void @func7(ptr %unknown) {
-; CHECK-LABEL: @func7(
-; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[UNKNOWN:%.*]], @func3
-; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
-; CHECK: 2:
-; CHECK-NEXT: call void @func3()
-; CHECK-NEXT: br label [[TMP6:%.*]]
-; CHECK: 3:
-; CHECK-NEXT: br i1 true, label [[TMP4:%.*]], label [[TMP5:%.*]]
-; CHECK: 4:
-; CHECK-NEXT: call void @func4()
-; CHECK-NEXT: br label [[TMP6]]
-; CHECK: 5:
-; CHECK-NEXT: unreachable
-; CHECK: 6:
-; CHECK-NEXT: ret void
+; UPTO2-LABEL: @func7(
+; UPTO2-NEXT: [[TMP1:%.*]] = icmp eq ptr [[UNKNOWN:%.*]], @func3
+; UPTO2-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP3:%.*]]
+; UPTO2: 2:
+; UPTO2-NEXT: call void @func3()
+; UPTO2-NEXT: br label [[TMP6:%.*]]
+; UPTO2: 3:
+; UPTO2-NEXT: br i1 true, label [[TMP4:%.*]], label [[TMP5:%.*]]
+; UPTO2: 4:
+; UPTO2-NEXT: call void @func4()
+; UPTO2-NEXT: br label [[TMP6]]
+; UPTO2: 5:
+; UPTO2-NEXT: unreachable
+; UPTO2: 6:
+; UPTO2-NEXT: ret void
+;
+; LIMI0-LABEL: @func7(
+; LIMI0-NEXT: call void [[UNKNOWN:%.*]](), !callees !0
+; LIMI0-NEXT: ret void
;
call void %unknown(), !callees !2
ret void
@@ -217,10 +291,20 @@ define void @func7(ptr %unknown) {
; Check there's no crash if something that isn't a function appears in !callees
define void @undef_in_callees() {
-; CHECK-LABEL: @undef_in_callees(
-; CHECK-NEXT: cond.end.i:
-; CHECK-NEXT: call void undef(ptr undef, i32 undef, ptr undef), !callees !2
-; CHECK-NEXT: ret void
+; UNLIM-LABEL: @undef_in_callees(
+; UNLIM-NEXT: cond.end.i:
+; UNLIM-NEXT: call void undef(ptr undef, i32 undef, ptr undef), !callees !2
+; UNLIM-NEXT: ret void
+;
+; 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: 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: ret void
;
cond.end.i:
call void undef(ptr undef, i32 undef, ptr undef), !callees !3
@@ -257,5 +341,21 @@ cond.end.i:
; These ones are added because of the callees metadata.
; DOT-DAG: Node[[FUNC7]] -> Node[[FUNC3]];
; DOT-DAG: Node[[FUNC7]] -> Node[[FUNC4]];
+;.
+; UNLIM: [[META0:![0-9]+]] = !{!1}
+; UNLIM: [[META1:![0-9]+]] = !{i64 0, i1 false}
+; 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}
+;.
+; 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}
+;.
;; 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