;; See also llvm/unittests/Transforms/Utils/CodeLayoutTest.cpp
; RUN: llc -mcpu=corei7 -mtriple=x86_64-linux -enable-ext-tsp-block-placement=1 < %s | FileCheck %s
define void @func1a() {
; Test that the algorithm positions the most likely successor first
;
; +-----+
; | b0 | -+
; +-----+ |
; | |
; | 40 |
; v |
; +-----+ |
; | b1 | | 100
; +-----+ |
; | |
; | 40 |
; v |
; +-----+ |
; | b2 | <+
; +-----+
;
; CHECK-LABEL: func1a:
; CHECK: b0
; CHECK: b2
; CHECK: b1
b0:
%call = call zeroext i1 @a()
br i1 %call, label %b1, label %b2, !prof !1
b1:
call void @d()
call void @d()
call void @d()
br label %b2
b2:
call void @e()
ret void
}
define void @func1b() {
; Test that the algorithm prefers many fallthroughs even in the presence of
; a heavy successor
;
; +-----+
; | b0 | -+
; +-----+ |
; | |
; | 80 |
; v |
; +-----+ |
; | b1 | | 100
; +-----+ |
; | |
; | 80 |
; v |
; +-----+ |
; | b2 | <+
; +-----+
;
; CHECK-LABEL: func1b:
; CHECK: b0
; CHECK: b1
; CHECK: b2
b0:
%call = call zeroext i1 @a()
br i1 %call, label %b1, label %b2, !prof !2
b1:
call void @d()
call void @d()
call void @d()
br label %b2
b2:
call void @e()
ret void
}
define void @func2() !prof !3 {
; Test that the algorithm positions the hot chain continuously
;
; +----+ [7] +-------+
; | b1 | <----- | b0 |
; +----+ +-------+
; | |
; | | [15]
; | v
; | +-------+
; | | b3 |
; | +-------+
; | |
; | | [15]
; | v
; | +-------+ [31]
; | | | -------+
; | | b4 | |
; | | | <------+
; | +-------+
; | |
; | | [15]
; | v
; | [7] +-------+
; +---------> | b2 |
; +-------+
;
; CHECK-LABEL: func2:
; CHECK: b0
; CHECK: b3
; CHECK: b4
; CHECK: b2
; CHECK: b1
b0:
call void @d()
call void @d()
call void @d()
%call = call zeroext i1 @a()
br i1 %call, label %b1, label %b3, !prof !4
b1:
call void @d()
br label %b2
b2:
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
ret void
b3:
call void @d()
br label %b4
b4:
call void @d()
%call2 = call zeroext i1 @a()
br i1 %call2, label %b2, label %b4, !prof !5
}
define void @func3() !prof !6 {
; A larger test where it is beneficial for locality to break the loop
;
; +--------+
; | b0 |
; +--------+
; |
; | [177]
; v
; +----+ [177] +---------------------------+
; | b5 | <------- | b1 |
; +----+ +---------------------------+
; | ^ ^
; | [196] | [124] | [70]
; v | |
; +----+ [70] +--------+ | |
; | b4 | <------- | b2 | | |
; +----+ +--------+ | |
; | | | |
; | | [124] | |
; | v | |
; | +--------+ | |
; | | b3 | -+ |
; | +--------+ |
; | |
; +-----------------------------------+
;
; CHECK-LABEL: func3:
; CHECK: b0
; CHECK: b1
; CHECK: b2
; CHECK: b3
; CHECK: b5
; CHECK: b4
b0:
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
call void @f()
br label %b1
b1:
%call = call zeroext i1 @a()
br i1 %call, label %b5, label %b2, !prof !7
b2:
call void @d()
call void @d()
call void @d()
call void @d()
%call2 = call zeroext i1 @a()
br i1 %call2, label %b3, label %b4, !prof !8
b3:
call void @d()
call void @f()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
call void @d()
br label %b1
b4:
call void @d()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
call void @e()
br label %b1
b5:
ret void
}
define void @func_loop() !prof !9 {
; Test that the algorithm can rotate loops in the presence of profile data.
;
; +--------+
; | entry |
; +--------+
; |
; | 1
; v
; +--------+ 16 +--------+
; | if.then| <---- | header | <+
; +--------+ +--------+ |
; | | |
; | | 16 |
; | v |
; | +--------+ |
; | | if.else| | 31
; | +--------+ |
; | | |
; | | 16 |
; | v |
; | 16 +--------+ |
; +------------> | if.end | -+
; +--------+
; |
; | 1
; v
; +--------+
; | end |
; +--------+
;
; CHECK-LABEL: func_loop:
; CHECK: if.else
; CHECK: if.end
; CHECK: header
; CHECK: if.then
entry:
br label %header
header:
call void @e()
%call = call zeroext i1 @a()
br i1 %call, label %if.then, label %if.else, !prof !10
if.then:
call void @f()
br label %if.end
if.else:
call void @g()
br label %if.end
if.end:
call void @h()
%call2 = call zeroext i1 @a()
br i1 %call2, label %header, label %end
end:
ret void
}
define void @func4() !prof !11 {
; Test verifying that chains can be split in order to improve the objective
; by creating more fallthroughs
;
; +-------+
; | entry |--------+
; +-------+ |
; | |
; | 27 |
; v |
; +-------+ |
; | b1 | -+ |
; +-------+ | |
; | | |
; | 10 | | 0
; v | |
; +-------+ | |
; | b3 | | 17 |
; +-------+ | |
; | | |
; | 10 | |
; v | |
; +-------+ | |
; | b2 | <+ ----+
; +-------+
;
; CHECK-LABEL: func4:
; CHECK: entry
; CHECK: b1
; CHECK: b3
; CHECK: b2
entry:
call void @b()
%call2 = call zeroext i1 @a()
br i1 %call2, label %b1, label %b2, !prof !12
b1:
call void @c()
%call = call zeroext i1 @a()
br i1 %call, label %b2, label %b3, !prof !13
b2:
call void @d()
ret void
b3:
call void @e()
br label %b2
}
declare zeroext i1 @a()
declare void @b()
declare void @c()
declare void @d()
declare void @e()
declare void @g()
declare void @f()
declare void @h()
!1 = !{!"branch_weights", i32 40, i32 100}
!2 = !{!"branch_weights", i32 80, i32 100}
!3 = !{!"function_entry_count", i64 2200}
!4 = !{!"branch_weights", i32 700, i32 1500}
!5 = !{!"branch_weights", i32 1500, i32 3100}
!6 = !{!"function_entry_count", i64 177}
!7 = !{!"branch_weights", i32 177, i32 196}
!8 = !{!"branch_weights", i32 125, i32 70}
!9 = !{!"function_entry_count", i64 1}
!10 = !{!"branch_weights", i32 16, i32 16}
!11 = !{!"function_entry_count", i64 1}
!12 = !{!"branch_weights", i32 27, i32 0}
!13 = !{!"branch_weights", i32 17, i32 10}