| ; 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='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 | |
| } |