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