1; RUN: opt -S -licm < %s | FileCheck %s 2; RUN: opt -aa-pipeline=basic-aa -passes='require<aa>,require<targetir>,require<scalar-evolution>,require<opt-remark-emit>,loop(licm)' -S %s | FileCheck %s 3 4declare void @use_nothrow(i64 %a) nounwind 5declare void @use(i64 %a) 6declare void @maythrow() 7 8define void @nothrow(i64 %x, i64 %y, i1* %cond) { 9; CHECK-LABEL: nothrow 10; CHECK-LABEL: entry 11; CHECK: %div = udiv i64 %x, %y 12; CHECK-LABEL: loop 13; CHECK: call void @use_nothrow(i64 %div) 14entry: 15 br label %loop 16 17loop: ; preds = %entry, %for.inc 18 %div = udiv i64 %x, %y 19 br label %loop2 20 21loop2: 22 call void @use_nothrow(i64 %div) 23 br label %loop 24} 25 26; The udiv is guarantee to execute if the loop is 27define void @throw_header_after(i64 %x, i64 %y, i1* %cond) { 28; CHECK-LABEL: throw_header_after 29; CHECK: %div = udiv i64 %x, %y 30; CHECK-LABEL: loop 31; CHECK: call void @use(i64 %div) 32entry: 33 br label %loop 34 35loop: ; preds = %entry, %for.inc 36 %div = udiv i64 %x, %y 37 call void @use(i64 %div) 38 br label %loop 39} 40define void @throw_header_after_rec(i64* %xp, i64* %yp, i1* %cond) { 41; CHECK-LABEL: throw_header_after_rec 42; CHECK: %x = load i64, i64* %xp 43; CHECK: %y = load i64, i64* %yp 44; CHECK: %div = udiv i64 %x, %y 45; CHECK-LABEL: loop 46; CHECK: call void @use(i64 %div) 47entry: 48 br label %loop 49 50loop: ; preds = %entry, %for.inc 51 %x = load i64, i64* %xp 52 %y = load i64, i64* %yp 53 %div = udiv i64 %x, %y 54 call void @use(i64 %div) readonly 55 br label %loop 56} 57 58; Similiar to the above, but the hoistable instruction (%y in this case) 59; happens not to be the first instruction in the block. 60define void @throw_header_after_nonfirst(i64* %xp, i64* %yp, i1* %cond) { 61; CHECK-LABEL: throw_header_after_nonfirst 62; CHECK: %y = load i64, i64* %yp 63; CHECK-LABEL: loop 64; CHECK: %x = load i64, i64* %gep 65; CHECK: %div = udiv i64 %x, %y 66; CHECK: call void @use(i64 %div) 67entry: 68 br label %loop 69 70loop: ; preds = %entry, %for.inc 71 %iv = phi i64 [0, %entry], [%div, %loop] 72 %gep = getelementptr i64, i64* %xp, i64 %iv 73 %x = load i64, i64* %gep 74 %y = load i64, i64* %yp 75 %div = udiv i64 %x, %y 76 call void @use(i64 %div) readonly 77 br label %loop 78} 79 80; Negative test 81define void @throw_header_before(i64 %x, i64 %y, i1* %cond) { 82; CHECK-LABEL: throw_header_before 83; CHECK-LABEL: loop 84; CHECK: %div = udiv i64 %x, %y 85; CHECK: call void @use(i64 %div) 86entry: 87 br label %loop 88 89loop: ; preds = %entry, %for.inc 90 call void @maythrow() 91 %div = udiv i64 %x, %y 92 call void @use(i64 %div) 93 br label %loop 94} 95 96; The header is known no throw, but the loop is not. We can 97; still lift out of the header. 98define void @nothrow_header(i64 %x, i64 %y, i1 %cond) { 99; CHECK-LABEL: nothrow_header 100; CHECK-LABEL: entry 101; CHECK: %div = udiv i64 %x, %y 102; CHECK-LABEL: loop 103 ; CHECK: call void @use(i64 %div) 104entry: 105 br label %loop 106loop: ; preds = %entry, %for.inc 107 %div = udiv i64 %x, %y 108 br i1 %cond, label %loop-if, label %exit 109loop-if: 110 call void @use(i64 %div) 111 br label %loop 112exit: 113 ret void 114} 115; Negative test - can't move out of throwing block 116define void @nothrow_header_neg(i64 %x, i64 %y, i1 %cond) { 117; CHECK-LABEL: nothrow_header_neg 118; CHECK-LABEL: entry 119; CHECK-LABEL: loop 120; CHECK: %div = udiv i64 %x, %y 121; CHECK: call void @use(i64 %div) 122entry: 123 br label %loop 124loop: ; preds = %entry, %for.inc 125 br label %loop-if 126loop-if: 127 %div = udiv i64 %x, %y 128 call void @use(i64 %div) 129 br label %loop 130} 131