Imported Upstream version 5.18.0.167

Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-10-20 08:25:10 +00:00
parent e19d552987
commit b084638f15
28489 changed files with 184 additions and 3866856 deletions

View File

@ -1,67 +0,0 @@
; Need to move users of allocas that were moved into the coroutine frame after
; coro.begin.
; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s
define nonnull i8* @f(i32 %n) {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null);
%n.addr = alloca i32
store i32 %n, i32* %n.addr ; this needs to go after coro.begin
%0 = tail call i32 @llvm.coro.size.i32()
%call = tail call i8* @malloc(i32 %0)
%1 = tail call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %call)
%2 = bitcast i32* %n.addr to i8*
call void @ctor(i8* %2)
br label %for.cond
for.cond:
%3 = load i32, i32* %n.addr
%dec = add nsw i32 %3, -1
store i32 %dec, i32* %n.addr
call void @print(i32 %3)
%4 = call i8 @llvm.coro.suspend(token none, i1 false)
%conv = sext i8 %4 to i32
switch i32 %conv, label %coro_Suspend [
i32 0, label %for.cond
i32 1, label %coro_Cleanup
]
coro_Cleanup:
%5 = call i8* @llvm.coro.free(token %id, i8* nonnull %1)
call void @free(i8* %5)
br label %coro_Suspend
coro_Suspend:
call i1 @llvm.coro.end(i8* null, i1 false)
ret i8* %1
}
; CHECK-LABEL: @main
define i32 @main() {
entry:
%hdl = call i8* @f(i32 4)
call void @llvm.coro.resume(i8* %hdl)
call void @llvm.coro.resume(i8* %hdl)
call void @llvm.coro.destroy(i8* %hdl)
ret i32 0
; CHECK: call void @ctor
; CHECK-NEXT: call void @print(i32 4)
; CHECK-NEXT: call void @print(i32 3)
; CHECK-NEXT: call void @print(i32 2)
; CHECK: ret i32 0
}
declare i8* @malloc(i32)
declare void @free(i8*)
declare void @print(i32)
declare void @ctor(i8* nocapture readonly)
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i32 @llvm.coro.size.i32()
declare i8* @llvm.coro.begin(token, i8*)
declare i8 @llvm.coro.suspend(token, i1)
declare i8* @llvm.coro.free(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)

View File

@ -1,88 +0,0 @@
; Verifies that we can insert the spill for a PHI preceding the catchswitch
; RUN: opt < %s -coro-split -S | FileCheck %s
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc"
; CHECK-LABEL: define void @f(
define void @f(i1 %cond) "coroutine.presplit"="1" personality i32 0 {
entry:
%id = call token @llvm.coro.id(i32 8, i8* null, i8* null, i8* null)
%size = call i32 @llvm.coro.size.i32()
%alloc = call i8* @malloc(i32 %size)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
br i1 %cond, label %if.else, label %if.then
if.then:
invoke void @may_throw1()
to label %coro.ret unwind label %catch.dispatch
if.else:
invoke void @may_throw2()
to label %coro.ret unwind label %catch.dispatch
catch.dispatch: ; preds = %if.else, %if.then
%val = phi i32 [ 1, %if.then ], [ 2, %if.else ]
%switch = catchswitch within none [label %catch] unwind label %cleanuppad
; Verifies that we split out the PHI into a separate block
; added a cleanuppad spill cleanupret unwinding into the catchswitch.
; CHECK: catch.dispatch:
; CHECK: %val = phi i32 [ 2, %if.else ], [ 1, %if.then ]
; CHECK: %[[Pad:.+]] = cleanuppad within none []
; CHECK: %val.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4
; CHECK: store i32 %val, i32* %val.spill.addr
; CHECK: cleanupret from %[[Pad]] unwind label %[[Switch:.+]]
; CHECK: [[Switch]]:
; CHECK: %switch = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
%pad = catchpad within %switch [i8* null, i32 64, i8* null]
catchret from %pad to label %suspend
suspend:
%sp = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %sp, label %coro.ret [
i8 0, label %resume
i8 1, label %coro.ret
]
resume: ; preds = %await2.suspend
call void @print(i32 %val)
br label %coro.ret
coro.ret:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
ret void
cleanuppad:
%cpad = cleanuppad within none []
cleanupret from %cpad unwind to caller
}
; Function Attrs: argmemonly nounwind readonly
declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) #1
; Function Attrs: nounwind
declare i1 @llvm.coro.alloc(token) #2
; Function Attrs: nobuiltin
declare i32 @llvm.coro.size.i32() #4
declare i8* @llvm.coro.begin(token, i8* writeonly) #2
declare token @llvm.coro.save(i8*)
declare i8 @llvm.coro.suspend(token, i1)
declare void @may_throw1()
declare void @may_throw2()
declare void @print(i32)
declare noalias i8* @malloc(i32)
declare void @free(i8*)
declare i1 @llvm.coro.end(i8*, i1) #2
; Function Attrs: nobuiltin nounwind
; Function Attrs: argmemonly nounwind readonly
declare i8* @llvm.coro.free(token, i8* nocapture readonly) #1

View File

@ -1,18 +0,0 @@
; Make sure that all library helper coro intrinsics are lowered.
; RUN: opt < %s -O0 -enable-coroutines -S | FileCheck %s
; CHECK-LABEL: @uses_library_support_coro_intrinsics(
; CHECK-NOT: @llvm.coro
; CHECK: ret void
define void @uses_library_support_coro_intrinsics(i8* %hdl) {
entry:
call void @llvm.coro.resume(i8* %hdl)
call void @llvm.coro.destroy(i8* %hdl)
call i1 @llvm.coro.done(i8* %hdl)
ret void
}
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)
declare i1 @llvm.coro.done(i8*)

View File

