418 lines · plain
1; Test no suspend coroutines2; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s3 4; Coroutine with no-suspends will turn into:5;6; CHECK-LABEL: define void @no_suspends(7; CHECK-NEXT: entry:8; CHECK-NEXT: call void @print(i32 %n)9; CHECK-NEXT: ret void10;11define void @no_suspends(i32 %n) presplitcoroutine {12entry:13 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)14 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)15 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin16dyn.alloc:17 %size = call i32 @llvm.coro.size.i32()18 %alloc = call ptr @malloc(i32 %size)19 br label %coro.begin20coro.begin:21 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]22 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)23 br label %body24body:25 call void @print(i32 %n)26 br label %cleanup27cleanup:28 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)29 %need.dyn.free = icmp ne ptr %mem, null30 br i1 %need.dyn.free, label %dyn.free, label %suspend31dyn.free:32 call void @free(ptr %mem)33 br label %suspend34suspend:35 call void @llvm.coro.end(ptr %hdl, i1 false, token none)36 ret void37}38 39; SimplifySuspendPoint will detect that coro.resume resumes itself and will40; replace suspend with a jump to %resume label turning it into no-suspend41; coroutine.42;43; CHECK-LABEL: define void @simplify_resume(44; CHECK-NEXT: entry:45; CHECK-NEXT: call void @llvm.memcpy46; CHECK-NEXT: call void @print(i32 0)47; CHECK-NEXT: ret void48;49define void @simplify_resume(ptr %src, ptr %dst) presplitcoroutine {50entry:51 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)52 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)53 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin54dyn.alloc:55 %size = call i32 @llvm.coro.size.i32()56 %alloc = call ptr @malloc(i32 %size)57 br label %coro.begin58coro.begin:59 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]60 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)61 br label %body62body:63 %save = call token @llvm.coro.save(ptr %hdl)64 ; memcpy intrinsics should not prevent simplification.65 call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 1, i1 false)66 %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)67 call fastcc void %subfn(ptr %hdl)68 %0 = call i8 @llvm.coro.suspend(token %save, i1 false)69 switch i8 %0, label %suspend [i8 0, label %resume70 i8 1, label %pre.cleanup]71resume:72 call void @print(i32 0)73 br label %cleanup74 75pre.cleanup:76 call void @print(i32 1)77 br label %cleanup78 79cleanup:80 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)81 call void @free(ptr %mem)82 br label %suspend83suspend:84 call void @llvm.coro.end(ptr %hdl, i1 false, token none)85 ret void86}87 88; SimplifySuspendPoint will detect that coroutine destroys itself and will89; replace suspend with a jump to %cleanup label turning it into no-suspend90; coroutine.91;92; CHECK-LABEL: define void @simplify_destroy(93; CHECK-NEXT: entry:94; CHECK-NEXT: call void @print(i32 1)95; CHECK-NEXT: ret void96;97define void @simplify_destroy() presplitcoroutine personality i32 0 {98entry:99 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)100 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)101 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin102dyn.alloc:103 %size = call i32 @llvm.coro.size.i32()104 %alloc = call ptr @malloc(i32 %size)105 br label %coro.begin106coro.begin:107 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]108 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)109 br label %body110body:111 %save = call token @llvm.coro.save(ptr %hdl)112 %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)113 invoke fastcc void %subfn(ptr %hdl) to label %real_susp unwind label %lpad114 115real_susp:116 %0 = call i8 @llvm.coro.suspend(token %save, i1 false)117 switch i8 %0, label %suspend [i8 0, label %resume118 i8 1, label %pre.cleanup]119resume:120 call void @print(i32 0)121 br label %cleanup122 123pre.cleanup:124 call void @print(i32 1)125 br label %cleanup126 127cleanup:128 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)129 call void @free(ptr %mem)130 br label %suspend131suspend:132 call void @llvm.coro.end(ptr %hdl, i1 false, token none)133 ret void134lpad:135 %lpval = landingpad { ptr, i32 }136 cleanup137 138 call void @print(i32 2)139 resume { ptr, i32 } %lpval140}141 142; SimplifySuspendPoint will detect that coro.resume resumes itself and will143; replace suspend with a jump to %resume label turning it into no-suspend144; coroutine.145;146; CHECK-LABEL: define void @simplify_resume_with_inlined_if(147; CHECK-NEXT: entry:148; CHECK-NEXT: br i1149; CHECK: call void @print(i32 0)150; CHECK-NEXT: ret void151;152define void @simplify_resume_with_inlined_if(ptr %src, ptr %dst, i1 %cond) presplitcoroutine {153entry:154 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)155 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)156 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin157dyn.alloc:158 %size = call i32 @llvm.coro.size.i32()159 %alloc = call ptr @malloc(i32 %size)160 br label %coro.begin161coro.begin:162 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]163 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)164 br label %body165body:166 %save = call token @llvm.coro.save(ptr %hdl)167 br i1 %cond, label %if.then, label %if.else168if.then:169 call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 1, i1 false)170 br label %if.end171if.else:172 call void @llvm.memcpy.p0.p0.i64(ptr %src, ptr %dst, i64 1, i1 false)173 br label %if.end174if.end:175 %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)176 call fastcc void %subfn(ptr %hdl)177 %0 = call i8 @llvm.coro.suspend(token %save, i1 false)178 switch i8 %0, label %suspend [i8 0, label %resume179 i8 1, label %pre.cleanup]180resume:181 call void @print(i32 0)182 br label %cleanup183 184pre.cleanup:185 call void @print(i32 1)186 br label %cleanup187 188cleanup:189 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)190 call void @free(ptr %mem)191 br label %suspend192suspend:193 call void @llvm.coro.end(ptr %hdl, i1 false, token none)194 ret void195}196 197 198 199; SimplifySuspendPoint won't be able to simplify if it detects that there are200; other calls between coro.save and coro.suspend. They potentially can call201; resume or destroy, so we should not simplify this suspend point.202;203; CHECK-LABEL: define void @cannot_simplify_other_calls(204; CHECK-NEXT: entry:205; CHECK-NEXT: llvm.coro.id206 207define void @cannot_simplify_other_calls() presplitcoroutine {208entry:209 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)210 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)211 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin212dyn.alloc:213 %size = call i32 @llvm.coro.size.i32()214 %alloc = call ptr @malloc(i32 %size)215 br label %coro.begin216coro.begin:217 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]218 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)219 br label %body220body:221 %save = call token @llvm.coro.save(ptr %hdl)222 br label %body1223 224body1:225 call void @foo()226 br label %body2227 228body2:229 %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)230 call fastcc void %subfn(ptr %hdl)231 %0 = call i8 @llvm.coro.suspend(token %save, i1 false)232 switch i8 %0, label %suspend [i8 0, label %resume233 i8 1, label %pre.cleanup]234resume:235 call void @print(i32 0)236 br label %cleanup237 238pre.cleanup:239 call void @print(i32 1)240 br label %cleanup241 242cleanup:243 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)244 call void @free(ptr %mem)245 br label %suspend246suspend:247 call void @llvm.coro.end(ptr %hdl, i1 false, token none)248 ret void249}250 251; SimplifySuspendPoint won't be able to simplify if it detects that there are252; other calls between coro.save and coro.suspend. They potentially can call253; resume or destroy, so we should not simplify this suspend point.254;255; CHECK-LABEL: define void @cannot_simplify_calls_in_terminator(256; CHECK-NEXT: entry:257; CHECK-NEXT: llvm.coro.id258 259define void @cannot_simplify_calls_in_terminator() presplitcoroutine personality i32 0 {260entry:261 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)262 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)263 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin264dyn.alloc:265 %size = call i32 @llvm.coro.size.i32()266 %alloc = call ptr @malloc(i32 %size)267 br label %coro.begin268coro.begin:269 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]270 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)271 br label %body272body:273 %save = call token @llvm.coro.save(ptr %hdl)274 invoke void @foo() to label %resume_cont unwind label %lpad275resume_cont:276 %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)277 call fastcc void %subfn(ptr %hdl)278 %0 = call i8 @llvm.coro.suspend(token %save, i1 false)279 switch i8 %0, label %suspend [i8 0, label %resume280 i8 1, label %pre.cleanup]281resume:282 call void @print(i32 0)283 br label %cleanup284 285pre.cleanup:286 call void @print(i32 1)287 br label %cleanup288 289cleanup:290 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)291 call void @free(ptr %mem)292 br label %suspend293suspend:294 call void @llvm.coro.end(ptr %hdl, i1 false, token none)295 ret void296lpad:297 %lpval = landingpad { ptr, i32 }298 cleanup299 300 call void @print(i32 2)301 resume { ptr, i32 } %lpval302}303 304; SimplifySuspendPoint won't be able to simplify if it detects that resume or305; destroy does not immediately preceed coro.suspend.306;307; CHECK-LABEL: define void @cannot_simplify_not_last_instr(308; CHECK-NEXT: entry:309; CHECK-NEXT: llvm.coro.id310 311define void @cannot_simplify_not_last_instr(ptr %dst, ptr %src) presplitcoroutine {312entry:313 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)314 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)315 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin316dyn.alloc:317 %size = call i32 @llvm.coro.size.i32()318 %alloc = call ptr @malloc(i32 %size)319 br label %coro.begin320coro.begin:321 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]322 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)323 br label %body324body:325 %save = call token @llvm.coro.save(ptr %hdl)326 %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)327 call fastcc void %subfn(ptr %hdl)328 ; memcpy separates destroy from suspend, therefore cannot simplify.329 call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 1, i1 false)330 %0 = call i8 @llvm.coro.suspend(token %save, i1 false)331 switch i8 %0, label %suspend [i8 0, label %resume332 i8 1, label %pre.cleanup]333resume:334 call void @print(i32 0)335 br label %cleanup336 337pre.cleanup:338 call void @print(i32 1)339 br label %cleanup340 341cleanup:342 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)343 call void @free(ptr %mem)344 br label %suspend345suspend:346 call void @llvm.coro.end(ptr %hdl, i1 false, token none)347 ret void348}349 350; SimplifySuspendPoint should not simplify final suspend point351;352; CHECK-LABEL: define void @cannot_simplify_final_suspend(353; CHECK-NEXT: entry:354; CHECK-NEXT: llvm.coro.id355;356define void @cannot_simplify_final_suspend() presplitcoroutine personality i32 0 {357entry:358 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)359 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)360 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin361dyn.alloc:362 %size = call i32 @llvm.coro.size.i32()363 %alloc = call ptr @malloc(i32 %size)364 br label %coro.begin365coro.begin:366 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]367 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)368 br label %body369body:370 %save = call token @llvm.coro.save(ptr %hdl)371 %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)372 invoke fastcc void %subfn(ptr %hdl) to label %real_susp unwind label %lpad373 374real_susp:375 %0 = call i8 @llvm.coro.suspend(token %save, i1 1)376 switch i8 %0, label %suspend [i8 0, label %resume377 i8 1, label %pre.cleanup]378resume:379 call void @print(i32 0)380 br label %cleanup381 382pre.cleanup:383 call void @print(i32 1)384 br label %cleanup385 386cleanup:387 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)388 call void @free(ptr %mem)389 br label %suspend390suspend:391 call void @llvm.coro.end(ptr %hdl, i1 false, token none)392 ret void393lpad:394 %lpval = landingpad { ptr, i32 }395 cleanup396 397 call void @print(i32 2)398 resume { ptr, i32 } %lpval399}400 401declare ptr @malloc(i32) allockind("alloc,uninitialized") allocsize(0)402declare void @free(ptr) willreturn allockind("free")403declare void @print(i32)404declare void @foo()405 406declare token @llvm.coro.id(i32, ptr, ptr, ptr)407declare i1 @llvm.coro.alloc(token)408declare i32 @llvm.coro.size.i32()409declare ptr @llvm.coro.begin(token, ptr)410declare token @llvm.coro.save(ptr %hdl)411declare i8 @llvm.coro.suspend(token, i1)412declare ptr @llvm.coro.free(token, ptr)413declare void @llvm.coro.end(ptr, i1, token)414 415declare ptr @llvm.coro.subfn.addr(ptr, i8)416 417declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)418