348 lines · plain
1; Tests that the dynamic allocation and deallocation of the coroutine frame is2; elided and any tail calls referencing the coroutine frame has the tail3; call attribute removed.4; RUN: opt < %s -S \5; RUN: -passes='cgscc(inline,function(coro-elide,instsimplify,simplifycfg))' \6; RUN: -aa-pipeline='basic-aa' | FileCheck %s7 8declare void @print(i32) nounwind9 10%f.frame = type {i32}11 12declare void @bar(ptr)13 14declare fastcc void @f.resume(ptr align 4 dereferenceable(4))15declare fastcc void @f.destroy(ptr)16declare fastcc void @f.cleanup(ptr)17 18declare void @may_throw()19declare ptr @CustomAlloc(i32)20declare void @CustomFree(ptr)21 22@f.resumers = internal constant [3 x ptr]23 [ptr @f.resume, ptr @f.destroy, ptr @f.cleanup]24 25; a coroutine start function26define ptr @f() personality ptr null {27entry:28 %id = call token @llvm.coro.id(i32 0, ptr null,29 ptr @f,30 ptr @f.resumers)31 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)32 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin33dyn.alloc:34 %alloc = call ptr @CustomAlloc(i32 4)35 br label %coro.begin36coro.begin:37 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]38 %hdl = call ptr @llvm.coro.begin(token %id, ptr %phi)39 invoke void @may_throw()40 to label %ret unwind label %ehcleanup41ret:42 ret ptr %hdl43 44ehcleanup:45 %tok = cleanuppad within none []46 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)47 %need.dyn.free = icmp ne ptr %mem, null48 br i1 %need.dyn.free, label %dyn.free, label %if.end49dyn.free:50 call void @CustomFree(ptr %mem)51 br label %if.end52if.end:53 cleanupret from %tok unwind to caller54}55 56; CHECK-LABEL: @callResume(57define void @callResume() {58entry:59; CHECK: alloca [4 x i8], align 460; CHECK-NOT: coro.begin61; CHECK-NOT: CustomAlloc62; CHECK: call void @may_throw()63 %hdl = call ptr @f()64 65; Need to remove 'tail' from the first call to @bar66; CHECK-NOT: tail call void @bar(67; CHECK: call void @bar(68 tail call void @bar(ptr %hdl)69; CHECK: tail call void @bar(70 tail call void @bar(ptr null)71 72; CHECK-NEXT: call fastcc void @f.resume(ptr %0)73 %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)74 call fastcc void %0(ptr %hdl)75 76; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)77 %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)78 call fastcc void %1(ptr %hdl)79 80; CHECK-NEXT: ret void81 ret void82}83 84; CHECK-LABEL: @callResume_with_coro_suspend_1(85define void @callResume_with_coro_suspend_1() {86entry:87; CHECK: alloca [4 x i8], align 488; CHECK-NOT: coro.begin89; CHECK-NOT: CustomAlloc90; CHECK: call void @may_throw()91 %hdl = call ptr @f()92 93; CHECK-NEXT: call fastcc void @f.resume(ptr %0)94 %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)95 call fastcc void %0(ptr %hdl)96 %1 = call token @llvm.coro.save(ptr %hdl)97 %2 = call i8 @llvm.coro.suspend(token %1, i1 false)98 switch i8 %2, label %coro.ret [99 i8 0, label %final.suspend100 i8 1, label %cleanups101 ]102 103; CHECK-LABEL: final.suspend:104final.suspend:105; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)106 %3 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)107 call fastcc void %3(ptr %hdl)108 %4 = call token @llvm.coro.save(ptr %hdl)109 %5 = call i8 @llvm.coro.suspend(token %4, i1 true)110 switch i8 %5, label %coro.ret [111 i8 0, label %coro.ret112 i8 1, label %cleanups113 ]114 115; CHECK-LABEL: cleanups:116cleanups:117; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)118 %6 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)119 call fastcc void %6(ptr %hdl)120 br label %coro.ret121 122; CHECK-LABEL: coro.ret:123coro.ret:124; CHECK-NEXT: ret void125 ret void126}127 128; CHECK-LABEL: @callResume_with_coro_suspend_2(129define void @callResume_with_coro_suspend_2() personality ptr null {130entry:131; CHECK: alloca [4 x i8], align 4132; CHECK-NOT: coro.begin133; CHECK-NOT: CustomAlloc134; CHECK: call void @may_throw()135 %hdl = call ptr @f()136 137 %0 = call token @llvm.coro.save(ptr %hdl)138; CHECK: invoke fastcc void @f.resume(ptr %0)139 %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)140 invoke fastcc void %1(ptr %hdl)141 to label %invoke.cont1 unwind label %lpad142 143; CHECK-LABEL: invoke.cont1:144invoke.cont1:145 %2 = call i8 @llvm.coro.suspend(token %0, i1 false)146 switch i8 %2, label %coro.ret [147 i8 0, label %final.ready148 i8 1, label %cleanups149 ]150 151; CHECK-LABEL: lpad:152lpad:153 %3 = landingpad { ptr, i32 }154 catch ptr null155; CHECK: call fastcc void @f.cleanup(ptr %0)156 %4 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)157 call fastcc void %4(ptr %hdl)158 br label %final.suspend159 160; CHECK-LABEL: final.ready:161final.ready:162; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)163 %5 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)164 call fastcc void %5(ptr %hdl)165 br label %final.suspend166 167; CHECK-LABEL: final.suspend:168final.suspend:169 %6 = call token @llvm.coro.save(ptr %hdl)170 %7 = call i8 @llvm.coro.suspend(token %6, i1 true)171 switch i8 %7, label %coro.ret [172 i8 0, label %coro.ret173 i8 1, label %cleanups174 ]175 176; CHECK-LABEL: cleanups:177cleanups:178; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)179 %8 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)180 call fastcc void %8(ptr %hdl)181 br label %coro.ret182 183; CHECK-LABEL: coro.ret:184coro.ret:185; CHECK-NEXT: ret void186 ret void187}188 189; CHECK-LABEL: @callResume_with_coro_suspend_3(190define void @callResume_with_coro_suspend_3(i8 %cond) {191entry:192; CHECK: alloca [4 x i8], align 4193 switch i8 %cond, label %coro.ret [194 i8 0, label %init.suspend195 i8 1, label %coro.ret196 ]197 198init.suspend:199; CHECK-NOT: llvm.coro.begin200; CHECK-NOT: CustomAlloc201; CHECK: call void @may_throw()202 %hdl = call ptr @f()203; CHECK-NEXT: call fastcc void @f.resume(ptr %0)204 %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)205 call fastcc void %0(ptr %hdl)206 %1 = call token @llvm.coro.save(ptr %hdl)207 %2 = call i8 @llvm.coro.suspend(token %1, i1 false)208 switch i8 %2, label %coro.ret [209 i8 0, label %final.suspend210 i8 1, label %cleanups211 ]212 213; CHECK-LABEL: final.suspend:214final.suspend:215; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)216 %3 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)217 call fastcc void %3(ptr %hdl)218 %4 = call token @llvm.coro.save(ptr %hdl)219 %5 = call i8 @llvm.coro.suspend(token %4, i1 true)220 switch i8 %5, label %coro.ret [221 i8 0, label %coro.ret222 i8 1, label %cleanups223 ]224 225; CHECK-LABEL: cleanups:226cleanups:227; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)228 %6 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)229 call fastcc void %6(ptr %hdl)230 br label %coro.ret231 232; CHECK-LABEL: coro.ret:233coro.ret:234; CHECK-NEXT: ret void235 ret void236}237 238 239 240; CHECK-LABEL: @callResume_PR34897_no_elision(241define void @callResume_PR34897_no_elision(i1 %cond) {242; CHECK-LABEL: entry:243entry:244; CHECK: call ptr @CustomAlloc(245 %hdl = call ptr @f()246; CHECK: tail call void @bar(247 tail call void @bar(ptr %hdl)248; CHECK: tail call void @bar(249 tail call void @bar(ptr null)250 br i1 %cond, label %if.then, label %if.else251 252; CHECK-LABEL: if.then:253if.then:254; CHECK: call fastcc void @f.resume(ptr255 %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)256 call fastcc void %0(ptr %hdl)257; CHECK-NEXT: call fastcc void @f.destroy(ptr258 %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)259 call fastcc void %1(ptr %hdl)260 br label %return261 262if.else:263 br label %return264 265; CHECK-LABEL: return:266return:267; CHECK: ret void268 ret void269}270 271; CHECK-LABEL: @callResume_PR34897_elision(272define void @callResume_PR34897_elision(i1 %cond) {273; CHECK-LABEL: entry:274entry:275; CHECK: alloca [4 x i8], align 4276; CHECK: tail call void @bar(277 tail call void @bar(ptr null)278 br i1 %cond, label %if.then, label %if.else279 280if.then:281; CHECK-NOT: CustomAlloc282; CHECK: call void @may_throw()283 %hdl = call ptr @f()284; CHECK: call void @bar(285 tail call void @bar(ptr %hdl)286; CHECK: call fastcc void @f.resume(ptr287 %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)288 call fastcc void %0(ptr %hdl)289; CHECK-NEXT: call fastcc void @f.cleanup(ptr290 %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)291 call fastcc void %1(ptr %hdl)292 br label %return293 294if.else:295 br label %return296 297; CHECK-LABEL: return:298return:299; CHECK: ret void300 ret void301}302 303 304; a coroutine start function (cannot elide heap alloc, due to second argument to305; coro.begin not pointint to coro.alloc)306define ptr @f_no_elision() personality ptr null {307entry:308 %id = call token @llvm.coro.id(i32 0, ptr null,309 ptr @f_no_elision,310 ptr @f.resumers)311 %alloc = call ptr @CustomAlloc(i32 4)312 %hdl = call ptr @llvm.coro.begin(token %id, ptr %alloc)313 ret ptr %hdl314}315 316; CHECK-LABEL: @callResume_no_elision(317define void @callResume_no_elision() {318entry:319; CHECK: call ptr @CustomAlloc(320 %hdl = call ptr @f_no_elision()321 322; Tail call should remain tail calls323; CHECK: tail call void @bar(324 tail call void @bar(ptr %hdl)325; CHECK: tail call void @bar(326 tail call void @bar(ptr null)327 328; CHECK-NEXT: call fastcc void @f.resume(ptr329 %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)330 call fastcc void %0(ptr %hdl)331 332; CHECK-NEXT: call fastcc void @f.destroy(ptr333 %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)334 call fastcc void %1(ptr %hdl)335 336; CHECK-NEXT: ret void337 ret void338}339 340declare token @llvm.coro.id(i32, ptr, ptr, ptr)341declare i1 @llvm.coro.alloc(token)342declare ptr @llvm.coro.free(token, ptr)343declare ptr @llvm.coro.begin(token, ptr)344declare ptr @llvm.coro.frame(token)345declare ptr @llvm.coro.subfn.addr(ptr, i8)346declare i8 @llvm.coro.suspend(token, i1)347declare token @llvm.coro.save(ptr)348