| ;; 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} |