| ; REQUIRES: aarch64-registered-target | |
| ; REQUIRES: x86-registered-target | |
| ; COM: Machine function splitting with FDO profiles | |
| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -function-splitting=all | FileCheck %s -check-prefixes=MFS-DEFAULTS,MFS-DEFAULTS-X86,MFS-NOBBSECTIONS | |
| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -function-splitting=all -mfs-psi-cutoff=0 -mfs-count-threshold=2000 | FileCheck %s --dump-input=always -check-prefixes=MFS-OPTS1,MFS-OPTS1-X86 | |
| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -function-splitting=all -mfs-psi-cutoff=950000 | FileCheck %s -check-prefixes=MFS-OPTS2,MFS-OPTS2-X86 | |
| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -function-splitting=all -mfs-split-ehcode | FileCheck %s -check-prefixes=MFS-EH-SPLIT,MFS-EH-SPLIT-X86 | |
| ; RUN: llc < %s -mtriple=x86_64 -function-splitting=all -O0 -mfs-psi-cutoff=0 -mfs-count-threshold=10000 | FileCheck %s -check-prefixes=MFS-O0,MFS-O0-X86 | |
| ; COM: Machine function splitting along with -basic-block-sections profile | |
| ; RUN: echo 'v1' > %t | |
| ; RUN: echo 'ffoo21' >> %t | |
| ; RUN: echo 'c0' >> %t | |
| ; RUN: echo 'ffoo22' >> %t | |
| ; RUN: echo 'c0 1' >> %t | |
| ; RUN: echo 'c2' >> %t | |
| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -basic-block-sections=%t -function-splitting=all | FileCheck %s --check-prefixes=MFS-BBSECTIONS,MFS-BBSECTIONS-ALL | |
| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -basic-block-sections=%t -function-splitting=bbsections | FileCheck %s --check-prefixes=MFS-BBSECTIONS,MFS-BBSECTIONS-ONLY | |
| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -basic-block-sections=%t -function-splitting=none | FileCheck %s --check-prefixes=MFS-BBSECTIONS-NONE | |
| ; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -aarch64-min-jump-table-entries=4 -function-splitting=all | FileCheck %s -check-prefixes=MFS-DEFAULTS,MFS-DEFAULTS-AARCH64 | |
| ; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -aarch64-min-jump-table-entries=4 -function-splitting=all -mfs-psi-cutoff=0 -mfs-count-threshold=2000 | FileCheck %s --dump-input=always -check-prefixes=MFS-OPTS1,MFS-OPTS1-AARCH64 | |
| ; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -aarch64-min-jump-table-entries=4 -function-splitting=all -mfs-psi-cutoff=950000 | FileCheck %s -check-prefixes=MFS-OPTS2,MFS-OPTS2-AARCH64 | |
| ; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -aarch64-min-jump-table-entries=4 -function-splitting=all -mfs-split-ehcode | FileCheck %s -check-prefixes=MFS-EH-SPLIT,MFS-EH-SPLIT-AARCH64 | |
| ; RUN: llc < %s -mtriple=aarch64 -function-splitting=all -O0 -mfs-psi-cutoff=0 -mfs-count-threshold=10000 | FileCheck %s -check-prefixes=MFS-O0,MFS-O0-AARCH64 | |
| ; RUN: llc < %s -mtriple=aarch64 -function-splitting=all -aarch64-redzone | FileCheck %s -check-prefixes=MFS-REDZONE-AARCH64 | |
| ; COM: Machine function splitting with AFDO profiles | |
| ; RUN: sed 's/InstrProf/SampleProfile/g' %s > %t.ll | |
| ; RUN: llc < %t.ll -mtriple=x86_64-unknown-linux-gnu -function-splitting=all | FileCheck %s --check-prefix=FSAFDO-MFS | |
| ; RUN: llc < %t.ll -mtriple=x86_64-unknown-linux-gnu -function-splitting=all | FileCheck %s --check-prefix=FSAFDO-MFS2 | |
| define void @foo1(i1 zeroext %0) nounwind !prof !14 !section_prefix !15 { | |
| ;; Check that cold block is moved to .text.split. | |
| ; MFS-DEFAULTS-LABEL: foo1 | |
| ; MFS-DEFAULTS: .section .text.split.foo1 | |
| ; MFS-DEFAULTS-NEXT: foo1.cold: | |
| ; MFS-DEFAULTS-X86-NOT: callq bar | |
| ; MFS-DEFAULTS-X86-NEXT: callq baz | |
| ; MFS-DEFAULTS-AARCH64-NOT: bl bar | |
| ; MFS-DEFAULTS-AARCH64-NEXT: bl baz | |
| ;; Check that with a basic-block-sections profile, a function outside the | |
| ;; profile is still split using PGO with -function-splitting=all. | |
| ; MFS-BBSECTIONS-ALL-LABEL: foo1: | |
| ; MFS-BBSECTIONS-ALL: .section .text.split.foo1 | |
| ; MFS-BBSECTIONS-ALL-NEXT: foo1.cold: | |
| ;; Check that with -function-splitting=bbsections, a function outside the | |
| ;; basic-block-sections profile is not split, even though it has PGO data. | |
| ; MFS-BBSECTIONS-ONLY-LABEL: foo1: | |
| ; MFS-BBSECTIONS-ONLY-NOT: foo1.cold: | |
| br i1 %0, label %2, label %4, !prof !17 | |
| 2: ; preds = %1 | |
| %3 = call i32 @bar() | |
| br label %6 | |
| 4: ; preds = %1 | |
| %5 = call i32 @baz() | |
| br label %6 | |
| 6: ; preds = %4, %2 | |
| %7 = tail call i32 @qux() | |
| ret void | |
| } | |
| define void @foo2(i1 zeroext %0) nounwind !prof !23 !section_prefix !16 { | |
| ;; Check that function marked unlikely is not split. | |
| ; MFS-DEFAULTS-LABEL: foo2 | |
| ; MFS-DEFAULTS-NOT: foo2.cold: | |
| br i1 %0, label %2, label %4, !prof !17 | |
| 2: ; preds = %1 | |
| %3 = call i32 @bar() | |
| br label %6 | |
| 4: ; preds = %1 | |
| %5 = call i32 @baz() | |
| br label %6 | |
| 6: ; preds = %4, %2 | |
| %7 = tail call i32 @qux() | |
| ret void | |
| } | |
| define void @foo3(i1 zeroext %0) nounwind !section_prefix !15 { | |
| ;; Check that function without profile data is not split. | |
| ; MFS-DEFAULTS-LABEL: foo3 | |
| ; MFS-DEFAULTS-NOT: foo3.cold: | |
| br i1 %0, label %2, label %4 | |
| 2: ; preds = %1 | |
| %3 = call i32 @bar() | |
| br label %6 | |
| 4: ; preds = %1 | |
| %5 = call i32 @baz() | |
| br label %6 | |
| 6: ; preds = %4, %2 | |
| %7 = tail call i32 @qux() | |
| ret void | |
| } | |
| define void @foo4(i1 zeroext %0, i1 zeroext %1) nounwind !prof !20 { | |
| ;; Check that count threshold works. | |
| ; MFS-OPTS1-LABEL: foo4 | |
| ; MFS-OPTS1: .section .text.split.foo4 | |
| ; MFS-OPTS1-NEXT: foo4.cold: | |
| ; MFS-OPTS1-X86-NOT: callq bar | |
| ; MFS-OPTS1-X86-NOT: callq baz | |
| ; MFS-OPTS1-X86-NEXT: callq bam | |
| ; MFS-OPTS1-AARCH64-NOT: bl bar | |
| ; MFS-OPTS1-AARCH64-NOT: bl baz | |
| ; MFS-OPTS1-AARCH64-NEXT: bl bam | |
| br i1 %0, label %3, label %7, !prof !18 | |
| 3: | |
| %4 = call i32 @bar() | |
| br label %7 | |
| 5: | |
| %6 = call i32 @baz() | |
| br label %7 | |
| 7: | |
| br i1 %1, label %8, label %10, !prof !19 | |
| 8: | |
| %9 = call i32 @bam() | |
| br label %12 | |
| 10: | |
| %11 = call i32 @baz() | |
| br label %12 | |
| 12: | |
| %13 = tail call i32 @qux() | |
| ret void | |
| } | |
| define void @foo5(i1 zeroext %0, i1 zeroext %1) nounwind !prof !20 { | |
| ;; Check that profile summary info cutoff works. | |
| ; MFS-OPTS2-LABEL: foo5 | |
| ; MFS-OPTS2: .section .text.split.foo5 | |
| ; MFS-OPTS2-NEXT: foo5.cold: | |
| ; MFS-OPTS2-X86-NOT: callq bar | |
| ; MFS-OPTS2-X86-NOT: callq baz | |
| ; MFS-OPTS2-X86-NEXT: callq bam | |
| ; MFS-OPTS2-AARCH64-NOT: bl bar | |
| ; MFS-OPTS2-AARCH64-NOT: bl baz | |
| ; MFS-OPTS2-AARCH64-NEXT: bl bam | |
| br i1 %0, label %3, label %7, !prof !21 | |
| 3: | |
| %4 = call i32 @bar() | |
| br label %7 | |
| 5: | |
| %6 = call i32 @baz() | |
| br label %7 | |
| 7: | |
| br i1 %1, label %8, label %10, !prof !22 | |
| 8: | |
| %9 = call i32 @bam() | |
| br label %12 | |
| 10: | |
| %11 = call i32 @baz() | |
| br label %12 | |
| 12: | |
| %13 = call i32 @qux() | |
| ret void | |
| } | |
| define void @foo6(i1 zeroext %0) nounwind section "nosplit" !prof !14 { | |
| ;; Check that function with section attribute is not split. | |
| ; MFS-DEFAULTS-LABEL: foo6 | |
| ; MFS-DEFAULTS-NOT: foo6.cold: | |
| br i1 %0, label %2, label %4, !prof !17 | |
| 2: ; preds = %1 | |
| %3 = call i32 @bar() | |
| br label %6 | |
| 4: ; preds = %1 | |
| %5 = call i32 @baz() | |
| br label %6 | |
| 6: ; preds = %4, %2 | |
| %7 = tail call i32 @qux() | |
| ret void | |
| } | |
| define i32 @foo7(i1 zeroext %0) personality ptr @__gxx_personality_v0 !prof !14 { | |
| ;; Check that a single cold ehpad is split out. | |
| ; MFS-DEFAULTS-LABEL: foo7 | |
| ; MFS-DEFAULTS: .section .text.split.foo7,"ax",@progbits | |
| ; MFS-DEFAULTS-NEXT: foo7.cold: | |
| ; MFS-DEFAULTS-X86: callq baz | |
| ; MFS-DEFAULTS-X86: callq _Unwind_Resume@PLT | |
| ; MFS-DEFAULTS-AARCH64: bl baz | |
| entry: | |
| invoke void @_Z1fv() | |
| to label %try.cont unwind label %lpad | |
| lpad: | |
| %1 = landingpad { ptr, i32 } | |
| cleanup | |
| catch ptr @_ZTIi | |
| resume { ptr, i32 } %1 | |
| try.cont: | |
| br i1 %0, label %2, label %4, !prof !17 | |
| 2: ; preds = try.cont | |
| %3 = call i32 @bar() | |
| br label %6 | |
| 4: ; preds = %1 | |
| %5 = call i32 @baz() | |
| br label %6 | |
| 6: ; preds = %4, %2 | |
| %7 = tail call i32 @qux() | |
| ret i32 %7 | |
| } | |
| define i32 @foo8(i1 zeroext %0) personality ptr @__gxx_personality_v0 !prof !14 { | |
| ;; Check that all ehpads are treated as hot if one of them is hot. | |
| ; MFS-DEFAULTS-LABEL: foo8 | |
| ; MFS-DEFAULTS-X86: callq _Unwind_Resume@PLT | |
| ; MFS-DEFAULTS-X86: callq _Unwind_Resume@PLT | |
| ; MFS-DEFAULTS: .section .text.split.foo8,"ax",@progbits | |
| ; MFS-DEFAULTS-NEXT: foo8.cold: | |
| ; MFS-DEFAULTS-X86: callq baz | |
| ; MFS-DEFAULTS-AARCH64: bl baz | |
| ;; Check that all ehpads are by default treated as cold with -mfs-split-ehcode. | |
| ; MFS-EH-SPLIT-LABEL: foo8 | |
| ; MFS-EH-SPLIT-X86: callq baz | |
| ; MFS-EH-SPLIT-AARCH64: bl baz | |
| ; MFS-EH-SPLIT-X86: .section .text.split.foo8,"ax",@progbits | |
| ; MFS-EH-SPLIT-X86-NEXT: foo8.cold: | |
| ; MFS-EH-SPLIT-X86: callq _Unwind_Resume@PLT | |
| ; MFS-EH-SPLIT-X86: callq _Unwind_Resume@PLT | |
| entry: | |
| invoke void @_Z1fv() | |
| to label %try.cont unwind label %lpad1 | |
| lpad1: | |
| %1 = landingpad { ptr, i32 } | |
| cleanup | |
| catch ptr @_ZTIi | |
| resume { ptr, i32 } %1 | |
| try.cont: | |
| br i1 %0, label %hot, label %cold, !prof !17 | |
| hot: | |
| %2 = call i32 @bar() | |
| invoke void @_Z1fv() | |
| to label %exit unwind label %lpad2, !prof !21 | |
| lpad2: | |
| %3 = landingpad { ptr, i32 } | |
| cleanup | |
| catch ptr @_ZTIi | |
| resume { ptr, i32 } %3 | |
| cold: | |
| %4 = call i32 @baz() | |
| br label %exit | |
| exit: | |
| %5 = tail call i32 @qux() | |
| ret i32 %5 | |
| } | |
| define i32 @foo10(i1 zeroext %0) personality ptr @__gxx_personality_v0 !prof !14 { | |
| ;; Check that nop is inserted just before the EH pad if it's beginning a section. | |
| ; MFS-DEFAULTS-LABEL: foo10 | |
| ; MFS-DEFAULTS-X86-LABEL: callq baz | |
| ; MFS-DEFAULTS-AARCH64: bl baz | |
| ; MFS-DEFAULTS-X86: .section .text.split.foo10,"ax",@progbits | |
| ; MFS-DEFAULTS-X86-NEXT: foo10.cold: | |
| ; MFS-DEFAULTS-X86: nop | |
| ; MFS-DEFAULTS-X86: callq _Unwind_Resume@PLT | |
| entry: | |
| invoke void @_Z1fv() | |
| to label %try.cont unwind label %lpad, !prof !17 | |
| lpad: | |
| %1 = landingpad { ptr, i32 } | |
| cleanup | |
| catch ptr @_ZTIi | |
| resume { ptr, i32 } %1 | |
| try.cont: | |
| %2 = call i32 @baz() | |
| ret i32 %2 | |
| } | |
| define void @foo11(i1 zeroext %0) personality ptr @__gxx_personality_v0 { | |
| ;; Check that function having landing pads are split with mfs-split-ehcode | |
| ;; even in the absence of profile data | |
| ; MFS-EH-SPLIT-LABEL: foo11 | |
| ; MFS-EH-SPLIT-X86: .section .text.split.foo11,"ax",@progbits | |
| ; MFS-EH-SPLIT-X86-NEXT: foo11.cold: | |
| ; MFS-EH-SPLIT-X86: nop | |
| ; MFS-EH-SPLIT-X86: callq _Unwind_Resume@PLT | |
| entry: | |
| invoke void @_Z1fv() | |
| to label %2 unwind label %lpad | |
| lpad: | |
| %1 = landingpad { ptr, i32 } | |
| cleanup | |
| catch ptr @_ZTIi | |
| resume { ptr, i32 } %1 | |
| 2: ; preds = entry | |
| %3 = tail call i32 @qux() | |
| ret void | |
| } | |
| define i32 @foo12(i1 zeroext %0) personality ptr @__gxx_personality_v0 !prof !14 { | |
| ;; Check that all code reachable from ehpad is split out with cycles. | |
| ; MFS-EH-SPLIT-LABEL: foo12 | |
| ; MFS-EH-SPLIT: .section .text.split.foo12,"ax",@progbits | |
| ; MFS-EH-SPLIT-NEXT: foo12.cold: | |
| ; MFS-EH-SPLIT-X86: callq bar | |
| ; MFS-EH-SPLIT-X86: callq baz | |
| ; MFS-EH-SPLIT-X86: callq qux | |
| ; MFS-EH-SPLIT-AARCH64: bl bar | |
| ; MFS-EH-SPLIT-AARCH64: bl baz | |
| ; MFS-EH-SPLIT-AARCH64: bl qux | |
| entry: | |
| invoke void @_Z1fv() | |
| to label %8 unwind label %lpad | |
| lpad: | |
| %1 = landingpad { ptr, i32 } | |
| cleanup | |
| catch ptr @_ZTIi | |
| br label %2 | |
| 2: ; preds = lpad | |
| %3 = call i32 @bar() | |
| br i1 %0, label %4, label %6 | |
| 4: ; preds = lpad | |
| %5 = call i32 @baz() | |
| br label %6 | |
| 6: ; preds = %4, %2 | |
| %7 = tail call i32 @qux() | |
| br i1 %0, label %2, label %8 | |
| 8: ; preds = %6 | |
| ret i32 0 | |
| } | |
| define i32 @foo13(i1 zeroext %0) personality ptr @__gxx_personality_v0 !prof !14{ | |
| ;; Check that all code reachable from EH | |
| ;; that is also reachable from outside EH pad | |
| ;; is not touched. | |
| ; MFS-EH-SPLIT-LABEL: foo13 | |
| ; MFS-EH-SPLIT-X86: callq bam | |
| ; MFS-EH-SPLIT-AARCH64: bl bam | |
| ; MFS-EH-SPLIT: .section .text.split.foo13,"ax",@progbits | |
| ; MFS-EH-SPLIT-NEXT: foo13.cold: | |
| ; MFS-EH-SPLIT-X86: callq baz | |
| ; MFS-EH-SPLIT-X86: callq bar | |
| ; MFS-EH-SPLIT-X86: callq qux | |
| ; MFS-EH-SPLIT-AARCH64: bl baz | |
| ; MFS-EH-SPLIT-AARCH64: bl bar | |
| ; MFS-EH-SPLIT-AARCH64: bl qux | |
| entry: | |
| invoke void @_Z1fv() | |
| to label %try.cont unwind label %lpad, !prof !17 | |
| lpad: | |
| %1 = landingpad { ptr, i32 } | |
| cleanup | |
| catch ptr @_ZTIi | |
| br i1 %0, label %2, label %4, !prof !17 | |
| 2: ; preds = lpad | |
| %3 = call i32 @bar() | |
| br label %6 | |
| 4: ; preds = lpad | |
| %5 = call i32 @baz() | |
| br label %6 | |
| 6: ; preds = %4, %2 | |
| %7 = tail call i32 @qux() | |
| br i1 %0, label %2, label %try.cont, !prof !17 | |
| try.cont: ; preds = %entry | |
| %8 = call i32 @bam() | |
| ret i32 %8 | |
| } | |
| define void @foo14(i1 zeroext %0, i1 zeroext %1) nounwind !prof !24 { | |
| ; FSAFDO-MFS: .section .text.split.foo14,"ax" | |
| ; FSAFDO-MFS: foo14.cold: | |
| br i1 %0, label %3, label %7, !prof !25 | |
| 3: | |
| %4 = call i32 @bar() | |
| br label %7 | |
| 5: | |
| %6 = call i32 @baz() | |
| br label %7 | |
| 7: | |
| br i1 %1, label %8, label %10, !prof !26 | |
| 8: | |
| %9 = call i32 @bam() | |
| br label %12 | |
| 10: | |
| %11 = call i32 @baz() | |
| br label %12 | |
| 12: | |
| %13 = tail call i32 @qux() | |
| ret void | |
| } | |
| define void @foo15(i1 zeroext %0, i1 zeroext %1) nounwind !prof !27 { | |
| ;; HasAccurateProfile is false, foo15 is hot, but no profile data for | |
| ;; blocks, no split should happen. | |
| ; FSAFDO-MFS2-NOT: .section .text.split.foo15,"ax" | |
| ; FSAFDO-MFS2-NOT: foo15.cold: | |
| br i1 %0, label %3, label %7 | |
| 3: | |
| %4 = call i32 @bar() | |
| br label %7 | |
| 5: | |
| %6 = call i32 @baz() | |
| br label %7 | |
| 7: | |
| br i1 %1, label %8, label %10 | |
| 8: | |
| %9 = call i32 @bam() | |
| br label %12 | |
| 10: | |
| %11 = call i32 @baz() | |
| br label %12 | |
| 12: | |
| %13 = tail call i32 @qux() | |
| ret void | |
| } | |
| define void @foo16(i1 zeroext %0) nounwind !prof !14 !section_prefix !15 { | |
| ;; Check that an unconditional branch is only appended to a block | |
| ;; if it would fall through to the wrong block otherwise. | |
| ; MFS-O0-LABEL: foo16 | |
| ; MFS-O0-X86: jmp | |
| ; MFS-O0-X86-NOT: jmp | |
| ; MFS-O0-AARCH64: b foo16.cold | |
| ; MFS-O0-AARCH64-NOT: b foo16.cold | |
| ; MFS-O0: .section .text.split.foo16 | |
| ; MFS-O0-NEXT: foo16.cold | |
| %2 = call i32 @baz() | |
| br i1 false, label %3, label %5, !prof !25 | |
| 3: ; preds = %1 | |
| %4 = call i32 @bar() | |
| unreachable | |
| 5: ; preds = %1 | |
| %6 = tail call i32 @qux() | |
| ret void | |
| } | |
| define i32 @foo17(i1 zeroext %0, i32 %a, i32 %b) nounwind !prof !14 !section_prefix !15 { | |
| ;; Check that cold blocks in functions with red zones aren't split. | |
| ; MFS-DEFAULTS-LABEL: foo17 | |
| ; MFS-DEFAULTS-X86: foo17.cold: | |
| ; MFS-REDZONE-AARCH64-NOT: foo17.cold: | |
| %a.addr = alloca i32, align 4 | |
| %b.addr = alloca i32, align 4 | |
| %x = alloca i32, align 4 | |
| br i1 %0, label %2, label %3, !prof !17 | |
| 2: ; preds = %1 | |
| store i32 %a, ptr %a.addr, align 4 | |
| store i32 %b, ptr %b.addr, align 4 | |
| br label %4 | |
| 3: ; preds = %1 | |
| store i32 %a, ptr %b.addr, align 4 | |
| store i32 %b, ptr %a.addr, align 4 | |
| br label %4 | |
| 4: ; preds = %3, %2 | |
| %tmp = load i32, ptr %a.addr, align 4 | |
| %tmp1 = load i32, ptr %b.addr, align 4 | |
| %add = add nsw i32 %tmp, %tmp1 | |
| store i32 %add, ptr %x, align 4 | |
| %tmp2 = load i32, ptr %x, align 4 | |
| ret i32 %tmp2 | |
| } | |
| define i32 @foo18(i32 %in) !prof !14 !section_prefix !15 { | |
| ;; Check that a cold block targeted by a jump table is not split | |
| ;; on AArch64. | |
| ; MFS-DEFAULTS-LABEL: foo18 | |
| ; MFS-DEFAULTS: .section .text.split.foo18 | |
| ; MFS-DEFAULTS-NEXT: foo18.cold: | |
| ; MFS-DEFAULTS-SAME: %common.ret | |
| ; MFS-DEFAULTS-X86-DAG: jmp qux | |
| ; MFS-DEFAULTS-X86-DAG: jmp bam | |
| ; MFS-DEFAULTS-AARCH64-NOT: b bar | |
| ; MFS-DEFAULTS-AARCH64-NOT: b baz | |
| ; MFS-DEFAULTS-AARCH64-NOT: b qux | |
| ; MFS-DEFAULTS-AARCH64-NOT: b bam | |
| switch i32 %in, label %common.ret [ | |
| i32 0, label %hot1 | |
| i32 1, label %hot2 | |
| i32 2, label %cold1 | |
| i32 3, label %cold2 | |
| ], !prof !28 | |
| common.ret: ; preds = %0 | |
| ret i32 0 | |
| hot1: ; preds = %0 | |
| %1 = tail call i32 @bar() | |
| ret i32 %1 | |
| hot2: ; preds = %0 | |
| %2 = tail call i32 @baz() | |
| ret i32 %2 | |
| cold1: ; preds = %0 | |
| %3 = tail call i32 @bam() | |
| ret i32 %3 | |
| cold2: ; preds = %0 | |
| %4 = tail call i32 @qux() | |
| ret i32 %4 | |
| } | |
| define i32 @foo19(i32 %in) !prof !14 !section_prefix !15 { | |
| ;; Check that a cold block that contains a jump table dispatch is | |
| ;; not split on AArch64. | |
| ; MFS-DEFAULTS-LABEL: foo19 | |
| ; MFS-DEFAULTS: .section .text.split.foo19 | |
| ; MFS-DEFAULTS-NEXT: foo19.cold: | |
| ; MFS-DEFAULTS-X86: .LJTI17_0 | |
| ; MFS-DEFAULTS-AARCH64-NOT: .LJTI17_0 | |
| ; MFS-DEFAULTS: .section .rodata | |
| ; MFS-DEFAULTS: .LJTI17_0 | |
| %cmp = icmp sgt i32 %in, 3 | |
| br i1 %cmp, label %hot, label %cold_switch, !prof !17 | |
| hot: ; preds = %0 | |
| ret i32 1 | |
| cold_switch: ; preds = %0 | |
| switch i32 %in, label %common.ret [ | |
| i32 0, label %hot1 | |
| i32 1, label %hot2 | |
| i32 2, label %cold1 | |
| i32 3, label %cold2 | |
| ], !prof !28 | |
| common.ret: ; preds = %0 | |
| ret i32 0 | |
| hot1: ; preds = %0 | |
| %1 = tail call i32 @bar() | |
| ret i32 %1 | |
| hot2: ; preds = %0 | |
| %2 = tail call i32 @baz() | |
| ret i32 %2 | |
| cold1: ; preds = %0 | |
| %3 = tail call i32 @bam() | |
| ret i32 %3 | |
| cold2: ; preds = %0 | |
| %4 = tail call i32 @qux() | |
| ret i32 %4 | |
| } | |
| define void @foo20(i1 zeroext %0) !prof !14 !section_prefix !15 { | |
| ;; Check that blocks containing or targeted by asm goto aren't split. | |
| ; MFS-DEFAULTS-LABEL: foo20 | |
| ; MFS-DEFAULTS-AARCH64-NOT: foo20.cold: | |
| ; MFS-DEFAULTS-X86: .section .text.split.foo20 | |
| ; MFS-DEFAULTS-X86: foo20.cold: | |
| ; MFS-DEFAULTS-X86-DAG: # %cold_asm | |
| ; MFS-DEFAULTS-X86-DAG: # %cold_asm_target | |
| br i1 %0, label %hot, label %cold_asm, !prof !17 | |
| hot: | |
| %2 = call i32 @bar() | |
| ret void | |
| cold_asm: | |
| callbr void asm sideeffect "nop", "!i"() #3 | |
| to label %asm.fallthrough [label %cold_asm_target] | |
| asm.fallthrough: | |
| br label %cold_asm_target | |
| cold_asm_target: | |
| %3 = call i32 @baz() | |
| ret void | |
| } | |
| define void @foo21(i1 zeroext %0) { | |
| ;; Check that a function with basic-block-sections profile (but no pgo profile) | |
| ;; is properly split when the profile is used along with mfs. | |
| ; MFS-BBSECTIONS: .section .text.hot.foo21 | |
| ; MFS-NOBBSECTIONS-NOT: .section .text.hot.foo21 | |
| ; MFS-BBSECTIONS-LABEL: foo21: | |
| ; MFS-NOBBSECTIONS-NOT: foo21.cold: | |
| ; MFS-BBSECTIONS: .section .text.split.foo21 | |
| ; MFS-BBSECTIONS: foo21.cold | |
| ;; Check that with -function-splitting=none, the function is not split. | |
| ; MFS-BBSECTIONS-NONE: .section .text.hot.foo21 | |
| ; MFS-BBSECTIONS-NONE-LABEL: foo21: | |
| ; MFS-BBSECTIONS-NONE-NOT: .section | |
| ; MFS-BBSECTIONS-NONE: .size foo21, | |
| %2 = alloca i8, align 1 | |
| %3 = zext i1 %0 to i8 | |
| store i8 %3, ptr %2, align 1 | |
| %4 = load i8, ptr %2, align 1 | |
| %5 = trunc i8 %4 to i1 | |
| br i1 %5, label %6, label %8 | |
| 6: ; preds = %1 | |
| %7 = call i32 @bar() | |
| br label %10 | |
| 8: ; preds = %1 | |
| %9 = call i32 @baz() | |
| br label %10 | |
| 10: ; preds = %8, %6 | |
| ret void | |
| } | |
| define void @foo22(i1 zeroext %0) nounwind !prof !14 !section_prefix !15 { | |
| ;; Check that when a function has both basic-block-section and pgo profiles | |
| ;; only the basic-block-section profile is used for splitting. | |
| ;; Check that we create two hot sections with -basic-block-sections. | |
| ; MFS-BBSECTIONS: .section .text.hot.foo22 | |
| ; MFS-BBSECTIONS-LABEL: foo22: | |
| ; MFS-BBSECTIONS: callq bar | |
| ; MFS-BBSECTIONS: .section .text.hot.foo22 | |
| ; MFS-BBSECTIONS-NEXT: foo22.__part.1: | |
| ; MFS-BBSECTIONS: callq baz | |
| ; MFS-BBSECTIONS-NOT: .section .text.split.foo22 | |
| ;; Check that with -function-splitting=none, both clusters are emitted in a | |
| ;; single section. | |
| ; MFS-BBSECTIONS-NONE: .section .text.hot.foo22 | |
| ; MFS-BBSECTIONS-NONE-LABEL: foo22: | |
| ; MFS-BBSECTIONS-NONE: callq bar | |
| ; MFS-BBSECTIONS-NONE-NOT: .section | |
| ; MFS-BBSECTIONS-NONE: callq baz | |
| ; MFS-BBSECTIONS-NONE-NOT: .section | |
| ; MFS-BBSECTIONS-NONE: .size foo22, | |
| br i1 %0, label %2, label %4, !prof !17 | |
| 2: ; preds = %1 | |
| %3 = call i32 @bar() | |
| br label %6 | |
| 4: ; preds = %1 | |
| %5 = call i32 @baz() | |
| br label %6 | |
| 6: ; preds = %4, %2 | |
| %7 = tail call i32 @qux() | |
| ret void | |
| } | |
| define i32 @foo23(i1 zeroext %0) personality ptr @__gxx_personality_v0 !prof !14 { | |
| ;; Check that nop is inserted just before the EH pad if it is the first | |
| ;; instruction in a section (but is preceeded by another empty block). | |
| ; MFS-DEFAULTS-LABEL: foo23 | |
| ; MFS-DEFAULTS-X86-LABEL: callq baz | |
| ; MFS-DEFAULTS-X86: .section .text.split.foo23,"ax",@progbits | |
| ; MFS-DEFAULTS-X86-NEXT: foo23.cold: | |
| ; MFS-DEFAULTS-X86: nop | |
| ; MFS-DEFAULTS-X86: callq _Unwind_Resume@PLT | |
| entry: | |
| br i1 %0, label %try, label %unreachable, !prof !17 | |
| try: | |
| invoke void @_Z1fv() | |
| to label %try.cont unwind label %lpad, !prof !17 | |
| try.cont: | |
| %1 = call i32 @baz() | |
| ret i32 %1 | |
| unreachable: | |
| unreachable | |
| lpad: | |
| %2 = landingpad { ptr, i32 } | |
| cleanup | |
| catch ptr @_ZTIi | |
| resume { ptr, i32 } %2 | |
| } | |
| declare i32 @bar() | |
| declare i32 @baz() | |
| declare i32 @bam() | |
| declare i32 @qux() | |
| declare void @_Z1fv() | |
| declare i32 @__gxx_personality_v0(...) | |
| @_ZTIi = external constant ptr | |
| !llvm.module.flags = !{!0} | |
| !0 = !{i32 1, !"ProfileSummary", !1} | |
| !1 = !{!2, !3, !4, !5, !6, !7, !8, !9} | |
| !2 = !{!"ProfileFormat", !"InstrProf"} | |
| !3 = !{!"TotalCount", i64 10000} | |
| !4 = !{!"MaxCount", i64 10} | |
| !5 = !{!"MaxInternalCount", i64 1} | |
| !6 = !{!"MaxFunctionCount", i64 1000} | |
| !7 = !{!"NumCounts", i64 3} | |
| !8 = !{!"NumFunctions", i64 5} | |
| !9 = !{!"DetailedSummary", !10} | |
| !10 = !{!11, !12, !13} | |
| !11 = !{i32 10000, i64 100, i32 1} | |
| !12 = !{i32 999900, i64 100, i32 1} | |
| !13 = !{i32 999999, i64 1, i32 2} | |
| !14 = !{!"function_entry_count", i64 7000} | |
| !15 = !{!"function_section_prefix", !"hot"} | |
| !16 = !{!"function_section_prefix", !"unlikely"} | |
| !17 = !{!"branch_weights", i32 7000, i32 0} | |
| !18 = !{!"branch_weights", i32 3000, i32 4000} | |
| !19 = !{!"branch_weights", i32 1000, i32 6000} | |
| !20 = !{!"function_entry_count", i64 10000} | |
| !21 = !{!"branch_weights", i32 6000, i32 4000} | |
| !22 = !{!"branch_weights", i32 80, i32 9920} | |
| !23 = !{!"function_entry_count", i64 7} | |
| !24 = !{!"function_entry_count", i64 10000} | |
| !25 = !{!"branch_weights", i32 0, i32 7000} | |
| !26 = !{!"branch_weights", i32 1000, i32 6000} | |
| !27 = !{!"function_entry_count", i64 10000} | |
| !28 = !{!"branch_weights", i32 0, i32 4000, i32 4000, i32 0, i32 0} |