You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
@ -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*)
|
@ -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
|
@ -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*)
|
||||
|
@ -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"
|
@ -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*)
|
@ -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)
|
@ -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)
|
@ -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*)
|
@ -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)
|
@ -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*)
|
@ -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*)
|
@ -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*)
|
@ -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*)
|
@ -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*)
|
@ -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
|
||||
|
@ -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)
|
@ -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*)
|
||||
|
@ -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)
|
59
external/llvm/test/Transforms/Coroutines/ex0.ll
vendored
59
external/llvm/test/Transforms/Coroutines/ex0.ll
vendored
@ -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*)
|
54
external/llvm/test/Transforms/Coroutines/ex1.ll
vendored
54
external/llvm/test/Transforms/Coroutines/ex1.ll
vendored
@ -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
Reference in New Issue
Block a user