| ; Check the optimizer doesn't crash at inlining the function top and all of its callees are inlined. |
| ; RUN: opt < %s -O3 -S | FileCheck %s |
| |
| define dso_local ptr @second(ptr %p) { |
| entry: |
| %p.addr = alloca ptr, align 8 |
| store ptr %p, ptr %p.addr, align 8 |
| %tmp = load ptr, ptr %p.addr, align 8 |
| %tmp1 = load ptr, ptr %tmp, align 8 |
| ret ptr %tmp1 |
| } |
| |
| define dso_local void @top() { |
| entry: |
| ; CHECK: {{.*}} = {{.*}} call {{.*}} @ext |
| ; CHECK-NOT: {{.*}} = {{.*}} call {{.*}} @third |
| ; CHECK-NOT: {{.*}} = {{.*}} call {{.*}} @second |
| ; CHECK-NOT: {{.*}} = {{.*}} call {{.*}} @wrapper |
| %q = alloca ptr, align 8 |
| store ptr @third, ptr %q, align 8 |
| %tmp = call ptr @second(ptr %q) |
| ; The call to 'wrapper' here is to ensure that its function attributes |
| ; i.e., returning its parameter and having no side effect, will be decuded |
| ; before the next round of inlining happens to 'top' to expose the bug. |
| %call = call ptr @wrapper(ptr %tmp) |
| ; The indirect call here is to confuse the alias analyzer so that |
| ; an incomplete graph will be built during the first round of inlining. |
| ; This allows the current function to be processed before the actual |
| ; callee, i.e., the function 'run', is processed. Once it's simplified to |
| ; a direct call, it also enables an additional round of inlining with all |
| ; function attributes deduced. |
| call void (...) %call() |
| ret void |
| } |
| |
| define dso_local ptr @gen() { |
| entry: |
| %call = call ptr (...) @ext() |
| ret ptr %call |
| } |
| |
| declare dso_local ptr @ext(...) |
| |
| define dso_local ptr @wrapper(ptr %fn) { |
| entry: |
| ret ptr %fn |
| } |
| |
| define dso_local void @run(ptr %fn) { |
| entry: |
| %fn.addr = alloca ptr, align 8 |
| %f = alloca ptr, align 8 |
| store ptr %fn, ptr %fn.addr, align 8 |
| %tmp = load ptr, ptr %fn.addr, align 8 |
| %call = call ptr @wrapper(ptr %tmp) |
| store ptr %call, ptr %f, align 8 |
| %tmp1 = load ptr, ptr %f, align 8 |
| call void (...) %tmp1() |
| ret void |
| } |
| |
| define dso_local void @third() { |
| entry: |
| %f = alloca ptr, align 8 |
| %call = call ptr @gen() |
| store ptr %call, ptr %f, align 8 |
| %tmp = load ptr, ptr %f, align 8 |
| call void @run(ptr %tmp) |
| ret void |
| } |