| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 |
| ; RUN: opt -S -passes=inline %s | FileCheck %s |
| ; RUN: opt -S -passes='cgscc(inline)' %s | FileCheck %s |
| ; RUN: opt -S -passes='module-inline' %s | FileCheck %s |
| |
| declare void @foo() |
| declare void @bar() |
| |
| define void @callee(ptr %arg) { |
| ; CHECK-LABEL: define void @callee |
| ; CHECK-SAME: (ptr [[ARG:%.*]]) { |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[ARG]], null |
| ; CHECK-NEXT: br i1 [[CMP]], label [[EXPENSIVE:%.*]], label [[DONE:%.*]] |
| ; CHECK: expensive: |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: ret void |
| ; CHECK: done: |
| ; CHECK-NEXT: call void @bar() |
| ; CHECK-NEXT: ret void |
| ; |
| %cmp = icmp eq ptr %arg, null |
| br i1 %cmp, label %expensive, label %done |
| |
| ; This block is designed to be too expensive to inline. We can only inline |
| ; callee if this block is known to be dead. |
| expensive: |
| call void @foo() |
| call void @foo() |
| call void @foo() |
| call void @foo() |
| call void @foo() |
| call void @foo() |
| call void @foo() |
| call void @foo() |
| call void @foo() |
| call void @foo() |
| ret void |
| |
| done: |
| call void @bar() |
| ret void |
| } |
| |
| ; Positive test - arg is known non null |
| define void @caller(ptr nonnull %arg) { |
| ; CHECK-LABEL: define void @caller |
| ; CHECK-SAME: (ptr nonnull [[ARG:%.*]]) { |
| ; CHECK-NEXT: call void @bar() |
| ; CHECK-NEXT: ret void |
| ; |
| call void @callee(ptr nonnull %arg) |
| ret void |
| } |
| |
| ; Negative test - arg is not known to be non null |
| define void @caller2(ptr %arg) { |
| ; CHECK-LABEL: define void @caller2 |
| ; CHECK-SAME: (ptr [[ARG:%.*]]) { |
| ; CHECK-NEXT: call void @callee(ptr [[ARG]]) |
| ; CHECK-NEXT: ret void |
| ; |
| call void @callee(ptr %arg) |
| ret void |
| } |
| |
| define void @caller3(ptr %arg) { |
| ; CHECK-LABEL: define void @caller3 |
| ; CHECK-SAME: (ptr [[ARG:%.*]]) { |
| ; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq ptr [[ARG]], null |
| ; CHECK-NEXT: br i1 [[CMP_I]], label [[EXPENSIVE_I:%.*]], label [[DONE_I:%.*]] |
| ; CHECK: expensive.i: |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: call void @foo() |
| ; CHECK-NEXT: br label [[CALLEE_EXIT:%.*]] |
| ; CHECK: done.i: |
| ; CHECK-NEXT: call void @bar() |
| ; CHECK-NEXT: br label [[CALLEE_EXIT]] |
| ; CHECK: callee.exit: |
| ; CHECK-NEXT: ret void |
| ; |
| call void @callee(ptr nonnull %arg) |
| ret void |
| } |
| |
| define void @caller4(ptr dereferenceable(8) %arg) { |
| ; CHECK-LABEL: define void @caller4 |
| ; CHECK-SAME: (ptr dereferenceable(8) [[ARG:%.*]]) { |
| ; CHECK-NEXT: call void @callee(ptr dereferenceable(8) [[ARG]]) |
| ; CHECK-NEXT: ret void |
| ; |
| call void @callee(ptr dereferenceable(8) %arg) |
| ret void |
| } |
| |
| define void @caller5(ptr dereferenceable(8) %arg) { |
| ; CHECK-LABEL: define void @caller5 |
| ; CHECK-SAME: (ptr dereferenceable(8) [[ARG:%.*]]) { |
| ; CHECK-NEXT: call void @callee(ptr [[ARG]]) |
| ; CHECK-NEXT: ret void |
| ; |
| call void @callee(ptr %arg) |
| ret void |
| } |
| |
| define void @caller6(ptr %arg) { |
| ; CHECK-LABEL: define void @caller6 |
| ; CHECK-SAME: (ptr [[ARG:%.*]]) { |
| ; CHECK-NEXT: call void @callee(ptr dereferenceable(8) [[ARG]]) |
| ; CHECK-NEXT: ret void |
| ; |
| call void @callee(ptr dereferenceable(8) %arg) |
| ret void |
| } |
| |
| declare ptr @buz() |
| define nonnull ptr @callee7() { |
| ; CHECK-LABEL: define nonnull ptr @callee7() { |
| ; CHECK-NEXT: [[R:%.*]] = call ptr @buz() #[[ATTR0:[0-9]+]] |
| ; CHECK-NEXT: ret ptr [[R]] |
| ; |
| %r = call ptr @buz() willreturn nounwind |
| ret ptr %r |
| } |
| |
| define ptr @caller7() { |
| ; CHECK-LABEL: define ptr @caller7() { |
| ; CHECK-NEXT: [[R_I:%.*]] = call nonnull ptr @buz() #[[ATTR0]] |
| ; CHECK-NEXT: ret ptr [[R_I]] |
| ; |
| %r = call ptr @callee7() |
| ret ptr %r |
| } |
| |
| define nonnull ptr @callee8() { |
| ; CHECK-LABEL: define nonnull ptr @callee8() { |
| ; CHECK-NEXT: [[R:%.*]] = call ptr @buz() |
| ; CHECK-NEXT: ret ptr [[R]] |
| ; |
| %r = call ptr @buz() |
| ret ptr %r |
| } |
| |
| define ptr @caller8() { |
| ; CHECK-LABEL: define ptr @caller8() { |
| ; CHECK-NEXT: [[R_I:%.*]] = call nonnull ptr @buz() |
| ; CHECK-NEXT: ret ptr [[R_I]] |
| ; |
| %r = call nonnull ptr @callee8() |
| ret ptr %r |
| } |
| |
| define ptr @callee9() { |
| ; CHECK-LABEL: define ptr @callee9() { |
| ; CHECK-NEXT: [[R:%.*]] = call ptr @buz() |
| ; CHECK-NEXT: call void @foo() #[[ATTR1:[0-9]+]] |
| ; CHECK-NEXT: ret ptr [[R]] |
| ; |
| %r = call ptr @buz() |
| call void @foo() nounwind |
| ret ptr %r |
| } |
| |
| define ptr @caller9() { |
| ; CHECK-LABEL: define ptr @caller9() { |
| ; CHECK-NEXT: [[R_I:%.*]] = call ptr @buz() |
| ; CHECK-NEXT: call void @foo() #[[ATTR1]] |
| ; CHECK-NEXT: ret ptr [[R_I]] |
| ; |
| %r = call nonnull ptr @callee9() |
| ret ptr %r |
| } |