Index: llvm/lib/Transforms/IPO/FunctionSpecialization.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -433,8 +433,11 @@ ? 1 : getSpecializationBonus(&FormalArg, ActualArg) - Cost; - if (Gain <= 0) + if (Gain <= 0) { + LLVM_DEBUG(dbgs() << "FnSpecialization: Not worth specializing " + << "argument. Gain: " << Gain << "\n"); continue; + } Worklist.push_back({F, &FormalArg, ActualArg, Gain}); } @@ -680,9 +683,9 @@ if (!A->getType()->isSingleValueType() || A->user_empty()) return false; - // If the argument isn't overdefined, there's nothing to do. It should - // already be constant. - if (!Solver.getLatticeValueFor(A).isOverdefined()) { + // If the argument is Constant, there's nothing to do. IPSCCP will + // propagate the argument. + if (isConstant(Solver.getLatticeValueFor(A))) { LLVM_DEBUG(dbgs() << "FnSpecialization: Nothing to do, argument " << A->getNameOrAsOperand() << " is already constant?\n"); @@ -700,7 +703,7 @@ // might be beneficial to take the occurrences into account in the cost // model, so we would need to find the unique constants. // - // TODO 2: this currently does not support constants, i.e. integer ranges. + // TODO 2: this currently does not support constant range arguments. // IsPartial = !getPossibleConstants(A, Constants); LLVM_DEBUG(dbgs() << "FnSpecialization: Found interesting argument " @@ -757,7 +760,7 @@ return false; } - if (isa(V) && (Solver.getLatticeValueFor(V).isConstant() || + if (isa(V) && (isConstant(Solver.getLatticeValueFor(V)) || EnableSpecializationForLiteralConstant)) Constants.push_back(cast(V)); else Index: llvm/test/Transforms/FunctionSpecialization/function-specialization6.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/FunctionSpecialization/function-specialization6.ll @@ -0,0 +1,59 @@ +; RUN: opt -function-specialization -force-function-specialization -S < %s | FileCheck %s + +define i64 @main(i64 %x, i1 %flag) { +; +; CHECK-LABEL: @main(i64 %x, i1 %flag) { +; CHECK: entry: +; CHECK-NEXT: br i1 %flag, label %three, label %four +; CHECK: three: +; CHECK-NEXT: [[TMP0:%.+]] = call i64 @compute.1(i64 3, i64 (i64)* @plus) +; CHECK-NEXT: br label %merge +; CHECK: four: +; CHECK-NEXT: [[TMP1:%.+]] = call i64 @compute.2(i64 4, i64 (i64)* @plus) +; CHECK-NEXT: br label %merge +; CHECK: merge: +; CHECK-NEXT: [[TMP2:%.+]] = phi i64 [ [[TMP0]], %three ], [ [[TMP1]], %four ] +; CHECK-NEXT: ret i64 [[TMP2]] +; CHECK-NEXT: } +; +entry: + br i1 %flag, label %three, label %four + +three: + %tmp0 = call i64 @compute(i64 3, i64 (i64)* @plus) + br label %merge + +four: + %tmp1 = call i64 @compute(i64 4, i64 (i64)* @plus) + br label %merge + +merge: + %tmp2 = phi i64 [ %tmp0, %three ], [ %tmp1, %four] + ret i64 %tmp2 +} + +; CHECK-NOT: define internal i64 @compute( +; +; CHECK-LABEL: define internal i64 @compute.1(i64 %x, i64 (i64)* %binop) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.+]] = call i64 @plus(i64 3) +; 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 @plus(i64 4) +; CHECK-NEXT: ret i64 [[TMP0]] +; CHECK-NEXT: } +; +define internal i64 @compute(i64 %x, i64 (i64)* %binop) { +entry: + %tmp0 = call i64 %binop(i64 %x) + ret i64 %tmp0 +} + +define internal i64 @plus(i64 %x) { +entry: + %tmp0 = add i64 %x, 1 + ret i64 %tmp0 +}