| ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s |
| |
| |
| @gvar = external global i32 |
| |
| ; dupbb has two predecessors, p1 and p2. p1 is hot, p2 is cold. So dupbb |
| ; should be placed after p1, and not duplicated into p2. |
| ; |
| ; CHECK-LABEL: test1 |
| ; CHECK: %p1 |
| ; CHECK: .LBB0_4: # %dupbb |
| ; CHECK: %p2 |
| ; CHECK: jmp .LBB0_4 |
| |
| define void @test1(i32* %p) !prof !1 { |
| entry: |
| br label %header |
| |
| header: |
| %call = call zeroext i1 @a() |
| br i1 %call, label %p1, label %p2, !prof !2 |
| |
| p1: |
| call void @b() |
| br label %dupbb |
| |
| p2: |
| call void @c() |
| br label %dupbb |
| |
| dupbb: |
| %cond = icmp eq i32* @gvar, %p |
| br i1 %cond, label %header, label %latch, !prof !3 |
| |
| latch: |
| %call3 = call zeroext i1 @a() |
| br i1 %call3, label %header, label %end, !prof !2 |
| |
| end: |
| ret void |
| } |
| |
| |
| ; dupbb has four predecessors p1, p2, p3 and p4. p1 and p2 are hot, p3 and p4 |
| ; are cold. So dupbb should be placed after p1, duplicated into p2. p3 and p4 |
| ; should jump to dupbb. |
| ; |
| ; CHECK-LABEL: test2 |
| ; CHECK: %p1 |
| ; CHECK: .LBB1_8: # %dupbb |
| ; |
| ; CHECK: %p2 |
| ; CHECK: callq c |
| ; CHECK-NEXT: cmpq |
| ; CHECK-NEXT: je |
| ; CHECK-NEXT: jmp |
| ; |
| ; CHECK: %p3 |
| ; CHECK: jmp .LBB1_8 |
| ; CHECK: %p4 |
| ; CHECK: jmp .LBB1_8 |
| |
| define void @test2(i32* %p) !prof !1 { |
| entry: |
| br label %header |
| |
| header: |
| %call = call zeroext i1 @a() |
| br i1 %call, label %bb1, label %bb2, !prof !2 |
| |
| bb1: |
| %call1 = call zeroext i1 @a() |
| br i1 %call1, label %p1, label %p2, !prof !4 |
| |
| bb2: |
| %call2 = call zeroext i1 @a() |
| br i1 %call2, label %p3, label %p4, !prof !4 |
| |
| p1: |
| call void @b() |
| br label %dupbb |
| |
| p2: |
| call void @c() |
| br label %dupbb |
| |
| p3: |
| call void @d() |
| br label %dupbb |
| |
| p4: |
| call void @e() |
| br label %dupbb |
| |
| dupbb: |
| %cond = icmp eq i32* @gvar, %p |
| br i1 %cond, label %bb3, label %bb4, !prof !4 |
| |
| bb3: |
| call void @b() |
| br label %bb4 |
| |
| bb4: |
| %call4 = call zeroext i1 @a() |
| br i1 %call4, label %header, label %latch, !prof !3 |
| |
| latch: |
| %call3 = call zeroext i1 @a() |
| br i1 %call3, label %header, label %end, !prof !2 |
| |
| end: |
| ret void |
| } |
| |
| |
| ; dupbb has three predecessors p1, p2 and p3. p3 has two successors, so dupbb |
| ; can't be duplicated into p3, but it should not block it to be duplicated into |
| ; other predecessors. |
| ; |
| ; CHECK-LABEL: test3 |
| ; CHECK: %p1 |
| ; CHECK: .LBB2_6: # %dupbb |
| ; |
| ; CHECK: %p2 |
| ; CHECK: callq c |
| ; CHECK: cmpq |
| ; CHECK-NEXT: je |
| ; CHECK-NEXT: jmp |
| ; |
| ; CHECK: %p3 |
| ; CHECK: jne .LBB2_6 |
| |
| define void @test3(i32* %p) !prof !1 { |
| entry: |
| br label %header |
| |
| header: |
| %call = call zeroext i1 @a() |
| br i1 %call, label %bb1, label %p3, !prof !2 |
| |
| bb1: |
| %call1 = call zeroext i1 @a() |
| br i1 %call1, label %p1, label %p2, !prof !4 |
| |
| p1: |
| call void @b() |
| br label %dupbb |
| |
| p2: |
| call void @c() |
| br label %dupbb |
| |
| p3: |
| %call2 = call zeroext i1 @a() |
| br i1 %call2, label %dupbb, label %bb4, !prof !4 |
| |
| dupbb: |
| %cond = icmp eq i32* @gvar, %p |
| br i1 %cond, label %bb3, label %bb4, !prof !4 |
| |
| bb3: |
| call void @b() |
| br label %bb4 |
| |
| bb4: |
| %call4 = call zeroext i1 @a() |
| br i1 %call4, label %header, label %latch, !prof !3 |
| |
| latch: |
| %call3 = call zeroext i1 @a() |
| br i1 %call3, label %header, label %end, !prof !2 |
| |
| end: |
| ret void |
| } |
| |
| declare zeroext i1 @a() |
| declare void @b() |
| declare void @c() |
| declare void @d() |
| declare void @e() |
| declare void @f() |
| |
| !1 = !{!"function_entry_count", i64 1000} |
| !2 = !{!"branch_weights", i32 100, i32 1} |
| !3 = !{!"branch_weights", i32 1, i32 100} |
| !4 = !{!"branch_weights", i32 60, i32 40} |