1; RUN: opt < %s -O2 -S 2; RUN: opt -S -hoist-common-insts -hoist-common-insts -passes=simplifycfg < %s | FileCheck %s --check-prefixes=CHECK 3target datalayout = "p:64:64:64" 4%swift.async_func_pointer = type <{ i32, i32 }> 5%swift.context = type { ptr, ptr } 6 7declare void @f() 8declare void @g() 9declare ptr @llvm.coro.async.resume() 10declare { ptr } @llvm.coro.suspend.async.sl_p0i8s(i32, ptr, ptr, ...) 11declare ptr @llvm.coro.begin(token, ptr writeonly) 12declare token @llvm.coro.id.async(i32, i32, i32, ptr) 13 14declare i1 @llvm.coro.end.async(ptr, i1, ...) 15 16define linkonce_odr hidden ptr @__swift_async_resume_get_context(ptr %0) { 17entry: 18 ret ptr %0 19} 20 21@repoTU = hidden global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @repo to i64), i64 ptrtoint (ptr @repoTU to i64)) to i32), i32 16 }>, align 8 22 23; This test used to crash in optimized mode because simplify cfg would sink the 24; suspend.async() instruction into a common successor block. 25 26; CHECK: swifttailcc void @repo 27; CHECK:llvm.coro.suspend.async.sl_p0s 28; CHECK: br 29; CHECK:llvm.coro.suspend.async.sl_p0s 30; CHECK: br 31; CHECK: ret 32 33define hidden swifttailcc void @repo(ptr swiftasync %0, i1 %cond) { 34entry: 35 %tok = call token @llvm.coro.id.async(i32 16, i32 16, i32 0, ptr @repoTU) 36 %id = call ptr @llvm.coro.begin(token %tok, ptr null) 37 br i1 %cond, label %bb1, label %bb2 38 39bb1: 40 call void @f() 41 %ptr0 = call ptr @llvm.coro.async.resume() 42 call void @f() 43 ; Simplifycfg must not sink the suspend instruction. 44 %t3 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0i8s(i32 0, ptr %ptr0, ptr @__swift_async_resume_get_context, ptr @repo.1, ptr %ptr0, ptr %0) 45 br label %tailblock 46 47bb2: 48 call void @g() 49 %ptr1 = call ptr @llvm.coro.async.resume() 50 call void @g() 51 ; Simplifycfg must not sink the suspend instruction. 52 %t4 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0i8s(i32 0, ptr %ptr1, ptr @__swift_async_resume_get_context, ptr @repo.1, ptr %ptr1, ptr %0) 53 br label %tailblock 54 55tailblock: 56 %t = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %id, i1 false, ptr @repo.0, ptr @return, ptr %0) 57 unreachable 58} 59 60define internal swifttailcc void @repo.0(ptr %0, ptr %1) { 61entry: 62 musttail call swifttailcc void %0(ptr swiftasync %1) 63 ret void 64} 65 66declare swifttailcc void @swift_task_switch(ptr, ptr) 67 68define internal swifttailcc void @repo.1(ptr %0, ptr %1) { 69entry: 70 musttail call swifttailcc void @swift_task_switch(ptr swiftasync %1, ptr %0) 71 ret void 72} 73 74declare swifttailcc void @return(ptr swiftasync) 75 76@repoTU2 = hidden global %swift.async_func_pointer <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @repo2 to i64), i64 ptrtoint (ptr @repoTU2 to i64)) to i32), i32 16 }>, align 8 77 78; This test used to crash in optimized mode because simplify cfg would hoist the 79; async.resume() instruction into a common block. 80 81; CHECK: swifttailcc void @repo2 82; CHECK: entry: 83; CHECK: br i1 84 85; CHECK: @llvm.coro.async.resume() 86; CHECK: llvm.coro.suspend.async.sl_p0s 87; CHECK: br 88 89; CHECK:@llvm.coro.async.resume() 90; CHECK:llvm.coro.suspend.async.sl_p0s 91; CHECK: br 92 93; CHECK: ret 94 95define hidden swifttailcc void @repo2(ptr swiftasync %0, i1 %cond) { 96entry: 97 %tok = call token @llvm.coro.id.async(i32 16, i32 16, i32 0, ptr @repoTU2) 98 %id = call ptr @llvm.coro.begin(token %tok, ptr null) 99 br i1 %cond, label %bb1, label %bb2 100 101bb1: 102 ; Simplifycfg must not hoist the resume instruction. 103 %ptr0 = call ptr @llvm.coro.async.resume() 104 call void @f() 105 %t3 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0i8s(i32 0, ptr %ptr0, ptr @__swift_async_resume_get_context, ptr @repo.1, ptr %ptr0, ptr %0) 106 call void @f() 107 br label %tailblock 108 109bb2: 110 ; Simplifycfg must not hoist the resume instruction. 111 %ptr1 = call ptr @llvm.coro.async.resume() 112 call void @g() 113 %t4 = call { ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0i8s(i32 0, ptr %ptr1, ptr @__swift_async_resume_get_context, ptr @repo.1, ptr %ptr1, ptr %0) 114 call void @g() 115 br label %tailblock 116 117tailblock: 118 %t = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %id, i1 false, ptr @repo.0, ptr @return, ptr %0) 119 unreachable 120} 121