Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -14868,7 +14868,7 @@ :: - declare void @llvm.trap() noreturn nounwind + declare void @llvm.trap() cold noreturn nounwind Overview: """"""""" Index: llvm/include/llvm/IR/Intrinsics.td =================================================================== --- llvm/include/llvm/IR/Intrinsics.td +++ llvm/include/llvm/IR/Intrinsics.td @@ -90,6 +90,10 @@ def IntrNoReturn : IntrinsicProperty; +// IntrCold - Calls to this intrinsic are cold. +// Parallels the cold attribute on LLVM IR functions. +def IntrCold : IntrinsicProperty; + // IntrNoduplicate - Calls to this intrinsic cannot be duplicated. // Parallels the noduplicate attribute on LLVM IR functions. def IntrNoDuplicate : IntrinsicProperty; @@ -867,7 +871,7 @@ // def int_flt_rounds : Intrinsic<[llvm_i32_ty]>, GCCBuiltin<"__builtin_flt_rounds">; -def int_trap : Intrinsic<[], [], [IntrNoReturn]>, +def int_trap : Intrinsic<[], [], [IntrNoReturn, IntrCold]>, GCCBuiltin<"__builtin_trap">; def int_debugtrap : Intrinsic<[]>, GCCBuiltin<"__builtin_debugtrap">; Index: llvm/lib/Transforms/IPO/HotColdSplitting.cpp =================================================================== --- llvm/lib/Transforms/IPO/HotColdSplitting.cpp +++ llvm/lib/Transforms/IPO/HotColdSplitting.cpp @@ -98,36 +98,27 @@ return !(isa(I) || isa(I)); } -static bool exceptionHandlingFunctions(const CallInst *CI) { - auto F = CI->getCalledFunction(); - if (!F) - return false; - auto FName = F->getName(); - return FName == "__cxa_begin_catch" || - FName == "__cxa_free_exception" || - FName == "__cxa_allocate_exception" || - FName == "__cxa_begin_catch" || - FName == "__cxa_end_catch"; -} - -static bool unlikelyExecuted(const BasicBlock &BB) { - if (blockEndsInUnreachable(BB)) - return true; +bool unlikelyExecuted(const BasicBlock &BB) { // Exception handling blocks are unlikely executed. if (BB.isEHPad()) return true; + + if (blockEndsInUnreachable(BB)) { + // Calls to noreturn functions are followed by an unreachable inst, but + // the call itself may be warm (e.g. longjmp, or exit). + if (auto *CI = + dyn_cast_or_null(BB.getTerminator()->getPrevNode())) + if (CI->hasFnAttr(Attribute::NoReturn) && !CI->hasFnAttr(Attribute::Cold)) + return false; + return true; + } + for (const Instruction &I : BB) - if (const CallInst *CI = dyn_cast(&I)) { - // The block is cold if it calls functions tagged as cold or noreturn. - if (CI->hasFnAttr(Attribute::Cold) || - CI->hasFnAttr(Attribute::NoReturn) || - exceptionHandlingFunctions(CI)) + if (const CallInst *CI = dyn_cast(&I)) + // The block is cold if it calls a cold function. + if (CI->hasFnAttr(Attribute::Cold)) return true; - // Assume that inline assembly is hot code. - if (isa(CI->getCalledValue())) - return false; - } return false; } Index: llvm/test/Feature/intrinsics.ll =================================================================== --- llvm/test/Feature/intrinsics.ll +++ llvm/test/Feature/intrinsics.ll @@ -70,4 +70,4 @@ } ; CHECK: attributes #0 = { nounwind readnone speculatable } -; CHECK: attributes #1 = { noreturn nounwind } +; CHECK: attributes #1 = { cold noreturn nounwind } Index: llvm/test/Transforms/HotColdSplit/noreturn.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/HotColdSplit/noreturn.ll @@ -0,0 +1,53 @@ +; RUN: opt -hotcoldsplit -S < %s | FileCheck %s + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.14.0" + +%struct.__jmp_buf_tag = type { [8 x i64], i32, %struct.__sigset_t } +%struct.__sigset_t = type { [16 x i64] } + +; Don't outline noreturn calls which aren't explicitly marked cold. + +; CHECK-LABEL: define {{.*}}@foo( +; CHECK-NOT: foo.cold.1 +define void @foo(i32, %struct.__jmp_buf_tag*) { + %3 = icmp eq i32 %0, 0 + tail call void @_Z10sideeffectv() + br i1 %3, label %5, label %4 + +;