llvm/llvm/test/CodeGen/X86/code_placement_ext_tsp.ll

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