| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -S -passes=licm < %s | FileCheck %s |
| |
| declare void @use_nothrow(i64 %a) nounwind |
| declare void @use(i64 %a) |
| declare void @maythrow() |
| |
| define void @nothrow(i64 %x, i64 %y, ptr %cond) { |
| ; CHECK-LABEL: define void @nothrow( |
| ; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], ptr [[COND:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[X]], [[Y]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br label %[[LOOP2:.*]] |
| ; CHECK: [[LOOP2]]: |
| ; CHECK-NEXT: call void @use_nothrow(i64 [[DIV]]) |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %entry, %for.inc |
| %div = udiv i64 %x, %y |
| br label %loop2 |
| |
| loop2: |
| call void @use_nothrow(i64 %div) |
| br label %loop |
| } |
| |
| ; The udiv is guarantee to execute if the loop is |
| define void @throw_header_after(i64 %x, i64 %y, ptr %cond) { |
| ; CHECK-LABEL: define void @throw_header_after( |
| ; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], ptr [[COND:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[X]], [[Y]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: call void @use(i64 [[DIV]]) |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %entry, %for.inc |
| %div = udiv i64 %x, %y |
| call void @use(i64 %div) |
| br label %loop |
| } |
| |
| define void @throw_header_after_rec(ptr %xp, ptr %yp, ptr %cond) { |
| ; CHECK-LABEL: define void @throw_header_after_rec( |
| ; CHECK-SAME: ptr [[XP:%.*]], ptr [[YP:%.*]], ptr [[COND:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[X:%.*]] = load i64, ptr [[XP]], align 4 |
| ; CHECK-NEXT: [[Y:%.*]] = load i64, ptr [[YP]], align 4 |
| ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[X]], [[Y]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: call void @use(i64 [[DIV]]) #[[ATTR1:[0-9]+]] |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %entry, %for.inc |
| %x = load i64, ptr %xp |
| %y = load i64, ptr %yp |
| %div = udiv i64 %x, %y |
| call void @use(i64 %div) readonly |
| br label %loop |
| } |
| |
| ; Similiar to the above, but the hoistable instruction (%y in this case) |
| ; happens not to be the first instruction in the block. |
| define void @throw_header_after_nonfirst(ptr %xp, ptr %yp, ptr %cond) { |
| ; CHECK-LABEL: define void @throw_header_after_nonfirst( |
| ; CHECK-SAME: ptr [[XP:%.*]], ptr [[YP:%.*]], ptr [[COND:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*]]: |
| ; CHECK-NEXT: [[Y:%.*]] = load i64, ptr [[YP]], align 4 |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[DIV:%.*]], %[[LOOP]] ] |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr i64, ptr [[XP]], i64 [[IV]] |
| ; CHECK-NEXT: [[X:%.*]] = load i64, ptr [[GEP]], align 4 |
| ; CHECK-NEXT: [[DIV]] = udiv i64 [[X]], [[Y]] |
| ; CHECK-NEXT: call void @use(i64 [[DIV]]) #[[ATTR1]] |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %entry, %for.inc |
| %iv = phi i64 [0, %entry], [%div, %loop] |
| %gep = getelementptr i64, ptr %xp, i64 %iv |
| %x = load i64, ptr %gep |
| %y = load i64, ptr %yp |
| %div = udiv i64 %x, %y |
| call void @use(i64 %div) readonly |
| br label %loop |
| } |
| |
| ; Negative test |
| define void @throw_header_before(i64 %x, i64 %y, ptr %cond) { |
| ; CHECK-LABEL: define void @throw_header_before( |
| ; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], ptr [[COND:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: call void @maythrow() |
| ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[X]], [[Y]] |
| ; CHECK-NEXT: call void @use(i64 [[DIV]]) |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %entry, %for.inc |
| call void @maythrow() |
| %div = udiv i64 %x, %y |
| call void @use(i64 %div) |
| br label %loop |
| } |
| |
| ; The header is known no throw, but the loop is not. We can |
| ; still lift out of the header. |
| define void @nothrow_header(i64 %x, i64 %y, i1 %cond) { |
| ; CHECK-LABEL: define void @nothrow_header( |
| ; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], i1 [[COND:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[X]], [[Y]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br i1 [[COND]], label %[[LOOP_IF:.*]], label %[[EXIT:.*]] |
| ; CHECK: [[LOOP_IF]]: |
| ; CHECK-NEXT: call void @use(i64 [[DIV]]) |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; CHECK: [[EXIT]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| loop: ; preds = %entry, %for.inc |
| %div = udiv i64 %x, %y |
| br i1 %cond, label %loop-if, label %exit |
| loop-if: |
| call void @use(i64 %div) |
| br label %loop |
| exit: |
| ret void |
| } |
| |
| ; Positive test - can hoist something that happens before thrower. |
| define void @nothrow_header_pos(i64 %x, i64 %y, i1 %cond) { |
| ; CHECK-LABEL: define void @nothrow_header_pos( |
| ; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], i1 [[COND:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[X]], [[Y]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br label %[[LOOP_IF:.*]] |
| ; CHECK: [[LOOP_IF]]: |
| ; CHECK-NEXT: call void @use(i64 [[DIV]]) |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; |
| entry: |
| br label %loop |
| loop: ; preds = %entry, %for.inc |
| br label %loop-if |
| loop-if: |
| %div = udiv i64 %x, %y |
| call void @use(i64 %div) |
| br label %loop |
| } |
| |
| |
| ; Negative test - can't move out of throwing block |
| define void @nothrow_header_neg(i64 %x, i64 %y, i1 %cond) { |
| ; CHECK-LABEL: define void @nothrow_header_neg( |
| ; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]], i1 [[COND:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br label %[[LOOP:.*]] |
| ; CHECK: [[LOOP]]: |
| ; CHECK-NEXT: br label %[[LOOP_IF:.*]] |
| ; CHECK: [[LOOP_IF]]: |
| ; CHECK-NEXT: call void @maythrow() |
| ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[X]], [[Y]] |
| ; CHECK-NEXT: call void @use(i64 [[DIV]]) |
| ; CHECK-NEXT: br label %[[LOOP]] |
| ; |
| entry: |
| br label %loop |
| loop: ; preds = %entry, %for.inc |
| br label %loop-if |
| loop-if: |
| call void @maythrow() |
| %div = udiv i64 %x, %y |
| call void @use(i64 %div) |
| br label %loop |
| } |