| ; RUN: opt -passes=inline -inline-threshold=0 -inline-all-viable-calls -S < %s | FileCheck %s |
| |
| ; Check that viable calls that are beyond the cost threshold are still inlined. |
| define i32 @callee_simple(i32 %x) { |
| %1 = add i32 %x, 1 |
| %2 = mul i32 %1, 2 |
| %3 = sub i32 %2, 1 |
| %4 = add i32 %3, 3 |
| %5 = mul i32 %4, 2 |
| %6 = sub i32 %5, 2 |
| %7 = add i32 %6, 1 |
| ret i32 %7 |
| } |
| |
| ; Check that user decisions are respected. |
| define i32 @callee_alwaysinline(i32 %x) alwaysinline { |
| %sub = sub i32 %x, 3 |
| ret i32 %sub |
| } |
| |
| define i32 @callee_noinline(i32 %x) noinline { |
| %div = sdiv i32 %x, 2 |
| ret i32 %div |
| } |
| |
| define i32 @callee_optnone(i32 %x) optnone noinline { |
| %rem = srem i32 %x, 2 |
| ret i32 %rem |
| } |
| |
| define i32 @caller(i32 %a) { |
| ; CHECK-LABEL: define i32 @caller( |
| ; CHECK-SAME: i32 [[A:%.*]]) { |
| ; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[A]], 1 |
| ; CHECK-NEXT: [[TMP8:%.*]] = mul i32 [[TMP7]], 2 |
| ; CHECK-NEXT: [[TMP3:%.*]] = sub i32 [[TMP8]], 1 |
| ; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[TMP3]], 3 |
| ; CHECK-NEXT: [[TMP5:%.*]] = mul i32 [[TMP4]], 2 |
| ; CHECK-NEXT: [[TMP6:%.*]] = sub i32 [[TMP5]], 2 |
| ; CHECK-NEXT: [[ADD_I:%.*]] = add i32 [[TMP6]], 1 |
| ; CHECK-NEXT: [[SUB_I:%.*]] = sub i32 [[ADD_I]], 3 |
| ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @callee_noinline(i32 [[SUB_I]]) |
| ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @callee_optnone(i32 [[TMP1]]) |
| ; CHECK-NEXT: [[SUM:%.*]] = add i32 [[TMP2]], [[TMP1]] |
| ; CHECK-NEXT: ret i32 [[SUM]] |
| ; |
| %1 = call i32 @callee_simple(i32 %a) |
| %2 = call i32 @callee_alwaysinline(i32 %1) |
| %3 = call i32 @callee_noinline(i32 %2) |
| %4 = call i32 @callee_optnone(i32 %3) |
| %sum = add i32 %4, %3 |
| ret i32 %sum |
| } |
| |
| ; Check that non-viable calls are not inlined |
| |
| ; Test recursive function is not inlined |
| define i32 @recursive(i32 %n) { |
| entry: |
| %cmp = icmp eq i32 %n, 0 |
| br i1 %cmp, label %base, label %recurse |
| |
| base: |
| ret i32 0 |
| |
| recurse: |
| %dec = sub i32 %n, 1 |
| %rec = call i32 @recursive(i32 %dec) |
| %add = add i32 %rec, 1 |
| ret i32 %add |
| } |
| |
| define i32 @call_recursive(i32 %x) { |
| ; CHECK-LABEL: define i32 @call_recursive( |
| ; CHECK-SAME: i32 [[X:%.*]]) { |
| ; CHECK-NEXT: [[R:%.*]] = call i32 @recursive(i32 [[X]]) |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %r = call i32 @recursive(i32 %x) |
| ret i32 %r |
| } |
| |
| ; Test indirectbr prevents inlining |
| define void @has_indirectbr(ptr %ptr, i32 %cond) { |
| entry: |
| switch i32 %cond, label %default [ |
| i32 0, label %target0 |
| i32 1, label %target1 |
| ] |
| |
| target0: |
| br label %end |
| |
| target1: |
| br label %end |
| |
| default: |
| br label %end |
| |
| end: |
| indirectbr ptr %ptr, [label %target0, label %target1] |
| ret void |
| } |
| |
| define void @call_indirectbr(ptr %p, i32 %c) { |
| ; CHECK-LABEL: define void @call_indirectbr( |
| ; CHECK-SAME: ptr [[P:%.*]], i32 [[C:%.*]]) { |
| ; CHECK-NEXT: call void @has_indirectbr(ptr [[P]], i32 [[C]]) |
| ; CHECK-NEXT: ret void |
| ; |
| call void @has_indirectbr(ptr %p, i32 %c) |
| ret void |
| } |
| |