summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Transforms/IPO/HotColdSplitting.cpp40
-rw-r--r--llvm/test/Transforms/HotColdSplit/eh-pads.ll38
-rw-r--r--llvm/test/Transforms/HotColdSplit/noreturn.ll73
-rw-r--r--llvm/test/Transforms/HotColdSplit/outline-cold-asm.ll27
4 files changed, 148 insertions, 30 deletions
diff --git a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
index 93d2b7550a0..704ddbe6110 100644
--- a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
+++ b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
@@ -26,6 +26,7 @@
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
@@ -98,36 +99,27 @@ bool blockEndsInUnreachable(const BasicBlock &BB) {
return !(isa<ReturnInst>(I) || isa<IndirectBrInst>(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(BasicBlock &BB) {
// Exception handling blocks are unlikely executed.
if (BB.isEHPad())
return true;
- for (const Instruction &I : BB)
- if (const CallInst *CI = dyn_cast<CallInst>(&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))
+
+ // The block is cold if it calls/invokes a cold function.
+ for (Instruction &I : BB)
+ if (auto CS = CallSite(&I))
+ if (CS.hasFnAttr(Attribute::Cold))
return true;
- // Assume that inline assembly is hot code.
- if (isa<InlineAsm>(CI->getCalledValue()))
+ // The block is cold if it has an unreachable terminator, unless it's
+ // preceded by a call to a (possibly warm) noreturn call (e.g. longjmp).
+ if (blockEndsInUnreachable(BB)) {
+ if (auto *CI =
+ dyn_cast_or_null<CallInst>(BB.getTerminator()->getPrevNode()))
+ if (CI->hasFnAttr(Attribute::NoReturn))
return false;
- }
+ return true;
+ }
+
return false;
}
diff --git a/llvm/test/Transforms/HotColdSplit/eh-pads.ll b/llvm/test/Transforms/HotColdSplit/eh-pads.ll
index cf413b480d8..f9b55f32fcf 100644
--- a/llvm/test/Transforms/HotColdSplit/eh-pads.ll
+++ b/llvm/test/Transforms/HotColdSplit/eh-pads.ll
@@ -6,12 +6,6 @@ target triple = "x86_64-apple-macosx10.14.0"
; CHECK-LABEL: define {{.*}}@foo(
; CHECK: landingpad
; CHECK: sideeffect(i32 2)
-
-; CHECK-LABEL: define {{.*}}@foo.cold.1(
-; CHECK: sideeffect(i32 0)
-; CHECK: sideeffect(i32 1)
-; CHECK: sink
-
define void @foo(i32 %cond) personality i8 0 {
entry:
invoke void @llvm.donothing() to label %normal unwind label %exception
@@ -32,6 +26,38 @@ normal:
ret void
}
+; CHECK-LABEL: define {{.*}}@bar(
+; CHECK-NOT: landingpad
+define void @bar(i32 %cond) personality i8 0 {
+entry:
+ br i1 undef, label %exit, label %continue
+
+exit:
+ ret void
+
+continue:
+ invoke void @sink() to label %normal unwind label %exception
+
+exception:
+ ; Note: EH pads are not candidates for region entry points.
+ %cleanup = landingpad i8 cleanup
+ ret void
+
+normal:
+ call void @sideeffect(i32 0)
+ call void @sideeffect(i32 1)
+ ret void
+}
+
+; CHECK-LABEL: define {{.*}}@foo.cold.1(
+; CHECK: sideeffect(i32 0)
+; CHECK: sideeffect(i32 1)
+; CHECK: sink
+
+; CHECK-LABEL: define {{.*}}@bar.cold.1(
+; CHECK: sideeffect(i32 0)
+; CHECK: sideeffect(i32 1)
+
declare void @sideeffect(i32)
declare void @sink() cold
diff --git a/llvm/test/Transforms/HotColdSplit/noreturn.ll b/llvm/test/Transforms/HotColdSplit/noreturn.ll
new file mode 100644
index 00000000000..66de93432b8
--- /dev/null
+++ b/llvm/test/Transforms/HotColdSplit/noreturn.ll
@@ -0,0 +1,73 @@
+; 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
+
+; <label>:4: ; preds = %2
+ tail call void @longjmp(%struct.__jmp_buf_tag* %1, i32 0)
+ unreachable
+
+; <label>:5: ; preds = %2
+ ret void
+}
+
+; Do outline noreturn calls marked cold.
+
+; CHECK-LABEL: define {{.*}}@bar(
+; CHECK: call {{.*}}@bar.cold.1(
+define void @bar(i32) {
+ %2 = icmp eq i32 %0, 0
+ tail call void @_Z10sideeffectv()
+ br i1 %2, label %sink, label %exit
+
+sink:
+ tail call void @_Z10sideeffectv()
+ tail call void @_Z10sideeffectv()
+ tail call void @_Z10sideeffectv()
+ call void @llvm.trap()
+ unreachable
+
+exit:
+ ret void
+}
+
+; Do outline noreturn calls preceded by a cold call.
+
+; CHECK-LABEL: define {{.*}}@baz(
+; CHECK: call {{.*}}@baz.cold.1(
+define void @baz(i32, %struct.__jmp_buf_tag*) {
+ %3 = icmp eq i32 %0, 0
+ tail call void @_Z10sideeffectv()
+ br i1 %3, label %5, label %4
+
+; <label>:4: ; preds = %2
+ call void @sink()
+ tail call void @longjmp(%struct.__jmp_buf_tag* %1, i32 0)
+ unreachable
+
+; <label>:5: ; preds = %2
+ ret void
+}
+
+; CHECK-LABEL: define {{.*}}@bar.cold.1(
+; CHECK: call {{.*}}@llvm.trap(
+
+declare void @sink() cold
+
+declare void @llvm.trap() noreturn cold
+
+declare void @_Z10sideeffectv()
+
+declare void @longjmp(%struct.__jmp_buf_tag*, i32) noreturn nounwind
diff --git a/llvm/test/Transforms/HotColdSplit/outline-cold-asm.ll b/llvm/test/Transforms/HotColdSplit/outline-cold-asm.ll
new file mode 100644
index 00000000000..f3685030c1d
--- /dev/null
+++ b/llvm/test/Transforms/HotColdSplit/outline-cold-asm.ll
@@ -0,0 +1,27 @@
+; 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"
+
+; CHECK-LABEL: define {{.*}}@fun(
+; CHECK: call {{.*}}@fun.cold.1(
+
+; CHECK-LABEL: define {{.*}}@fun.cold.1(
+; CHECK: asm ""
+
+define void @fun() {
+entry:
+ br i1 undef, label %if.then, label %if.else
+
+if.then:
+ ret void
+
+if.else:
+ call void asm "", ""()
+ call void @sink()
+ call void @sink()
+ call void @sink()
+ ret void
+}
+
+declare void @sink() cold
OpenPOWER on IntegriCloud