1; Check the optimizer doesn't crash at inlining the function top and all of its callees are inlined. 2; RUN: opt < %s -O3 -S | FileCheck %s 3 4define dso_local void (...)* @second(i8** %p) { 5entry: 6 %p.addr = alloca i8**, align 8 7 store i8** %p, i8*** %p.addr, align 8 8 %tmp = load i8**, i8*** %p.addr, align 8 9 %tmp1 = load i8*, i8** %tmp, align 8 10 %tmp2 = bitcast i8* %tmp1 to void (...)* 11 ret void (...)* %tmp2 12} 13 14define dso_local void @top() { 15entry: 16 ; CHECK: {{.*}} = {{.*}} call {{.*}} @ext 17 ; CHECK-NOT: {{.*}} = {{.*}} call {{.*}} @third 18 ; CHECK-NOT: {{.*}} = {{.*}} call {{.*}} @second 19 ; CHECK-NOT: {{.*}} = {{.*}} call {{.*}} @wrapper 20 %q = alloca i8*, align 8 21 store i8* bitcast (void ()* @third to i8*), i8** %q, align 8 22 %tmp = call void (...)* @second(i8** %q) 23 ; The call to 'wrapper' here is to ensure that its function attributes 24 ; i.e., returning its parameter and having no side effect, will be decuded 25 ; before the next round of inlining happens to 'top' to expose the bug. 26 %call = call void (...)* @wrapper(void (...)* %tmp) 27 ; The indirect call here is to confuse the alias analyzer so that 28 ; an incomplete graph will be built during the first round of inlining. 29 ; This allows the current function to be processed before the actual 30 ; callee, i.e., the function 'run', is processed. Once it's simplified to 31 ; a direct call, it also enables an additional round of inlining with all 32 ; function attributes deduced. 33 call void (...) %call() 34 ret void 35} 36 37define dso_local void (...)* @gen() { 38entry: 39 %call = call void (...)* (...) @ext() 40 ret void (...)* %call 41} 42 43declare dso_local void (...)* @ext(...) 44 45define dso_local void (...)* @wrapper(void (...)* %fn) { 46entry: 47 ret void (...)* %fn 48} 49 50define dso_local void @run(void (...)* %fn) { 51entry: 52 %fn.addr = alloca void (...)*, align 8 53 %f = alloca void (...)*, align 8 54 store void (...)* %fn, void (...)** %fn.addr, align 8 55 %tmp = load void (...)*, void (...)** %fn.addr, align 8 56 %call = call void (...)* @wrapper(void (...)* %tmp) 57 store void (...)* %call, void (...)** %f, align 8 58 %tmp1 = load void (...)*, void (...)** %f, align 8 59 call void (...) %tmp1() 60 ret void 61} 62 63define dso_local void @third() { 64entry: 65 %f = alloca void (...)*, align 8 66 %call = call void (...)* @gen() 67 store void (...)* %call, void (...)** %f, align 8 68 %tmp = load void (...)*, void (...)** %f, align 8 69 call void @run(void (...)* %tmp) 70 ret void 71}