Index: llvm/lib/Transforms/IPO/FunctionSpecialization.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ 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; Index: llvm/test/Transforms/FunctionSpecialization/function-specialization-always-inline.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/FunctionSpecialization/function-specialization-always-inline.ll @@ -0,0 +1,61 @@ +; RUN: opt -function-specialization -func-specialization-avg-iters-cost=3 -func-specialization-size-threshold=10 -S < %s | FileCheck %s + +; CHECK-NOT: foo.{{[0-9]+}} + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" + +@A = external dso_local constant i32, align 4 +@B = external dso_local constant i32, align 4 +@C = external dso_local constant i32, align 4 +@D = external dso_local constant i32, align 4 + +declare i1 @cond_begin() +declare i1 @cond_end() +declare i1 @getCond() + +define internal i32 @foo(i32 %x, i32* %b, i32* %c) alwaysinline { +entry: + br label %loop.entry + +loop.entry: + br label %loop2.entry + +loop2.entry: + br label %loop2.body + +loop2.body: + %0 = load i32, i32* %b, align 4 + %1 = load i32, i32* %c, align 4 + %add.0 = add nsw i32 %0, %1 + %add = add nsw i32 %add.0, %x + br label %loop2.end + +loop2.end: + %cond.end = call i1 @cond_end() + br i1 %cond.end, label %loop2.entry, label %loop.end + +loop.end: + %cond2.end = call i1 @getCond() + br i1 %cond2.end, label %loop.entry, label %return + +return: + ret i32 %add +} + +define dso_local i32 @bar(i32 %x, i32 %y) { +entry: + %tobool = icmp ne i32 %x, 0 + br i1 %tobool, label %if.then, label %if.else + +if.then: + %call = call i32 @foo(i32 %x, i32* @A, i32* @C) + br label %return + +if.else: + %call1 = call i32 @foo(i32 %y, i32* @B, i32* @D) + br label %return + +return: + %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.else ] + ret i32 %retval.0 +} \ No newline at end of file Index: llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-integers.ll =================================================================== --- llvm/test/Transforms/FunctionSpecialization/function-specialization-constant-integers.ll +++ 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( Index: llvm/test/Transforms/FunctionSpecialization/function-specialization-loop.ll =================================================================== --- llvm/test/Transforms/FunctionSpecialization/function-specialization-loop.ll +++ 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( Index: llvm/test/Transforms/FunctionSpecialization/function-specialization2.ll =================================================================== --- llvm/test/Transforms/FunctionSpecialization/function-specialization2.ll +++ 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(