1; RUN: llc < %s -march=x86-64 -mtriple=x86_64-unknown-linux-gnu -asm-verbose=false | FileCheck %s 2 3; These tests check for loop branching structure, and that the loop align 4; directive is placed in the expected place. 5 6; CodeGen should insert a branch into the middle of the loop in 7; order to avoid a branch within the loop. 8 9; CHECK-LABEL: simple: 10; CHECK: jmp .LBB0_1 11; CHECK-NEXT: align 12; CHECK-NEXT: .LBB0_2: 13; CHECK-NEXT: callq loop_latch 14; CHECK-NEXT: .LBB0_1: 15; CHECK-NEXT: callq loop_header 16 17define void @simple() nounwind { 18entry: 19 br label %loop 20 21loop: 22 call void @loop_header() 23 %t0 = tail call i32 @get() 24 %t1 = icmp slt i32 %t0, 0 25 br i1 %t1, label %done, label %bb 26 27bb: 28 call void @loop_latch() 29 br label %loop 30 31done: 32 call void @exit() 33 ret void 34} 35 36; CodeGen should move block_a to the top of the loop so that it 37; falls through into the loop, avoiding a branch within the loop. 38 39; CHECK-LABEL: slightly_more_involved: 40; CHECK: jmp .LBB1_1 41; CHECK-NEXT: align 42; CHECK-NEXT: .LBB1_4: 43; CHECK-NEXT: callq bar99 44; CHECK-NEXT: .LBB1_1: 45; CHECK-NEXT: callq body 46 47define void @slightly_more_involved() nounwind { 48entry: 49 br label %loop 50 51loop: 52 call void @body() 53 %t0 = call i32 @get() 54 %t1 = icmp slt i32 %t0, 2 55 br i1 %t1, label %block_a, label %bb 56 57bb: 58 %t2 = call i32 @get() 59 %t3 = icmp slt i32 %t2, 99 60 br i1 %t3, label %exit, label %loop 61 62block_a: 63 call void @bar99() 64 br label %loop 65 66exit: 67 call void @exit() 68 ret void 69} 70 71; Same as slightly_more_involved, but block_a is now a CFG diamond with 72; fallthrough edges which should be preserved. 73; "callq block_a_merge_func" is tail duped. 74 75; CHECK-LABEL: yet_more_involved: 76; CHECK: jmp .LBB2_1 77; CHECK-NEXT: align 78; CHECK-NEXT: .LBB2_5: 79; CHECK-NEXT: callq block_a_true_func 80; CHECK-NEXT: callq block_a_merge_func 81; CHECK-NEXT: .LBB2_1: 82; CHECK-NEXT: callq body 83; 84; LBB2_4 85; CHECK: callq bar99 86; CHECK-NEXT: callq get 87; CHECK-NEXT: cmpl $2999, %eax 88; CHECK-NEXT: jle .LBB2_5 89; CHECK-NEXT: callq block_a_false_func 90; CHECK-NEXT: callq block_a_merge_func 91; CHECK-NEXT: jmp .LBB2_1 92 93define void @yet_more_involved() nounwind { 94entry: 95 br label %loop 96 97loop: 98 call void @body() 99 %t0 = call i32 @get() 100 %t1 = icmp slt i32 %t0, 2 101 br i1 %t1, label %block_a, label %bb 102 103bb: 104 %t2 = call i32 @get() 105 %t3 = icmp slt i32 %t2, 99 106 br i1 %t3, label %exit, label %loop 107 108block_a: 109 call void @bar99() 110 %z0 = call i32 @get() 111 %z1 = icmp slt i32 %z0, 3000 112 br i1 %z1, label %block_a_true, label %block_a_false 113 114block_a_true: 115 call void @block_a_true_func() 116 br label %block_a_merge 117 118block_a_false: 119 call void @block_a_false_func() 120 br label %block_a_merge 121 122block_a_merge: 123 call void @block_a_merge_func() 124 br label %loop 125 126exit: 127 call void @exit() 128 ret void 129} 130 131; CodeGen should move the CFG islands that are part of the loop but don't 132; conveniently fit anywhere so that they are at least contiguous with the 133; loop. 134 135; CHECK-LABEL: cfg_islands: 136; CHECK: jmp .LBB3_1 137; CHECK-NEXT: align 138; CHECK-NEXT: .LBB3_7: 139; CHECK-NEXT: callq bar100 140; CHECK-NEXT: .LBB3_1: 141; CHECK-NEXT: callq loop_header 142; CHECK: jl .LBB3_7 143; CHECK: jge .LBB3_3 144; CHECK-NEXT: callq bar101 145; CHECK-NEXT: jmp .LBB3_1 146; CHECK-NEXT: align 147; CHECK-NEXT: .LBB3_3: 148; CHECK: jge .LBB3_4 149; CHECK-NEXT: callq bar102 150; CHECK-NEXT: jmp .LBB3_1 151; CHECK-NEXT: .LBB3_4: 152; CHECK: jl .LBB3_6 153; CHECK-NEXT: callq loop_latch 154; CHECK-NEXT: jmp .LBB3_1 155; CHECK-NEXT: .LBB3_6: 156 157define void @cfg_islands() nounwind { 158entry: 159 br label %loop 160 161loop: 162 call void @loop_header() 163 %t0 = call i32 @get() 164 %t1 = icmp slt i32 %t0, 100 165 br i1 %t1, label %block100, label %bb 166 167bb: 168 %t2 = call i32 @get() 169 %t3 = icmp slt i32 %t2, 101 170 br i1 %t3, label %block101, label %bb1 171 172bb1: 173 %t4 = call i32 @get() 174 %t5 = icmp slt i32 %t4, 102 175 br i1 %t5, label %block102, label %bb2 176 177bb2: 178 %t6 = call i32 @get() 179 %t7 = icmp slt i32 %t6, 103 180 br i1 %t7, label %exit, label %bb3 181 182bb3: 183 call void @loop_latch() 184 br label %loop 185 186exit: 187 call void @exit() 188 ret void 189 190block100: 191 call void @bar100() 192 br label %loop 193 194block101: 195 call void @bar101() 196 br label %loop 197 198block102: 199 call void @bar102() 200 br label %loop 201} 202 203; CHECK-LABEL: check_minsize: 204; CHECK: jmp .LBB4_1 205; CHECK-NOT: align 206; CHECK-NEXT: .LBB4_2: 207; CHECK-NEXT: callq loop_latch 208; CHECK-NEXT: .LBB4_1: 209; CHECK-NEXT: callq loop_header 210 211 212define void @check_minsize() minsize nounwind { 213entry: 214 br label %loop 215 216loop: 217 call void @loop_header() 218 %t0 = tail call i32 @get() 219 %t1 = icmp slt i32 %t0, 0 220 br i1 %t1, label %done, label %bb 221 222bb: 223 call void @loop_latch() 224 br label %loop 225 226done: 227 call void @exit() 228 ret void 229} 230 231declare void @bar99() nounwind 232declare void @bar100() nounwind 233declare void @bar101() nounwind 234declare void @bar102() nounwind 235declare void @body() nounwind 236declare void @exit() nounwind 237declare void @loop_header() nounwind 238declare void @loop_latch() nounwind 239declare i32 @get() nounwind 240declare void @block_a_true_func() nounwind 241declare void @block_a_false_func() nounwind 242declare void @block_a_merge_func() nounwind 243