@ -1,142 +0,0 @@
; Tests that debug information is sane after coro-split
; RUN: opt < %s -coro-split -S | FileCheck %s
source_filename = "simple-repro.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: noinline nounwind
define i8* @f(i32 %x) #0 !dbg !6 {
entry:
%x.addr = alloca i32, align 4
%coro_hdl = alloca i8*, align 8
store i32 %x, i32* %x.addr, align 4
call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !12, metadata !13), !dbg !14
call void @llvm.dbg.declare(metadata i8** %coro_hdl, metadata !15, metadata !13), !dbg !16
%0 = call token @llvm.coro.id(i32 0, i8* null, i8* bitcast (i8* (i32)* @f to i8*), i8* null), !dbg !16
%1 = call i64 @llvm.coro.size.i64(), !dbg !16
%call = call i8* @malloc(i64 %1), !dbg !16
%2 = call i8* @llvm.coro.begin(token %0, i8* %call) #7, !dbg !16
store i8* %2, i8** %coro_hdl, align 8, !dbg !16
%3 = call i8 @llvm.coro.suspend(token none, i1 false), !dbg !17
%conv = sext i8 %3 to i32, !dbg !17
call void @coro.devirt.trigger(i8* null)
switch i32 %conv, label %sw.default [
i32 0, label %sw.bb
i32 1, label %sw.bb1
], !dbg !17
sw.bb: ; preds = %entry
br label %sw.epilog, !dbg !18
sw.bb1: ; preds = %entry
br label %coro_Cleanup, !dbg !18
sw.default: ; preds = %entry
br label %coro_Suspend, !dbg !18
sw.epilog: ; preds = %sw.bb
%4 = load i32, i32* %x.addr, align 4, !dbg !20
%add = add nsw i32 %4, 1, !dbg !21
store i32 %add, i32* %x.addr, align 4, !dbg !22
br label %coro_Cleanup, !dbg !23
coro_Cleanup: ; preds = %sw.epilog, %sw.bb1
%5 = load i8*, i8** %coro_hdl, align 8, !dbg !24
%6 = call i8* @llvm.coro.free(token %0, i8* %5), !dbg !24
call void @free(i8* %6), !dbg !24
br label %coro_Suspend, !dbg !24
coro_Suspend: ; preds = %coro_Cleanup, %sw.default
%7 = call i1 @llvm.coro.end(i8* null, i1 false) #7, !dbg !24
%8 = load i8*, i8** %coro_hdl, align 8, !dbg !24
ret i8* %8, !dbg !24
}
; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
; Function Attrs: argmemonly nounwind readonly
declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) #2
declare i8* @malloc(i64) #3
; Function Attrs: nounwind readnone
declare i64 @llvm.coro.size.i64() #4
; Function Attrs: nounwind
declare i8* @llvm.coro.begin(token, i8* writeonly) #5
; Function Attrs: nounwind
declare i8 @llvm.coro.suspend(token, i1) #5
declare void @free(i8*) #3
; Function Attrs: argmemonly nounwind readonly
declare i8* @llvm.coro.free(token, i8* nocapture readonly) #2
; Function Attrs: nounwind
declare i1 @llvm.coro.end(i8*, i1) #5
; Function Attrs: alwaysinline
define private void @coro.devirt.trigger(i8*) #6 {
entry:
ret void
}
; Function Attrs: argmemonly nounwind readonly
declare i8* @llvm.coro.subfn.addr(i8* nocapture readonly, i8) #2
attributes #0 = { noinline nounwind "coroutine.presplit"="1" "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone speculatable }
attributes #2 = { argmemonly nounwind readonly }
attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #4 = { nounwind readnone }
attributes #5 = { nounwind }
attributes #6 = { alwaysinline }
attributes #7 = { noduplicate }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4}
!llvm.ident = !{!5}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.0 (http://llvm.org/git/clang.git 97b002238b11ff30d94d0516d6a0515db5725fd8) (http://llvm.org/git/llvm.git 0cb060ba567f1aa5b4b04e86665f88e4632b528a)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "<stdin>", directory: "C:\5CGitHub\5Cllvm\5Cbuild\5CDebug\5Cbin")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{!"clang version 5.0.0 (http://llvm.org/git/clang.git 97b002238b11ff30d94d0516d6a0515db5725fd8) (http://llvm.org/git/llvm.git 0cb060ba567f1aa5b4b04e86665f88e4632b528a)"}
!6 = distinct !DISubprogram(name: "f", linkageName: "flink", scope: !7, file: !7, line: 55, type: !8, isLocal: false, isDefinition: true, scopeLine: 55, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
!7 = !DIFile(filename: "simple-repro.c", directory: "C:\5CGitHub\5Cllvm\5Cbuild\5CDebug\5Cbin")
!8 = !DISubroutineType(types: !9)
!9 = !{!10, !11}
!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!12 = !DILocalVariable(name: "x", arg: 1, scope: !6, file: !7, line: 55, type: !11)
!13 = !DIExpression()
!14 = !DILocation(line: 55, column: 13, scope: !6)
!15 = !DILocalVariable(name: "coro_hdl", scope: !6, file: !7, line: 56, type: !10)
!16 = !DILocation(line: 56, column: 3, scope: !6)
!17 = !DILocation(line: 58, column: 5, scope: !6)
!18 = !DILocation(line: 58, column: 5, scope: !19)
!19 = distinct !DILexicalBlock(scope: !6, file: !7, line: 58, column: 5)
!20 = !DILocation(line: 59, column: 9, scope: !6)
!21 = !DILocation(line: 59, column: 10, scope: !6)
!22 = !DILocation(line: 59, column: 7, scope: !6)
!23 = !DILocation(line: 59, column: 5, scope: !6)
!24 = !DILocation(line: 62, column: 3, scope: !6)
; CHECK: define i8* @f(i32 %x) #0 !dbg ![[ORIG:[0-9]+]]
; CHECK: define internal fastcc void @f.resume(%f.Frame* %FramePtr) #0 !dbg ![[RESUME:[0-9]+]]
; CHECK: define internal fastcc void @f.destroy(%f.Frame* %FramePtr) #0 !dbg ![[DESTROY:[0-9]+]]
; CHECK: define internal fastcc void @f.cleanup(%f.Frame* %FramePtr) #0 !dbg ![[CLEANUP:[0-9]+]]
; CHECK: ![[ORIG]] = distinct !DISubprogram(name: "f", linkageName: "flink"
; CHECK: !DILocalVariable(name: "x", arg: 1, scope: ![[ORIG]]
; CHECK: ![[RESUME]] = distinct !DISubprogram(name: "f", linkageName: "flink"
; CHECK: !DILocalVariable(name: "x", arg: 1, scope: ![[RESUME]]
; CHECK: ![[DESTROY]] = distinct !DISubprogram(name: "f", linkageName: "flink"
; CHECK: ![[CLEANUP]] = distinct !DISubprogram(name: "f", linkageName: "flink"

View File

@ -1,41 +0,0 @@
; Tests that CoroEarly pass correctly lowers coro.resume and coro.destroy
; intrinsics.
; RUN: opt < %s -S -coro-early | FileCheck %s
; CHECK-LABEL: @callResume(
define void @callResume(i8* %hdl) {
; CHECK-NEXT: entry
entry:
; CHECK-NEXT: %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
; CHECK-NEXT: %1 = bitcast i8* %0 to void (i8*)*
; CHECK-NEXT: call fastcc void %1(i8* %hdl)
call void @llvm.coro.resume(i8* %hdl)
; CHECK-NEXT: %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
; CHECK-NEXT: %3 = bitcast i8* %2 to void (i8*)*
; CHECK-NEXT: call fastcc void %3(i8* %hdl)
call void @llvm.coro.destroy(i8* %hdl)
ret void
; CHECK-NEXT: ret void
}
; CHECK-LABEL: @eh(
define void @eh(i8* %hdl) personality i8* null {
; CHECK-NEXT: entry
entry:
; CHECK-NEXT: %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
; CHECK-NEXT: %1 = bitcast i8* %0 to void (i8*)*
; CHECK-NEXT: invoke fastcc void %1(i8* %hdl)
invoke void @llvm.coro.resume(i8* %hdl)
to label %cont unwind label %ehcleanup
cont:
ret void
ehcleanup:
%0 = cleanuppad within none []
cleanupret from %0 unwind to caller
}
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)

View File

@ -1,218 +0,0 @@
; Check that we can handle edge splits leading into a landingpad
; RUN: opt < %s -coro-split -S | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; CHECK-LABEL: define internal fastcc void @f.resume(
define void @f(i1 %cond) "coroutine.presplit"="1" personality i32 0 {
entry:
%id = call token @llvm.coro.id(i32 16, i8* null, i8* null, i8* null)
%size = tail call i64 @llvm.coro.size.i64()
%alloc = call i8* @malloc(i64 %size)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
%sp = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %sp, label %coro.ret [
i8 0, label %resume
i8 1, label %cleanup
]
resume:
br i1 %cond, label %invoke1, label %invoke2
invoke1:
invoke void @may_throw1()
to label %unreach unwind label %pad.with.phi
invoke2:
invoke void @may_throw2()
to label %unreach unwind label %pad.with.phi
; Verify that we cloned landing pad on every edge and inserted a reload of the spilled value
; CHECK: pad.with.phi.from.invoke2:
; CHECK: %0 = landingpad { i8*, i32 }
; CHECK: catch i8* null
; CHECK: br label %pad.with.phi
; CHECK: pad.with.phi.from.invoke1:
; CHECK: %1 = landingpad { i8*, i32 }
; CHECK: catch i8* null
; CHECK: br label %pad.with.phi
; CHECK: pad.with.phi:
; CHECK: %val = phi i32 [ 0, %pad.with.phi.from.invoke1 ], [ 1, %pad.with.phi.from.invoke2 ]
; CHECK: %lp = phi { i8*, i32 } [ %0, %pad.with.phi.from.invoke2 ], [ %1, %pad.with.phi.from.invoke1 ]
; CHECK: %exn = extractvalue { i8*, i32 } %lp, 0
; CHECK: call i8* @__cxa_begin_catch(i8* %exn)
; CHECK: call void @use_val(i32 %val)
; CHECK: call void @__cxa_end_catch()
; CHECK: call void @free(i8* %vFrame)
; CHECK: ret void
pad.with.phi:
%val = phi i32 [ 0, %invoke1 ], [ 1, %invoke2 ]
%lp = landingpad { i8*, i32 }
catch i8* null
%exn = extractvalue { i8*, i32 } %lp, 0
call i8* @__cxa_begin_catch(i8* %exn)
call void @use_val(i32 %val)
call void @__cxa_end_catch()
br label %cleanup
cleanup: ; preds = %invoke.cont15, %if.else, %if.then, %ehcleanup21, %init.suspend
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %coro.ret
coro.ret:
call i1 @llvm.coro.end(i8* null, i1 false)
ret void
unreach:
unreachable
}
; CHECK-LABEL: define internal fastcc void @g.resume(
define void @g(i1 %cond, i32 %x, i32 %y) "coroutine.presplit"="1" personality i32 0 {
entry:
%id = call token @llvm.coro.id(i32 16, i8* null, i8* null, i8* null)
%size = tail call i64 @llvm.coro.size.i64()
%alloc = call i8* @malloc(i64 %size)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
%sp = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %sp, label %coro.ret [
i8 0, label %resume
i8 1, label %cleanup
]
resume:
br i1 %cond, label %invoke1, label %invoke2
invoke1:
invoke void @may_throw1()
to label %unreach unwind label %pad.with.phi
invoke2:
invoke void @may_throw2()
to label %unreach unwind label %pad.with.phi
; Verify that we created cleanuppads on every edge and inserted a reload of the spilled value
; CHECK: pad.with.phi.from.invoke2:
; CHECK: %0 = cleanuppad within none []
; CHECK: %y.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 6
; CHECK: %y.reload = load i32, i32* %y.reload.addr
; CHECK: cleanupret from %0 unwind label %pad.with.phi
; CHECK: pad.with.phi.from.invoke1:
; CHECK: %1 = cleanuppad within none []
; CHECK: %x.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 5
; CHECK: %x.reload = load i32, i32* %x.reload.addr
; CHECK: cleanupret from %1 unwind label %pad.with.phi
; CHECK: pad.with.phi:
; CHECK: %val = phi i32 [ %x.reload, %pad.with.phi.from.invoke1 ], [ %y.reload, %pad.with.phi.from.invoke2 ]
; CHECK: %tok = cleanuppad within none []
; CHECK: call void @use_val(i32 %val)
; CHECK: cleanupret from %tok unwind to caller
pad.with.phi:
%val = phi i32 [ %x, %invoke1 ], [ %y, %invoke2 ]
%tok = cleanuppad within none []
call void @use_val(i32 %val)
cleanupret from %tok unwind to caller
cleanup: ; preds = %invoke.cont15, %if.else, %if.then, %ehcleanup21, %init.suspend
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %coro.ret
coro.ret:
call i1 @llvm.coro.end(i8* null, i1 false)
ret void
unreach:
unreachable
}
; CHECK-LABEL: define internal fastcc void @h.resume(
define void @h(i1 %cond, i32 %x, i32 %y) "coroutine.presplit"="1" personality i32 0 {
entry:
%id = call token @llvm.coro.id(i32 16, i8* null, i8* null, i8* null)
%size = tail call i64 @llvm.coro.size.i64()
%alloc = call i8* @malloc(i64 %size)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
%sp = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %sp, label %coro.ret [
i8 0, label %resume
i8 1, label %cleanup
]
resume:
br i1 %cond, label %invoke1, label %invoke2
invoke1:
invoke void @may_throw1()
to label %coro.ret unwind label %pad.with.phi
invoke2:
invoke void @may_throw2()
to label %coro.ret unwind label %pad.with.phi
; Verify that we created cleanuppads on every edge and inserted a reload of the spilled value
; CHECK: pad.with.phi.from.invoke2:
; CHECK: %0 = cleanuppad within none []
; CHECK: %y.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 6
; CHECK: %y.reload = load i32, i32* %y.reload.addr
; CHECK: cleanupret from %0 unwind label %pad.with.phi
; CHECK: pad.with.phi.from.invoke1:
; CHECK: %1 = cleanuppad within none []
; CHECK: %x.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 5
; CHECK: %x.reload = load i32, i32* %x.reload.addr
; CHECK: cleanupret from %1 unwind label %pad.with.phi
; CHECK: pad.with.phi:
; CHECK: %val = phi i32 [ %x.reload, %pad.with.phi.from.invoke1 ], [ %y.reload, %pad.with.phi.from.invoke2 ]
; CHECK: %switch = catchswitch within none [label %catch] unwind to caller
pad.with.phi:
%val = phi i32 [ %x, %invoke1 ], [ %y, %invoke2 ]
%switch = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
%pad = catchpad within %switch [i8* null, i32 64, i8* null]
call void @use_val(i32 %val)
catchret from %pad to label %coro.ret
cleanup: ; preds = %invoke.cont15, %if.else, %if.then, %ehcleanup21, %init.suspend
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %coro.ret
coro.ret:
call i1 @llvm.coro.end(i8* null, i1 false)
ret void
}
; Function Attrs: argmemonly nounwind readonly
declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*)
declare noalias i8* @malloc(i64)
declare i64 @llvm.coro.size.i64()
declare i8* @llvm.coro.begin(token, i8* writeonly)
; Function Attrs: nounwind
declare token @llvm.coro.save(i8*)
declare i8 @llvm.coro.suspend(token, i1)
; Function Attrs: argmemonly nounwind
declare void @may_throw1()
declare void @may_throw2()
declare i8* @__cxa_begin_catch(i8*)
declare void @use_val(i32)
declare void @__cxa_end_catch()
; Function Attrs: nounwind
declare i1 @llvm.coro.end(i8*, i1)
declare void @free(i8*)
declare i8* @llvm.coro.free(token, i8* nocapture readonly)

View File

@ -1,112 +0,0 @@
; Tests that the coro.destroy and coro.resume are devirtualized where possible,
; SCC pipeline restarts and inlines the direct calls.
; RUN: opt < %s -S -inline -coro-elide -dce | FileCheck %s
declare void @print(i32) nounwind
; resume part of the coroutine
define fastcc void @f.resume(i8*) {
tail call void @print(i32 0)
ret void
}
; destroy part of the coroutine
define fastcc void @f.destroy(i8*) {
tail call void @print(i32 1)
ret void
}
@f.resumers = internal constant [2 x void (i8*)*] [void (i8*)* @f.resume,
void (i8*)* @f.destroy]
; a coroutine start function
define i8* @f() {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null,
i8* bitcast (i8*()* @f to i8*),
i8* bitcast ([2 x void (i8*)*]* @f.resumers to i8*))
%hdl = call i8* @llvm.coro.begin(token %id, i8* null)
ret i8* %hdl
}
; CHECK-LABEL: @callResume(
define void @callResume() {
entry:
%hdl = call i8* @f()
; CHECK: call void @print(i32 0)
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
%1 = bitcast i8* %0 to void (i8*)*
call fastcc void %1(i8* %hdl)
; CHECK-NEXT: call void @print(i32 1)
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
%3 = bitcast i8* %2 to void (i8*)*
call fastcc void %3(i8* %hdl)
; CHECK-NEXT: ret void
ret void
}
; CHECK-LABEL: @eh(
define void @eh() personality i8* null {
entry:
%hdl = call i8* @f()
; CHECK: call void @print(i32 0)
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
%1 = bitcast i8* %0 to void (i8*)*
invoke void %1(i8* %hdl)
to label %cont unwind label %ehcleanup
cont:
ret void
ehcleanup:
%tok = cleanuppad within none []
cleanupret from %tok unwind to caller
}
; CHECK-LABEL: @no_devirt_info_null(
; no devirtualization here, since coro.begin info parameter is null
define void @no_devirt_info_null() {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%hdl = call i8* @llvm.coro.begin(token %id, i8* null)
; CHECK: call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
%1 = bitcast i8* %0 to void (i8*)*
call fastcc void %1(i8* %hdl)
; CHECK: call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
%3 = bitcast i8* %2 to void (i8*)*
call fastcc void %3(i8* %hdl)
; CHECK: ret void
ret void
}
; CHECK-LABEL: @no_devirt_no_begin(
; no devirtualization here, since coro.begin is not visible
define void @no_devirt_no_begin(i8* %hdl) {
entry:
; CHECK: call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
%1 = bitcast i8* %0 to void (i8*)*
call fastcc void %1(i8* %hdl)
; CHECK: call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
%3 = bitcast i8* %2 to void (i8*)*
call fastcc void %3(i8* %hdl)
; CHECK: ret void
ret void
}
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i8* @llvm.coro.begin(token, i8*)
declare i8* @llvm.coro.frame()
declare i8* @llvm.coro.subfn.addr(i8*, i8)

View File

@ -1,66 +0,0 @@
; Check that we can handle spills of the result of the invoke instruction
; RUN: opt < %s -coro-split -S | FileCheck %s
define i8* @f(i64 %this) "coroutine.presplit"="1" personality i32 0 {
entry:
%this.addr = alloca i64
store i64 %this, i64* %this.addr
%this1 = load i64, i64* %this.addr
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%size = call i32 @llvm.coro.size.i32()
%alloc = call i8* @malloc(i32 %size)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
%r = invoke double @print(double 0.0) to label %cont unwind label %pad
cont:
%0 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %0, label %suspend [i8 0, label %resume
i8 1, label %cleanup]
resume:
call double @print(double %r)
call void @print2(i64 %this1)
br label %cleanup
cleanup:
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %suspend
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
ret i8* %hdl
pad:
%tok = cleanuppad within none []
cleanupret from %tok unwind to caller
}
; See if the float was added to the frame
; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i64, double }
; See if the float was spilled into the frame
; CHECK-LABEL: @f(
; CHECK: %r = call double @print(
; CHECK: %r.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5
; CHECK: store double %r, double* %r.spill.addr
; CHECK: ret i8* %hdl
; See of the float was loaded from the frame
; CHECK-LABEL: @f.resume(
; CHECK: %r.reload = load double, double* %r.reload.addr
; CHECK: call double @print(double %r.reload)
; CHECK: ret void
declare i8* @llvm.coro.free(token, i8*)
declare i32 @llvm.coro.size.i32()
declare i8 @llvm.coro.suspend(token, i1)
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i1 @llvm.coro.alloc(token)
declare i8* @llvm.coro.begin(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare noalias i8* @malloc(i32)
declare double @print(double)
declare void @print2(i64)
declare void @free(i8*)

View File

@ -1,127 +0,0 @@
; Tests that the dynamic allocation and deallocation of the coroutine frame is
; elided and any tail calls referencing the coroutine frame has the tail
; call attribute removed.
; RUN: opt < %s -S -inline -coro-elide -instsimplify -simplifycfg | FileCheck %s
declare void @print(i32) nounwind
%f.frame = type {i32}
declare void @bar(i8*)
declare fastcc void @f.resume(%f.frame*)
declare fastcc void @f.destroy(%f.frame*)
declare fastcc void @f.cleanup(%f.frame*)
declare void @may_throw()
declare i8* @CustomAlloc(i32)
declare void @CustomFree(i8*)
@f.resumers = internal constant [3 x void (%f.frame*)*]
[void (%f.frame*)* @f.resume, void (%f.frame*)* @f.destroy, void (%f.frame*)* @f.cleanup]
; a coroutine start function
define i8* @f() personality i8* null {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null,
i8* bitcast (i8*()* @f to i8*),
i8* bitcast ([3 x void (%f.frame*)*]* @f.resumers to i8*))
%need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
dyn.alloc:
%alloc = call i8* @CustomAlloc(i32 4)
br label %coro.begin
coro.begin:
%phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
%hdl = call i8* @llvm.coro.begin(token %id, i8* %phi)
invoke void @may_throw()
to label %ret unwind label %ehcleanup
ret:
ret i8* %hdl
ehcleanup:
%tok = cleanuppad within none []
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
%need.dyn.free = icmp ne i8* %mem, null
br i1 %need.dyn.free, label %dyn.free, label %if.end
dyn.free:
call void @CustomFree(i8* %mem)
br label %if.end
if.end:
cleanupret from %tok unwind to caller
}
; CHECK-LABEL: @callResume(
define void @callResume() {
entry:
; CHECK: alloca %f.frame
; CHECK-NOT: coro.begin
; CHECK-NOT: CustomAlloc
; CHECK: call void @may_throw()
%hdl = call i8* @f()
; Need to remove 'tail' from the first call to @bar
; CHECK-NOT: tail call void @bar(
; CHECK: call void @bar(
tail call void @bar(i8* %hdl)
; CHECK: tail call void @bar(
tail call void @bar(i8* null)
; CHECK-NEXT: call fastcc void bitcast (void (%f.frame*)* @f.resume to void (i8*)*)(i8* %vFrame)
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
%1 = bitcast i8* %0 to void (i8*)*
call fastcc void %1(i8* %hdl)
; CHECK-NEXT: call fastcc void bitcast (void (%f.frame*)* @f.cleanup to void (i8*)*)(i8* %vFrame)
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
%3 = bitcast i8* %2 to void (i8*)*
call fastcc void %3(i8* %hdl)
; CHECK-NEXT: ret void
ret void
}
; a coroutine start function (cannot elide heap alloc, due to second argument to
; coro.begin not pointint to coro.alloc)
define i8* @f_no_elision() personality i8* null {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null,
i8* bitcast (i8*()* @f_no_elision to i8*),
i8* bitcast ([3 x void (%f.frame*)*]* @f.resumers to i8*))
%alloc = call i8* @CustomAlloc(i32 4)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
ret i8* %hdl
}
; CHECK-LABEL: @callResume_no_elision(
define void @callResume_no_elision() {
entry:
; CHECK: call i8* @CustomAlloc(
%hdl = call i8* @f_no_elision()
; Tail call should remain tail calls
; CHECK: tail call void @bar(
tail call void @bar(i8* %hdl)
; CHECK: tail call void @bar(
tail call void @bar(i8* null)
; CHECK-NEXT: call fastcc void bitcast (void (%f.frame*)* @f.resume to void (i8*)*)(i8*
%0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
%1 = bitcast i8* %0 to void (i8*)*
call fastcc void %1(i8* %hdl)
; CHECK-NEXT: call fastcc void bitcast (void (%f.frame*)* @f.destroy to void (i8*)*)(i8*
%2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
%3 = bitcast i8* %2 to void (i8*)*
call fastcc void %3(i8* %hdl)
; CHECK-NEXT: ret void
ret void
}
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i1 @llvm.coro.alloc(token)
declare i8* @llvm.coro.free(token, i8*)
declare i8* @llvm.coro.begin(token, i8*)
declare i8* @llvm.coro.frame(token)
declare i8* @llvm.coro.subfn.addr(i8*, i8)

View File

@ -1,52 +0,0 @@
; Verifies that we materialize instruction across suspend points
; RUN: opt < %s -coro-split -S | FileCheck %s
define i8* @f(i32 %n) "coroutine.presplit"="1" {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%size = call i32 @llvm.coro.size.i32()
%alloc = call i8* @malloc(i32 %size)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
%inc1 = add i32 %n, 1
%sp1 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %sp1, label %suspend [i8 0, label %resume1
i8 1, label %cleanup]
resume1:
%inc2 = add i32 %inc1, 1
%sp2 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %sp1, label %suspend [i8 0, label %resume2
i8 1, label %cleanup]
resume2:
call void @print(i32 %inc1)
call void @print(i32 %inc2)
br label %cleanup
cleanup:
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %suspend
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
ret i8* %hdl
}
; See that we only spilled one value
; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i32 }
; CHECK-LABEL: @f(
declare i8* @llvm.coro.free(token, i8*)
declare i32 @llvm.coro.size.i32()
declare i8 @llvm.coro.suspend(token, i1)
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i1 @llvm.coro.alloc(token)
declare i8* @llvm.coro.begin(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare noalias i8* @malloc(i32)
declare void @print(i32)
declare void @free(i8*)

View File

@ -1,60 +0,0 @@
; Verifies that we insert spills of PHI instruction _after) all PHI Nodes
; RUN: opt < %s -coro-split -S | FileCheck %s
define i8* @f(i1 %n) "coroutine.presplit"="1" {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%size = call i32 @llvm.coro.size.i32()
%alloc = call i8* @malloc(i32 %size)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
br i1 %n, label %begin, label %alt
alt:
br label %begin
begin:
%phi1 = phi i32 [ 0, %entry ], [ 2, %alt ]
%phi2 = phi i32 [ 1, %entry ], [ 3, %alt ]
%sp1 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %sp1, label %suspend [i8 0, label %resume
i8 1, label %cleanup]
resume:
call i32 @print(i32 %phi1)
call i32 @print(i32 %phi2)
br label %cleanup
cleanup:
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %suspend
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
ret i8* %hdl
}
; Verifies that the both phis are stored correctly in the coroutine frame
; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i32, i32 }
; CHECK-LABEL: @f(
; CHECK: store void (%f.Frame*)* @f.destroy, void (%f.Frame*)** %destroy.addr
; CHECK: %phi1 = select i1 %n, i32 0, i32 2
; CHECK: %phi2 = select i1 %n, i32 1, i32 3
; CHECK: %phi2.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5
; CHECK: store i32 %phi2, i32* %phi2.spill.addr
; CHECK: %phi1.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4
; CHECK: store i32 %phi1, i32* %phi1.spill.addr
; CHECK: ret i8* %hdl
declare i8* @llvm.coro.free(token, i8*)
declare i32 @llvm.coro.size.i32()
declare i8 @llvm.coro.suspend(token, i1)
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i1 @llvm.coro.alloc(token)
declare i8* @llvm.coro.begin(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare noalias i8* @malloc(i32)
declare i32 @print(i32)
declare void @free(i8*)

View File

@ -1,69 +0,0 @@
; Check that we can spills coro.begin from an inlined inner coroutine.
; RUN: opt < %s -coro-split -S | FileCheck %s
%g.Frame = type { void (%g.Frame*)*, void (%g.Frame*)*, i32, i1, i32 }
@g.resumers = private constant [3 x void (%g.Frame*)*] [void (%g.Frame*)* @g.dummy, void (%g.Frame*)* @g.dummy, void (%g.Frame*)* @g.dummy]
declare void @g.dummy(%g.Frame*)
define i8* @f() "coroutine.presplit"="1" {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%size = call i32 @llvm.coro.size.i32()
%alloc = call i8* @malloc(i32 %size)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
%innerid = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* bitcast ([3 x void (%g.Frame*)*]* @g.resumers to i8*))
%innerhdl = call noalias nonnull i8* @llvm.coro.begin(token %innerid, i8* null)
%gframe = bitcast i8* %innerhdl to %g.Frame*
%tok = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %tok, label %suspend [i8 0, label %resume
i8 1, label %cleanup]
resume:
%gvar.addr = getelementptr inbounds %g.Frame, %g.Frame* %gframe, i32 0, i32 4
%gvar = load i32, i32* %gvar.addr
call void @print.i32(i32 %gvar)
br label %cleanup
cleanup:
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %suspend
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
ret i8* %hdl
}
; See if the i8* for coro.begin was added to f.Frame
; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i8* }
; See if the g's coro.begin was spilled into the frame
; CHECK-LABEL: @f(
; CHECK: %innerid = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* bitcast ([3 x void (%g.Frame*)*]* @g.resumers to i8*))
; CHECK: %innerhdl = call noalias nonnull i8* @llvm.coro.begin(token %innerid, i8* null)
; CHECK: %[[spilladdr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4
; CHECK: store i8* %innerhdl, i8** %[[spilladdr]]
; See if the coro.begin was loaded from the frame
; CHECK-LABEL: @f.resume(
; CHECK: %[[innerhdlAddr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %{{.+}}, i32 0, i32 4
; CHECK: %[[innerhdl:.+]] = load i8*, i8** %[[innerhdlAddr]]
; CHECK: %[[gframe:.+]] = bitcast i8* %[[innerhdl]] to %g.Frame*
; CHECK: %[[gvarAddr:.+]] = getelementptr inbounds %g.Frame, %g.Frame* %[[gframe]], i32 0, i32 4
; CHECK: %[[gvar:.+]] = load i32, i32* %[[gvarAddr]]
; CHECK: call void @print.i32(i32 %[[gvar]])
declare i8* @llvm.coro.free(token, i8*)
declare i32 @llvm.coro.size.i32()
declare i8 @llvm.coro.suspend(token, i1)
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i1 @llvm.coro.alloc(token)
declare i8* @llvm.coro.begin(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare noalias i8* @malloc(i32)
declare void @print.i32(i32)
declare void @free(i8*)

View File

@ -1,79 +0,0 @@
; Tests that coro-split pass splits the coroutine into f, f.resume and f.destroy
; RUN: opt < %s -coro-split -S | FileCheck %s
define i8* @f() "coroutine.presplit"="1" {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%need.alloc = call i1 @llvm.coro.alloc(token %id)
br i1 %need.alloc, label %dyn.alloc, label %begin
dyn.alloc:
%size = call i32 @llvm.coro.size.i32()
%alloc = call i8* @malloc(i32 %size)
br label %begin
begin:
%phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
%hdl = call i8* @llvm.coro.begin(token %id, i8* %phi)
call void @print(i32 0)
%0 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %0, label %suspend [i8 0, label %resume
i8 1, label %cleanup]
resume:
call void @print(i32 1)
br label %cleanup
cleanup:
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %suspend
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
ret i8* %hdl
}
; CHECK-LABEL: @f(
; CHECK: call i8* @malloc
; CHECK: @llvm.coro.begin(token %id, i8* %phi)
; CHECK: store void (%f.Frame*)* @f.resume, void (%f.Frame*)** %resume.addr
; CHECK: %[[SEL:.+]] = select i1 %need.alloc, void (%f.Frame*)* @f.destroy, void (%f.Frame*)* @f.cleanup
; CHECK: store void (%f.Frame*)* %[[SEL]], void (%f.Frame*)** %destroy.addr
; CHECK: call void @print(i32 0)
; CHECK-NOT: call void @print(i32 1)
; CHECK-NOT: call void @free(
; CHECK: ret i8* %hdl
; CHECK-LABEL: @f.resume(
; CHECK-NOT: call i8* @malloc
; CHECK-NOT: call void @print(i32 0)
; CHECK: call void @print(i32 1)
; CHECK-NOT: call void @print(i32 0)
; CHECK: call void @free(
; CHECK: ret void
; CHECK-LABEL: @f.destroy(
; CHECK-NOT: call i8* @malloc
; CHECK-NOT: call void @print(
; CHECK: call void @free(
; CHECK: ret void
; CHECK-LABEL: @f.cleanup(
; CHECK-NOT: call i8* @malloc
; CHECK-NOT: call void @print(
; CHECK-NOT: call void @free(
; CHECK: ret void
declare i8* @llvm.coro.free(token, i8*)
declare i32 @llvm.coro.size.i32()
declare i8 @llvm.coro.suspend(token, i1)
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i1 @llvm.coro.alloc(token)
declare i8* @llvm.coro.begin(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare noalias i8* @malloc(i32)
declare void @print(i32)
declare void @free(i8*)

View File

@ -1,56 +0,0 @@
; Tests that a coroutine is split, inlined into the caller and devirtualized.
; RUN: opt < %s -S -enable-coroutines -O2 | FileCheck %s
define i8* @f() {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
dyn.alloc:
%size = call i32 @llvm.coro.size.i32()
%alloc = call i8* @malloc(i32 %size)
br label %coro.begin
coro.begin:
%phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
%hdl = call i8* @llvm.coro.begin(token %id, i8* %phi)
call void @print(i32 0)
%0 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %0, label %suspend [i8 0, label %resume
i8 1, label %cleanup]
resume:
call void @print(i32 1)
br label %cleanup
cleanup:
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %suspend
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
ret i8* %hdl
}
define i32 @main() {
entry:
%hdl = call i8* @f()
call void @llvm.coro.resume(i8* %hdl)
ret i32 0
; CHECK-LABEL: @main(
; CHECK: call void @print(i32 0)
; CHECK: call void @print(i32 1)
; CHECK: ret i32 0
}
declare i8* @llvm.coro.free(token, i8*)
declare i32 @llvm.coro.size.i32()
declare i8 @llvm.coro.suspend(token, i1)
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i1 @llvm.coro.alloc(token)
declare i8* @llvm.coro.begin(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare noalias i8* @malloc(i32)
declare void @print(i32)
declare void @free(i8*)

View File

@ -1,57 +0,0 @@
; Tests that coro-split can handle the case when a code after coro.suspend uses
; a value produces between coro.save and coro.suspend (%Result.i19)
; and checks whether stray coro.saves are properly removed
; RUN: opt < %s -coro-split -S | FileCheck %s
%"struct.std::coroutine_handle" = type { i8* }
%"struct.std::coroutine_handle.0" = type { %"struct.std::coroutine_handle" }
%"struct.lean_future<int>::Awaiter" = type { i32, %"struct.std::coroutine_handle.0" }
declare i8* @malloc(i64)
declare void @print(i32)
define void @a() "coroutine.presplit"="1" {
entry:
%ref.tmp7 = alloca %"struct.lean_future<int>::Awaiter", align 8
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%alloc = call i8* @malloc(i64 16) #3
%vFrame = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %alloc)
%save = call token @llvm.coro.save(i8* null)
%Result.i19 = getelementptr inbounds %"struct.lean_future<int>::Awaiter", %"struct.lean_future<int>::Awaiter"* %ref.tmp7, i64 0, i32 0
%suspend = call i8 @llvm.coro.suspend(token %save, i1 false)
switch i8 %suspend, label %exit [
i8 0, label %await.ready
i8 1, label %exit
]
await.ready:
%StrayCoroSave = call token @llvm.coro.save(i8* null)
%val = load i32, i32* %Result.i19
call void @print(i32 %val)
br label %exit
exit:
call i1 @llvm.coro.end(i8* null, i1 false)
ret void
}
; CHECK-LABEL: @a.resume(
; CHECK: getelementptr inbounds %a.Frame
; CHECK-NEXT: getelementptr inbounds %"struct.lean_future<int>::Awaiter"
; CHECK-NOT: call token @llvm.coro.save(i8* null)
; CHECK-NEXT: %val = load i32, i32* %Result
; CHECK-NEXT: call void @print(i32 %val)
; CHECK-NEXT: ret void
declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*)
declare i1 @llvm.coro.alloc(token) #3
declare noalias nonnull i8* @"\01??2@YAPEAX_K@Z"(i64) local_unnamed_addr
declare i64 @llvm.coro.size.i64() #5
declare i8* @llvm.coro.begin(token, i8* writeonly) #3
declare void @"\01?puts@@YAXZZ"(...)
declare token @llvm.coro.save(i8*) #3
declare i8* @llvm.coro.frame() #5
declare i8 @llvm.coro.suspend(token, i1) #3
declare void @"\01??3@YAXPEAX@Z"(i8*) local_unnamed_addr #10
declare i8* @llvm.coro.free(token, i8* nocapture readonly) #2
declare i1 @llvm.coro.end(i8*, i1) #3

View File

@ -1,119 +0,0 @@
; Make sure that coro-split correctly deals with debug information.
; The test here is simply that it does not result in bad IR that will crash opt.
; RUN: opt < %s -coro-split -disable-output
source_filename = "coro.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: nounwind readnone
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
declare void @bar(...) local_unnamed_addr #2
; Function Attrs: nounwind uwtable
define i8* @f() #3 !dbg !16 {
entry:
%0 = tail call token @llvm.coro.id(i32 0, i8* null, i8* bitcast (i8* ()* @f to i8*), i8* null), !dbg !26
%1 = tail call i64 @llvm.coro.size.i64(), !dbg !26
%call = tail call i8* @malloc(i64 %1), !dbg !26
%2 = tail call i8* @llvm.coro.begin(token %0, i8* %call) #9, !dbg !26
tail call void @llvm.dbg.value(metadata i8* %2, metadata !21, metadata !12), !dbg !26
br label %for.cond, !dbg !27
for.cond: ; preds = %for.cond, %entry
tail call void @llvm.dbg.value(metadata i32 undef, metadata !22, metadata !12), !dbg !28
tail call void @llvm.dbg.value(metadata i32 undef, metadata !11, metadata !12) #7, !dbg !29
tail call void (...) @bar() #7, !dbg !33
%3 = tail call token @llvm.coro.save(i8* null), !dbg !34
%4 = tail call i8 @llvm.coro.suspend(token %3, i1 false), !dbg !34
%conv = sext i8 %4 to i32, !dbg !34
switch i32 %conv, label %coro_Suspend [
i32 0, label %for.cond
i32 1, label %coro_Cleanup
], !dbg !34
coro_Cleanup: ; preds = %for.cond
%5 = tail call i8* @llvm.coro.free(token %0, i8* %2), !dbg !35
tail call void @free(i8* nonnull %5), !dbg !36
br label %coro_Suspend, !dbg !36
coro_Suspend: ; preds = %for.cond, %if.then, %coro_Cleanup
tail call i1 @llvm.coro.end(i8* null, i1 false) #9, !dbg !38
ret i8* %2, !dbg !39
}
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #4
; Function Attrs: argmemonly nounwind readonly
declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) #5
; Function Attrs: nounwind
declare noalias i8* @malloc(i64) local_unnamed_addr #6
declare i64 @llvm.coro.size.i64() #1
declare i8* @llvm.coro.begin(token, i8* writeonly) #7
declare token @llvm.coro.save(i8*) #7
declare i8 @llvm.coro.suspend(token, i1) #7
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #4
declare i8* @llvm.coro.free(token, i8* nocapture readonly) #5
declare void @free(i8* nocapture) local_unnamed_addr #6
declare i1 @llvm.coro.end(i8*, i1) #7
declare i8* @llvm.coro.subfn.addr(i8* nocapture readonly, i8) #5
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone }
attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #3 = { nounwind uwtable "coroutine.presplit"="1" "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #4 = { argmemonly nounwind }
attributes #5 = { argmemonly nounwind readonly }
attributes #6 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #7 = { nounwind }
attributes #8 = { alwaysinline nounwind }
attributes #9 = { noduplicate }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4}
!llvm.ident = !{!5}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (http://llvm.org/git/clang.git 6c405f93921ac99ff5b8521bb1b3df4449deede4) (http://llvm.org/git/llvm.git 6e6d3247102a0f87ce14e906dcf6a3a5ed3faa65)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "coro.c", directory: "/home/gor/build/bin")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 6c405f93921ac99ff5b8521bb1b3df4449deede4) (http://llvm.org/git/llvm.git 6e6d3247102a0f87ce14e906dcf6a3a5ed3faa65)"}
!6 = distinct !DISubprogram(name: "print", scope: !1, file: !1, line: 6, type: !7, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !10)
!7 = !DISubroutineType(types: !8)
!8 = !{null, !9}
!9 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!10 = !{!11}
!11 = !DILocalVariable(name: "v", arg: 1, scope: !6, file: !1, line: 6, type: !9)
!12 = !DIExpression()
!13 = !DILocation(line: 6, column: 16, scope: !6)
!14 = !DILocation(line: 6, column: 19, scope: !6)
!15 = !DILocation(line: 6, column: 25, scope: !6)
!16 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 8, type: !17, isLocal: false, isDefinition: true, scopeLine: 8, isOptimized: true, unit: !0, variables: !20)
!17 = !DISubroutineType(types: !18)
!18 = !{!19}
!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64, align: 64)
!20 = !{!21, !22, !24}
!21 = !DILocalVariable(name: "coro_hdl", scope: !16, file: !1, line: 9, type: !19)
!22 = !DILocalVariable(name: "i", scope: !23, file: !1, line: 11, type: !9)
!23 = distinct !DILexicalBlock(scope: !16, file: !1, line: 11, column: 3)
!24 = !DILocalVariable(name: "coro_mem", scope: !25, file: !1, line: 16, type: !19)
!25 = distinct !DILexicalBlock(scope: !16, file: !1, line: 16, column: 3)
!26 = !DILocation(line: 9, column: 3, scope: !16)
!27 = !DILocation(line: 11, column: 8, scope: !23)
!28 = !DILocation(line: 11, column: 12, scope: !23)
!29 = !DILocation(line: 6, column: 16, scope: !6, inlinedAt: !30)
!30 = distinct !DILocation(line: 12, column: 5, scope: !31)
!31 = distinct !DILexicalBlock(scope: !32, file: !1, line: 11, column: 25)
!32 = distinct !DILexicalBlock(scope: !23, file: !1, line: 11, column: 3)
!33 = !DILocation(line: 6, column: 19, scope: !6, inlinedAt: !30)
!34 = !DILocation(line: 13, column: 5, scope: !31)
!35 = !DILocation(line: 16, column: 3, scope: !25)
!36 = !DILocation(line: 16, column: 3, scope: !37)
!37 = distinct !DILexicalBlock(scope: !25, file: !1, line: 16, column: 3)
!38 = !DILocation(line: 16, column: 3, scope: !16)
!39 = !DILocation(line: 17, column: 1, scope: !16)

View File

@ -1,145 +0,0 @@
; Tests that coro-split removes cleanup code after coro.end in resume functions
; and retains it in the start function.
; RUN: opt < %s -coro-split -S | FileCheck %s
define i8* @f(i1 %val) "coroutine.presplit"="1" personality i32 3 {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%hdl = call i8* @llvm.coro.begin(token %id, i8* null)
call void @print(i32 0)
br i1 %val, label %resume, label %susp
susp:
%0 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %0, label %suspend [i8 0, label %resume
i8 1, label %suspend]
resume:
invoke void @print(i32 1) to label %suspend unwind label %lpad
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
call void @print(i32 0) ; should not be present in f.resume
ret i8* %hdl
lpad:
%lpval = landingpad { i8*, i32 }
cleanup
call void @print(i32 2)
%need.resume = call i1 @llvm.coro.end(i8* null, i1 true)
br i1 %need.resume, label %eh.resume, label %cleanup.cont
cleanup.cont:
call void @print(i32 3) ; should not be present in f.resume
br label %eh.resume
eh.resume:
resume { i8*, i32 } %lpval
}
; Verify that start function contains both print calls the one before and after coro.end
; CHECK-LABEL: define i8* @f(
; CHECK: invoke void @print(i32 1)
; CHECK: to label %AfterCoroEnd unwind label %lpad
; CHECK: AfterCoroEnd:
; CHECK: call void @print(i32 0)
; CHECK: ret i8* %hdl
; CHECK: lpad:
; CHECK-NEXT: %lpval = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call void @print(i32 2)
; CHECK-NEXT: call void @print(i32 3)
; CHECK-NEXT: resume { i8*, i32 } %lpval
define i8* @f2(i1 %val) "coroutine.presplit"="1" personality i32 4 {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%hdl = call i8* @llvm.coro.begin(token %id, i8* null)
call void @print(i32 0)
br i1 %val, label %resume, label %susp
susp:
%0 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %0, label %suspend [i8 0, label %resume
i8 1, label %suspend]
resume:
invoke void @print(i32 1) to label %suspend unwind label %lpad
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
call void @print(i32 0) ; should not be present in f.resume
ret i8* %hdl
lpad:
%tok = cleanuppad within none []
call void @print(i32 2)
%unused = call i1 @llvm.coro.end(i8* null, i1 true) [ "funclet"(token %tok) ]
cleanupret from %tok unwind label %cleanup.cont
cleanup.cont:
%tok2 = cleanuppad within none []
call void @print(i32 3) ; should not be present in f.resume
cleanupret from %tok2 unwind to caller
}
; Verify that start function contains both print calls the one before and after coro.end
; CHECK-LABEL: define i8* @f2(
; CHECK: invoke void @print(i32 1)
; CHECK: to label %AfterCoroEnd unwind label %lpad
; CHECK: AfterCoroEnd:
; CHECK: call void @print(i32 0)
; CHECK: ret i8* %hdl
; CHECK: lpad:
; CHECK-NEXT: %tok = cleanuppad within none []
; CHECK-NEXT: call void @print(i32 2)
; CHECK-NEXT: call void @print(i32 3)
; CHECK-NEXT: cleanupret from %tok unwind to caller
; VERIFY Resume Parts
; Verify that resume function does not contains both print calls appearing after coro.end
; CHECK-LABEL: define internal fastcc void @f.resume
; CHECK: invoke void @print(i32 1)
; CHECK: to label %CoroEnd unwind label %lpad
; CHECK: CoroEnd:
; CHECK-NEXT: ret void
; CHECK: lpad:
; CHECK-NEXT: %lpval = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call void @print(i32 2)
; CHECK-NEXT: resume { i8*, i32 } %lpval
; Verify that resume function does not contains both print calls appearing after coro.end
; CHECK-LABEL: define internal fastcc void @f2.resume
; CHECK: invoke void @print(i32 1)
; CHECK: to label %CoroEnd unwind label %lpad
; CHECK: CoroEnd:
; CHECK-NEXT: ret void
; CHECK: lpad:
; CHECK-NEXT: %tok = cleanuppad within none []
; CHECK-NEXT: call void @print(i32 2)
; CHECK-NEXT: cleanupret from %tok unwind to caller
declare i8* @llvm.coro.free(token, i8*)
declare i32 @llvm.coro.size.i32()
declare i8 @llvm.coro.suspend(token, i1)
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i8* @llvm.coro.alloc(token)
declare i8* @llvm.coro.begin(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare noalias i8* @malloc(i32)
declare void @print(i32)
declare void @free(i8*)

View File

@ -1,60 +0,0 @@
; Tests that coro-split will convert coro.resume followed by a suspend to a
; musttail call.
; RUN: opt < %s -coro-split -S | FileCheck %s
define void @f() "coroutine.presplit"="1" {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%alloc = call i8* @malloc(i64 16) #3
%vFrame = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %alloc)
%save = call token @llvm.coro.save(i8* null)
%addr1 = call i8* @llvm.coro.subfn.addr(i8* null, i8 0)
%pv1 = bitcast i8* %addr1 to void (i8*)*
call fastcc void %pv1(i8* null)
%suspend = call i8 @llvm.coro.suspend(token %save, i1 false)
switch i8 %suspend, label %exit [
i8 0, label %await.ready
i8 1, label %exit
]
await.ready:
%save2 = call token @llvm.coro.save(i8* null)
%addr2 = call i8* @llvm.coro.subfn.addr(i8* null, i8 0)
%pv2 = bitcast i8* %addr2 to void (i8*)*
call fastcc void %pv2(i8* null)
%suspend2 = call i8 @llvm.coro.suspend(token %save2, i1 false)
switch i8 %suspend2, label %exit [
i8 0, label %exit
i8 1, label %exit
]
exit:
call i1 @llvm.coro.end(i8* null, i1 false)
ret void
}
; Verify that in the initial function resume is not marked with musttail.
; CHECK-LABEL: @f(
; CHECK: %[[addr1:.+]] = call i8* @llvm.coro.subfn.addr(i8* null, i8 0)
; CHECK-NEXT: %[[pv1:.+]] = bitcast i8* %[[addr1]] to void (i8*)*
; CHECK-NOT: musttail call fastcc void %[[pv1]](i8* null)
; Verify that in the resume part resume call is marked with musttail.
; CHECK-LABEL: @f.resume(
; CHECK: %[[addr2:.+]] = call i8* @llvm.coro.subfn.addr(i8* null, i8 0)
; CHECK-NEXT: %[[pv2:.+]] = bitcast i8* %[[addr2]] to void (i8*)*
; CHECK-NEXT: musttail call fastcc void %[[pv2]](i8* null)
; CHECK-NEXT: ret void
declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*)
declare i1 @llvm.coro.alloc(token) #3
declare i64 @llvm.coro.size.i64() #5
declare i8* @llvm.coro.begin(token, i8* writeonly) #3
declare token @llvm.coro.save(i8*) #3
declare i8* @llvm.coro.frame() #5
declare i8 @llvm.coro.suspend(token, i1) #3
declare i8* @llvm.coro.free(token, i8* nocapture readonly) #2
declare i1 @llvm.coro.end(i8*, i1) #3
declare i8* @llvm.coro.subfn.addr(i8* nocapture readonly, i8) #5
declare i8* @malloc(i64)

View File

@ -1,59 +0,0 @@
; First example from Doc/Coroutines.rst (two block loop)
; RUN: opt < %s -enable-coroutines -O2 -S | FileCheck %s
define i8* @f(i32 %n) {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%size = call i32 @llvm.coro.size.i32()
%alloc = call i8* @malloc(i32 %size)
%hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
br label %loop
loop:
%n.val = phi i32 [ %n, %entry ], [ %inc, %resume ]
call void @print(i32 %n.val)
%0 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %0, label %suspend [i8 0, label %resume
i8 1, label %cleanup]
resume:
%inc = add i32 %n.val, 1
br label %loop
cleanup:
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %suspend
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 0)
ret i8* %hdl
}
; CHECK-LABEL: @main(
define i32 @main() {
entry:
%hdl = call i8* @f(i32 4)
call void @llvm.coro.resume(i8* %hdl)
call void @llvm.coro.resume(i8* %hdl)
call void @llvm.coro.destroy(i8* %hdl)
ret i32 0
; CHECK: entry:
; CHECK: call void @print(i32 4)
; CHECK: call void @print(i32 5)
; CHECK: call void @print(i32 6)
; CHECK: ret i32 0
}
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i8* @llvm.coro.alloc(token)
declare i8* @llvm.coro.free(token, i8*)
declare i32 @llvm.coro.size.i32()
declare i8 @llvm.coro.suspend(token, i1)
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)
declare i8* @llvm.coro.begin(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare noalias i8* @malloc(i32)
declare void @print(i32)
declare void @free(i8*)

View File

@ -1,54 +0,0 @@
; First example from Doc/Coroutines.rst (one block loop)
; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s
define i8* @f(i32 %n) {
entry:
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%size = call i32 @llvm.coro.size.i32()
%alloc = call i8* @malloc(i32 %size)
%hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %alloc)
br label %loop
loop:
%n.val = phi i32 [ %n, %entry ], [ %inc, %loop ]
%inc = add nsw i32 %n.val, 1
call void @print(i32 %n.val)
%0 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %0, label %suspend [i8 0, label %loop
i8 1, label %cleanup]
cleanup:
%mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
call void @free(i8* %mem)
br label %suspend
suspend:
call i1 @llvm.coro.end(i8* %hdl, i1 false)
ret i8* %hdl
}
; CHECK-LABEL: @main(
define i32 @main() {
entry:
%hdl = call i8* @f(i32 4)
call void @llvm.coro.resume(i8* %hdl)
call void @llvm.coro.resume(i8* %hdl)
call void @llvm.coro.destroy(i8* %hdl)
ret i32 0
; CHECK-NEXT: entry:
; CHECK: call void @print(i32 4)
; CHECK: call void @print(i32 5)
; CHECK: call void @print(i32 6)
; CHECK: ret i32 0
}
declare i8* @malloc(i32)
declare void @free(i8*)
declare void @print(i32)
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
declare i32 @llvm.coro.size.i32()
declare i8* @llvm.coro.begin(token, i8*)
declare i8 @llvm.coro.suspend(token, i1)
declare i8* @llvm.coro.free(token, i8*)
declare i1 @llvm.coro.end(i8*, i1)
declare void @llvm.coro.resume(i8*)
declare void @llvm.coro.destroy(i8*)

Some files were not shown because too many files have changed in this diff Show More