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 @@ -66,6 +66,12 @@ "specialization"), cl::init(3)); +static cl::opt SmallFunctionThreshold( + "func-specialization-size-threshold", cl::Hidden, + cl::desc("For functions whose IR instruction count below this threshold, " + " they wouldn't be specialized to avoid useless sepcializations."), + cl::init(100)); + static cl::opt AvgLoopIterationCount("func-specialization-avg-iters-cost", cl::Hidden, cl::desc("Average loop iteration count cost"), @@ -340,6 +346,10 @@ if (!Solver.isBlockExecutable(&F->getEntryBlock())) return false; + // It wastes time to specialize a function which would get inlined finally. + if (F->hasFnAttribute(Attribute::AlwaysInline)) + return false; + LLVM_DEBUG(dbgs() << "FnSpecialization: Try function: " << F->getName() << "\n"); @@ -430,7 +440,11 @@ // If the code metrics reveal that we shouldn't duplicate the function, we // shouldn't specialize it. Set the specialization cost to Invalid. - if (Metrics.notDuplicatable) { + // Or if the lines of codes implies that this function is easy to get + // inlined so that we shouldn't specialize it. + if (Metrics.notDuplicatable || + (!ForceFunctionSpecialization && + Metrics.NumInsts < SmallFunctionThreshold)) { InstructionCost C{}; C.setInvalid(); return C; diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-loop.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-always-inline.ll copy from llvm/test/Transforms/FunctionSpecialization/function-specialization-loop.ll copy to llvm/test/Transforms/FunctionSpecialization/function-specialization-always-inline.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization-loop.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-always-inline.ll @@ -1,8 +1,6 @@ -; RUN: opt -function-specialization -func-specialization-avg-iters-cost=3 -S < %s | FileCheck %s +; RUN: opt -function-specialization -func-specialization-avg-iters-cost=3 -func-specialization-size-threshold=10 -S < %s | FileCheck %s -; Check that the loop depth results in a larger specialization bonus. -; CHECK: @foo.1( -; CHECK: @foo.2( +; CHECK-NOT: foo.{{[0-9]+}} target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" @@ -15,7 +13,7 @@ declare i1 @cond_end() declare i1 @getCond() -define internal i32 @foo(i32 %x, i32* %b, i32* %c) { +define internal i32 @foo(i32 %x, i32* %b, i32* %c) alwaysinline { entry: br label %loop.entry diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-integers.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-integers.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-integers.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-integers.ll @@ -1,4 +1,4 @@ -; RUN: opt -function-specialization -function-specialization-for-literal-constant=true -S < %s | FileCheck %s +; RUN: opt -function-specialization -function-specialization-for-literal-constant=true -func-specialization-size-threshold=10 -S < %s | FileCheck %s ; Check that the literal constant parameter could be specialized. ; CHECK: @foo.1( diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-loop.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-loop.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization-loop.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-loop.ll @@ -1,4 +1,4 @@ -; RUN: opt -function-specialization -func-specialization-avg-iters-cost=3 -S < %s | FileCheck %s +; RUN: opt -function-specialization -func-specialization-avg-iters-cost=3 -func-specialization-size-threshold=10 -S < %s | FileCheck %s ; Check that the loop depth results in a larger specialization bonus. ; CHECK: @foo.1( diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-stats.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-stats.ll --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization-stats.ll +++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-stats.ll @@ -1,5 +1,5 @@ ; REQUIRES: asserts -; RUN: opt -stats -function-specialization -S < %s 2>&1 | FileCheck %s +; RUN: opt -stats -function-specialization -S -force-function-specialization < %s 2>&1 | FileCheck %s ; CHECK: 2 function-specialization - Number of functions specialized 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 @@ -1,8 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -function-specialization -deadargelim -S < %s | FileCheck %s -; RUN: opt -function-specialization -func-specialization-max-iters=1 -deadargelim -S < %s | FileCheck %s -; RUN: opt -function-specialization -func-specialization-max-iters=0 -deadargelim -S < %s | FileCheck %s --check-prefix=DISABLED -; RUN: opt -function-specialization -func-specialization-avg-iters-cost=1 -deadargelim -S < %s | FileCheck %s +; RUN: opt -function-specialization -deadargelim -force-function-specialization -S < %s | FileCheck %s +; RUN: opt -function-specialization -func-specialization-max-iters=1 -deadargelim -force-function-specialization -S < %s | FileCheck %s +; RUN: opt -function-specialization -func-specialization-max-iters=0 -deadargelim -force-function-specialization -S < %s | FileCheck %s --check-prefix=DISABLED +; RUN: opt -function-specialization -func-specialization-avg-iters-cost=1 -deadargelim -force-function-specialization -S < %s | FileCheck %s ; DISABLED-NOT: @func.1( ; DISABLED-NOT: @func.2(