diff --git a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h --- a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h +++ b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h @@ -62,16 +62,24 @@ namespace llvm { // Bookkeeping struct to pass data from the analysis and profitability phase // to the actual transform helper functions. -struct SpecializationInfo { +struct SpecInfo { SmallVector Args; // Stores the {formal,actual} argument pairs. InstructionCost Gain; // Profitability: Gain = Bonus - Cost. Function *Clone; // The definition of the specialized function. + + bool operator==(const SpecInfo &Other) const { + if (Args.size() != Other.Args.size()) + return false; + for (size_t I = 0; I < Args.size(); ++I) + if (Args[I] != Other.Args[I]) + return false; + return true; + } + + bool operator!=(const SpecInfo &Other) const { return !(*this == Other); } }; -using CallSpecBinding = std::pair; -// We are using MapVector because it guarantees deterministic iteration -// order across executions. -using SpecializationMap = SmallMapVector; +using UniqueSpecSet = std::set>; class FunctionSpecializer { @@ -140,11 +148,11 @@ /// /// \returns true if any specializations have been found. bool findSpecializations(Function *F, InstructionCost Cost, - SmallVectorImpl &WorkList); + SmallVectorImpl &WorkList); bool isCandidateFunction(Function *F); - Function *createSpecialization(Function *F, CallSpecBinding &Specialization); + Function *createSpecialization(Function *F, SpecInfo &Specialization); /// Compute and return the cost of specializing function \p F. InstructionCost getSpecializationCost(Function *F); @@ -162,8 +170,7 @@ Constant *getCandidateConstant(Value *V); /// Redirects callsites of function \p F to its specialized copies. - void updateCallSites(Function *F, - SmallVectorImpl &Specializations); + void updateCallSites(Function *F, SmallVectorImpl &Specializations); }; } // namespace llvm diff --git a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h --- a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h +++ b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h @@ -50,7 +50,13 @@ Argument *Formal; // The Formal argument being analysed. Constant *Actual; // A corresponding actual constant argument. - ArgInfo(Argument *F, Constant *A) : Formal(F), Actual(A){}; + ArgInfo(Argument *F, Constant *A) : Formal(F), Actual(A) {}; + + bool operator==(const ArgInfo &Other) const { + return Formal == Other.Formal && Actual == Other.Actual; + } + + bool operator!=(const ArgInfo &Other) const { return !(*this == Other); } }; class SCCPInstVisitor; diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp --- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -257,7 +257,7 @@ LLVM_DEBUG(dbgs() << "FnSpecialization: Specialization cost for " << F.getName() << " is " << Cost << "\n"); - SmallVector Specializations; + SmallVector Specializations; if (!findSpecializations(&F, Cost, Specializations)) { LLVM_DEBUG( dbgs() << "FnSpecialization: No possible specializations found\n"); @@ -267,7 +267,7 @@ Changed = true; SmallVector Clones; - for (CallSpecBinding &Specialization : Specializations) + for (SpecInfo &Specialization : Specializations) Clones.push_back(createSpecialization(&F, Specialization)); Solver.solveWhileResolvedUndefsIn(Clones); @@ -326,9 +326,9 @@ /// applying them. /// /// \returns true if any specializations have been found. -bool FunctionSpecializer::findSpecializations( - Function *F, InstructionCost Cost, - SmallVectorImpl &WorkList) { +bool +FunctionSpecializer::findSpecializations(Function *F, InstructionCost Cost, + SmallVectorImpl &WorkList) { // Get a list of interesting arguments. SmallVector Args; for (Argument &Arg : F->args()) @@ -339,7 +339,7 @@ return false; // Find all the call sites for the function. - SpecializationMap Specializations; + UniqueSpecSet UniqueSpecs; for (User *U : F->users()) { if (!isa(U) && !isa(U)) continue; @@ -361,35 +361,24 @@ // Examine arguments and create specialization candidates from call sites // with constant arguments. - bool Added = false; + SpecInfo Spec{{}, 0 - Cost, /*Clone=*/nullptr}; for (Argument *A : Args) { Constant *C = getCandidateConstant(CS.getArgOperand(A->getArgNo())); if (!C) continue; - if (!Added) { - Specializations[&CS] = {{}, 0 - Cost, nullptr}; - Added = true; - } - - SpecializationInfo &S = Specializations.back().second; - S.Gain += getSpecializationBonus(A, C, Solver.getLoopInfo(*F)); - S.Args.push_back({A, C}); + Spec.Gain += getSpecializationBonus(A, C, Solver.getLoopInfo(*F)); + Spec.Args.push_back({A, C}); } - Added = false; + if (!Spec.Args.empty() && (Spec.Gain > 0 || ForceFunctionSpecialization)) + UniqueSpecs.insert(std::move(Spec)); } - // Remove unprofitable specializations. - if (!ForceFunctionSpecialization) - Specializations.remove_if( - [](const auto &Entry) { return Entry.second.Gain <= 0; }); - - // Clear the MapVector and return the underlying vector. - WorkList = Specializations.takeVector(); + WorkList.append(UniqueSpecs.begin(), UniqueSpecs.end()); // Sort the candidates in descending order. llvm::stable_sort(WorkList, [](const auto &L, const auto &R) { - return L.second.Gain > R.second.Gain; + return L.Gain > R.Gain; }); // Truncate the worklist to 'MaxClonesThreshold' candidates if necessary. @@ -403,11 +392,9 @@ LLVM_DEBUG(dbgs() << "FnSpecialization: Specializations for function " << F->getName() << "\n"; - for (const auto &Entry - : WorkList) { - dbgs() << "FnSpecialization: Gain = " << Entry.second.Gain - << "\n"; - for (const ArgInfo &Arg : Entry.second.Args) + for (const SpecInfo &Spec : WorkList) { + dbgs() << "FnSpecialization: Gain = " << Spec.Gain << "\n"; + for (const ArgInfo &Arg : Spec.Args) dbgs() << "FnSpecialization: FormalArg = " << Arg.Formal->getNameOrAsOperand() << ", ActualArg = " << Arg.Actual->getNameOrAsOperand() @@ -452,14 +439,14 @@ Function * FunctionSpecializer::createSpecialization(Function *F, - CallSpecBinding &Specialization) { + SpecInfo &Specialization) { Function *Clone = cloneCandidateFunction(F); - Specialization.second.Clone = Clone; + Specialization.Clone = Clone; // Initialize the lattice state of the arguments of the function clone, // marking the argument on which we specialized the function constant // with the given value. - Solver.markArgInFuncSpecialization(Clone, Specialization.second.Args); + Solver.markArgInFuncSpecialization(Clone, Specialization.Args); Solver.addArgumentTrackedFunction(Clone); Solver.markBlockExecutable(&Clone->front()); @@ -660,7 +647,7 @@ /// Redirects callsites of function \p F to its specialized copies. void FunctionSpecializer::updateCallSites( - Function *F, SmallVectorImpl &Specializations) { + Function *F, SmallVectorImpl &Specializations) { SmallVector ToUpdate; for (User *U : F->users()) { if (auto *CS = dyn_cast(U)) @@ -673,9 +660,9 @@ for (CallBase *CS : ToUpdate) { // Decrement the counter if the callsite is either recursive or updated. bool ShouldDecrementCount = CS->getFunction() == F; - for (CallSpecBinding &Specialization : Specializations) { - Function *Clone = Specialization.second.Clone; - SmallVectorImpl &Args = Specialization.second.Args; + for (SpecInfo &Specialization : Specializations) { + Function *Clone = Specialization.Clone; + SmallVectorImpl &Args = Specialization.Args; if (any_of(Args, [CS, this](const ArgInfo &Arg) { unsigned ArgNo = Arg.Formal->getArgNo(); diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression.ll @@ -30,10 +30,10 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[PLUS:%.*]], label [[MINUS:%.*]] ; CHECK: plus: -; CHECK-NEXT: [[TMP0:%.*]] = call i64 @func2.2(i64* getelementptr inbounds ([[STRUCT:%.*]], %struct* @Global, i32 0, i32 3)) +; CHECK-NEXT: [[TMP0:%.*]] = call i64 @func2.1(i64* getelementptr inbounds ([[STRUCT:%.*]], %struct* @Global, i32 0, i32 3)) ; CHECK-NEXT: br label [[MERGE:%.*]] ; CHECK: minus: -; CHECK-NEXT: [[TMP1:%.*]] = call i64 @func2.1(i64* getelementptr inbounds ([[STRUCT]], %struct* @Global, i32 0, i32 4)) +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @func2.2(i64* getelementptr inbounds ([[STRUCT]], %struct* @Global, i32 0, i32 4)) ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: ; CHECK-NEXT: [[TMP2:%.*]] = phi i64 [ [[TMP0]], [[PLUS]] ], [ [[TMP1]], [[MINUS]] ] diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression3.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression3.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression3.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-expression3.ll @@ -4,8 +4,8 @@ define i32 @main() { ; CHECK-LABEL: @main( ; CHECK-NEXT: bb: -; CHECK-NEXT: tail call void @wombat.1(i8* undef, i64 undef, i64 undef, i32 (i8*, i8*)* bitcast (i32 ()* @quux to i32 (i8*, i8*)*)) -; CHECK-NEXT: tail call void @wombat.2(i8* undef, i64 undef, i64 undef, i32 (i8*, i8*)* bitcast (i32 ()* @eggs to i32 (i8*, i8*)*)) +; CHECK-NEXT: tail call void @wombat.2(i8* undef, i64 undef, i64 undef, i32 (i8*, i8*)* bitcast (i32 ()* @quux to i32 (i8*, i8*)*)) +; CHECK-NEXT: tail call void @wombat.1(i8* undef, i64 undef, i64 undef, i32 (i8*, i8*)* bitcast (i32 ()* @eggs to i32 (i8*, i8*)*)) ; CHECK-NEXT: ret i32 undef ; bb: diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-nonconst-glob.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-nonconst-glob.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization-nonconst-glob.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-nonconst-glob.ll @@ -7,8 +7,8 @@ ; Global B is not constant. We do not specialise on addresses unless we ; enable that: -; ON-ADDRESS: call i32 @foo.1(i32 %x, i32* @A) -; ON-ADDRESS: call i32 @foo.2(i32 %y, i32* @B) +; ON-ADDRESS: call i32 @foo.2(i32 %x, i32* @A) +; ON-ADDRESS: call i32 @foo.1(i32 %y, i32* @B) target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization.ll @@ -6,10 +6,10 @@ ; CHECK: entry: ; CHECK-NEXT: br i1 %flag, label %plus, label %minus ; CHECK: plus: -; CHECK-NEXT: [[TMP0:%.+]] = call i64 @compute.1(i64 %x, i64 (i64)* @plus) +; CHECK-NEXT: [[TMP0:%.+]] = call i64 @compute.2(i64 %x, i64 (i64)* @plus) ; CHECK-NEXT: br label %merge ; CHECK: minus: -; CHECK-NEXT: [[TMP1:%.+]] = call i64 @compute.2(i64 %x, i64 (i64)* @minus) +; CHECK-NEXT: [[TMP1:%.+]] = call i64 @compute.1(i64 %x, i64 (i64)* @minus) ; CHECK-NEXT: br label %merge ; CHECK: merge: ; CHECK-NEXT: [[TMP2:%.+]] = phi i64 [ [[TMP0]], %plus ], [ [[TMP1]], %minus ] @@ -36,13 +36,13 @@ ; ; CHECK-LABEL: define internal i64 @compute.1(i64 %x, i64 (i64)* %binop) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.+]] = call i64 @plus(i64 %x) +; CHECK-NEXT: [[TMP0:%.+]] = call i64 @minus(i64 %x) ; CHECK-NEXT: ret i64 [[TMP0]] ; CHECK-NEXT: } ; ; CHECK-LABEL: define internal i64 @compute.2(i64 %x, i64 (i64)* %binop) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.+]] = call i64 @minus(i64 %x) +; CHECK-NEXT: [[TMP0:%.+]] = call i64 @plus(i64 %x) ; CHECK-NEXT: ret i64 [[TMP0]] ; CHECK-NEXT: } ; diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization2.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization2.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization2.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization2.ll @@ -43,9 +43,9 @@ } define i32 @main(i32* %0, i32 %1) { -; CHECK: call void @func.2(i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; CHECK: call void @func.1(i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) %3 = call i32 @func(i32* %0, i32 %1, void (i32*)* nonnull @increment) -; CHECK: call void @func.1(i32* [[TMP0]], i32 0) +; CHECK: call void @func.2(i32* [[TMP0]], i32 0) %4 = call i32 @func(i32* %0, i32 %3, void (i32*)* nonnull @decrement) ; CHECK: ret i32 0 ret i32 %4 @@ -61,7 +61,7 @@ ; CHECK: [[TMP7:%.*]] = load i32, i32* [[TMP3]], align 4 ; CHECK: [[TMP8:%.*]] = sext i32 [[TMP7]] to i64 ; CHECK: [[TMP9:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP8]] -; CHECK: call void @decrement(i32* [[TMP9]]) +; CHECK: call void @increment(i32* [[TMP9]]) ; CHECK: [[TMP10:%.*]] = load i32, i32* [[TMP3]], align 4 ; CHECK: [[TMP11:%.*]] = add nsw i32 [[TMP10]], -1 ; CHECK: call void @func.1(i32* [[TMP0]], i32 [[TMP11]]) @@ -80,7 +80,7 @@ ; CHECK: [[TMP7:%.*]] = load i32, i32* [[TMP3]], align 4 ; CHECK: [[TMP8:%.*]] = sext i32 [[TMP7]] to i64 ; CHECK: [[TMP9:%.*]] = getelementptr inbounds i32, i32* [[TMP0:%.*]], i64 [[TMP8]] -; CHECK: call void @increment(i32* [[TMP9]]) +; CHECK: call void @decrement(i32* [[TMP9]]) ; CHECK: [[TMP10:%.*]] = load i32, i32* [[TMP3]], align 4 ; CHECK: [[TMP11:%.*]] = add nsw i32 [[TMP10]], -1 ; CHECK: call void @func.2(i32* [[TMP0]], i32 [[TMP11]]) diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization3.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization3.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization3.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization3.ll @@ -14,8 +14,8 @@ define dso_local i32 @bar(i32 %x, i32 %y) { ; COMMON-LABEL: @bar -; FORCE: %call = call i32 @foo.1(i32 %x, i32* @A) -; FORCE: %call1 = call i32 @foo.2(i32 %y, i32* @B) +; FORCE: %call = call i32 @foo.2(i32 %x, i32* @A) +; FORCE: %call1 = call i32 @foo.1(i32 %y, i32* @B) ; DISABLED-NOT: %call1 = call i32 @foo.1( entry: %tobool = icmp ne i32 %x, 0 @@ -38,14 +38,14 @@ ; ; FORCE: define internal i32 @foo.1(i32 %x, i32* %b) { ; FORCE-NEXT: entry: -; FORCE-NEXT: %0 = load i32, i32* @A, align 4 +; FORCE-NEXT: %0 = load i32, i32* @B, align 4 ; FORCE-NEXT: %add = add nsw i32 %x, %0 ; FORCE-NEXT: ret i32 %add ; FORCE-NEXT: } ; ; FORCE: define internal i32 @foo.2(i32 %x, i32* %b) { ; FORCE-NEXT: entry: -; FORCE-NEXT: %0 = load i32, i32* @B, align 4 +; FORCE-NEXT: %0 = load i32, i32* @A, align 4 ; FORCE-NEXT: %add = add nsw i32 %x, %0 ; FORCE-NEXT: ret i32 %add ; FORCE-NEXT: } diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization4.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization4.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization4.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization4.ll @@ -44,18 +44,18 @@ ; CHECK: define internal i32 @foo.1(i32 %x, i32* %b, i32* %c) { ; CHECK-NEXT: entry: -; CHECK-NEXT: %0 = load i32, i32* @A, align 4 +; CHECK-NEXT: %0 = load i32, i32* @B, align 4 ; CHECK-NEXT: %add = add nsw i32 %x, %0 -; CHECK-NEXT: %1 = load i32, i32* @C, align 4 +; CHECK-NEXT: %1 = load i32, i32* @D, align 4 ; CHECK-NEXT: %add1 = add nsw i32 %add, %1 ; CHECK-NEXT: ret i32 %add1 ; CHECK-NEXT: } ; CHECK: define internal i32 @foo.2(i32 %x, i32* %b, i32* %c) { ; CHECK-NEXT: entry: -; CHECK-NEXT: %0 = load i32, i32* @B, align 4 +; CHECK-NEXT: %0 = load i32, i32* @A, align 4 ; CHECK-NEXT: %add = add nsw i32 %x, %0 -; CHECK-NEXT: %1 = load i32, i32* @D, align 4 +; CHECK-NEXT: %1 = load i32, i32* @C, align 4 ; CHECK-NEXT: %add1 = add nsw i32 %add, %1 ; CHECK-NEXT: ret i32 %add1 ; CHECK-NEXT: } diff --git a/llvm/test/Transforms/FunctionSpecialization/identical-specializations.ll b/llvm/test/Transforms/FunctionSpecialization/identical-specializations.ll --- a/llvm/test/Transforms/FunctionSpecialization/identical-specializations.ll +++ b/llvm/test/Transforms/FunctionSpecialization/identical-specializations.ll @@ -6,14 +6,14 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[PLUS:%.*]], label [[MINUS:%.*]] ; CHECK: plus: -; CHECK-NEXT: [[CMP0:%.*]] = call i64 @compute.1(i64 [[X:%.*]], i64 [[Y:%.*]], i64 (i64, i64)* @plus, i64 (i64, i64)* @minus) +; CHECK-NEXT: [[CMP0:%.*]] = call i64 @compute.2(i64 [[X:%.*]], i64 [[Y:%.*]], i64 (i64, i64)* @plus, i64 (i64, i64)* @minus) ; CHECK-NEXT: br label [[MERGE:%.*]] ; CHECK: minus: -; CHECK-NEXT: [[CMP1:%.*]] = call i64 @compute.2(i64 [[X]], i64 [[Y]], i64 (i64, i64)* @minus, i64 (i64, i64)* @plus) +; CHECK-NEXT: [[CMP1:%.*]] = call i64 @compute.1(i64 [[X]], i64 [[Y]], i64 (i64, i64)* @minus, i64 (i64, i64)* @plus) ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: ; CHECK-NEXT: [[PH:%.*]] = phi i64 [ [[CMP0]], [[PLUS]] ], [ [[CMP1]], [[MINUS]] ] -; CHECK-NEXT: [[CMP2:%.*]] = call i64 @compute.1(i64 [[PH]], i64 42, i64 (i64, i64)* @plus, i64 (i64, i64)* @minus) +; CHECK-NEXT: [[CMP2:%.*]] = call i64 @compute.2(i64 [[PH]], i64 42, i64 (i64, i64)* @plus, i64 (i64, i64)* @minus) ; CHECK-NEXT: ret i64 [[CMP2]] ; entry: @@ -60,20 +60,20 @@ ret i64 %sub } -; CHECK-LABEL: @compute.1 -; CHECK-NEXT: entry: -; CHECK-NEXT: [[CMP0:%.*]] = call i64 @plus(i64 [[X:%.*]], i64 [[Y:%.*]]) -; CHECK-NEXT: [[CMP1:%.*]] = call i64 @minus(i64 [[X]], i64 [[Y]]) -; CHECK-NEXT: [[CMP2:%.*]] = call i64 @compute(i64 [[X]], i64 [[Y]], i64 (i64, i64)* @plus, i64 (i64, i64)* @plus) - -; CHECK-LABEL: @compute.2 +; CHECK: define internal i64 @compute.1 ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP0:%.*]] = call i64 @minus(i64 [[X:%.*]], i64 [[Y:%.*]]) ; CHECK-NEXT: [[CMP1:%.*]] = call i64 @plus(i64 [[X]], i64 [[Y]]) -; CHECK-NEXT: [[CMP2:%.*]] = call i64 @compute.2(i64 [[X]], i64 [[Y]], i64 (i64, i64)* @minus, i64 (i64, i64)* @plus) +; CHECK-NEXT: [[CMP2:%.*]] = call i64 @compute.1(i64 [[X]], i64 [[Y]], i64 (i64, i64)* @minus, i64 (i64, i64)* @plus) -; CHECK-LABEL: @compute.3 +; CHECK: define internal i64 @compute.2 ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP0:%.*]] = call i64 @plus(i64 [[X:%.*]], i64 [[Y:%.*]]) ; CHECK-NEXT: [[CMP1:%.*]] = call i64 @minus(i64 [[X]], i64 [[Y]]) -; CHECK-NEXT: [[CMP2:%.*]] = call i64 @compute(i64 [[X]], i64 [[Y]], i64 (i64, i64)* @plus, i64 (i64, i64)* @plus) +; CHECK-NEXT: [[CMP2:%.*]] = call i64 @compute.3(i64 [[X]], i64 [[Y]], i64 (i64, i64)* @plus, i64 (i64, i64)* @plus) + +; CHECK: define internal i64 @compute.3 +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP0:%.*]] = call i64 %binop1(i64 [[X:%.*]], i64 [[Y:%.*]]) +; CHECK-NEXT: [[CMP1:%.*]] = call i64 @plus(i64 [[X]], i64 [[Y]]) +; CHECK-NEXT: [[CMP2:%.*]] = call i64 @compute.3(i64 [[X]], i64 [[Y]], i64 (i64, i64)* %binop1, i64 (i64, i64)* @plus) diff --git a/llvm/test/Transforms/FunctionSpecialization/remove-dead-recursive-function.ll b/llvm/test/Transforms/FunctionSpecialization/remove-dead-recursive-function.ll --- a/llvm/test/Transforms/FunctionSpecialization/remove-dead-recursive-function.ll +++ b/llvm/test/Transforms/FunctionSpecialization/remove-dead-recursive-function.ll @@ -20,13 +20,13 @@ ; CHECK-NOT: define internal i64 @compute( ; ; CHECK-LABEL: define internal i64 @compute.1(i64 %n, i64 (i64)* %binop) { -; CHECK: [[TMP0:%.+]] = call i64 @plus(i64 %n) -; CHECK: [[TMP1:%.+]] = call i64 @compute.1(i64 [[TMP2:%.+]], i64 (i64)* @plus) +; CHECK: [[TMP0:%.+]] = call i64 @minus(i64 %n) +; CHECK: [[TMP1:%.+]] = call i64 @compute.1(i64 [[TMP2:%.+]], i64 (i64)* @minus) ; CHECK: add nsw i64 [[TMP1]], [[TMP0]] ; ; CHECK-LABEL: define internal i64 @compute.2(i64 %n, i64 (i64)* %binop) { -; CHECK: [[TMP0:%.+]] = call i64 @minus(i64 %n) -; CHECK: [[TMP1:%.+]] = call i64 @compute.2(i64 [[TMP2:%.+]], i64 (i64)* @minus) +; CHECK: [[TMP0:%.+]] = call i64 @plus(i64 %n) +; CHECK: [[TMP1:%.+]] = call i64 @compute.2(i64 [[TMP2:%.+]], i64 (i64)* @plus) ; CHECK: add nsw i64 [[TMP1]], [[TMP0]] ; define internal i64 @compute(i64 %n, i64 (i64)* %binop) { diff --git a/llvm/test/Transforms/FunctionSpecialization/specialization-order.ll b/llvm/test/Transforms/FunctionSpecialization/specialization-order.ll --- a/llvm/test/Transforms/FunctionSpecialization/specialization-order.ll +++ b/llvm/test/Transforms/FunctionSpecialization/specialization-order.ll @@ -21,7 +21,7 @@ define dso_local i32 @g0(i32 %x, i32 %y) { ; CHECK-LABEL: @g0 -; CHECK: call i32 @f.2(i32 [[X:%.*]], i32 [[Y:%.*]]) +; CHECK: call i32 @f.1(i32 [[X:%.*]], i32 [[Y:%.*]]) entry: %call = tail call i32 @f(i32 %x, i32 %y, ptr @add, ptr @add) ret i32 %call @@ -30,7 +30,7 @@ define dso_local i32 @g1(i32 %x, i32 %y) { ; CHECK-LABEL: @g1( -; CHECK: call i32 @f.1(i32 [[X:%.*]], i32 [[Y:%.*]]) +; CHECK: call i32 @f.2(i32 [[X:%.*]], i32 [[Y:%.*]]) entry: %call = tail call i32 @f(i32 %x, i32 %y, ptr @sub, ptr @add) ret i32 %call @@ -45,11 +45,11 @@ } ; CHECK-LABEL: define {{.*}} i32 @f.1 -; CHECK: call i32 @sub(i32 %x, i32 %y) +; CHECK: call i32 @add(i32 %x, i32 %y) ; CHECK-NEXT: call i32 @add(i32 %x, i32 %y) ; CHECK-LABEL: define {{.*}} i32 @f.2 -; CHECK: call i32 @add(i32 %x, i32 %y) +; CHECK: call i32 @sub(i32 %x, i32 %y) ; CHECK-NEXT call i32 @add(i32 %x, i32 %y) ; CHECK-LABEL: define {{.*}} i32 @f.3