1 ; Tests the PHI nodes in cleanuppads for catchswitch instructions are correctly
3 ; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse' -S | FileCheck %s
5 declare i32 @__CxxFrameHandler3(...)
6 define i8* @f2(i1 %val) "coroutine.presplit"="1" personality i32 (...)* @__CxxFrameHandler3 {
8 %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
9 %valueA = call i32 @f();
10 %valueB = call i32 @f();
11 %need.alloc = call i1 @llvm.coro.alloc(token %id)
12 br i1 %need.alloc, label %dyn.alloc, label %dowork.0
15 %size = call i32 @llvm.coro.size.i32()
16 %alloc = call i8* @malloc(i32 %size)
20 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
21 %hdl = call i8* @llvm.coro.begin(token %id, i8* %phi)
22 invoke void @print(i32 0)
23 to label %checksuspend unwind label %catch.dispatch.1
26 %0 = call i8 @llvm.coro.suspend(token none, i1 false)
27 switch i8 %0, label %suspend [i8 0, label %dowork.1
31 invoke void @print(i32 0)
32 to label %checksuspend unwind label %catch.dispatch.1
35 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
36 call void @free(i8* %mem)
40 call i1 @llvm.coro.end(i8* %hdl, i1 0)
44 %cs1 = catchswitch within none [label %handler1] unwind to caller
46 %h1 = catchpad within %cs1 [i8* null, i32 64, i8* null]
47 invoke void @print(i32 2) [ "funclet"(token %h1) ]
48 to label %catchret1 unwind label %catch.dispatch.2
50 catchret from %h1 to label %cleanup
53 %cs2 = catchswitch within %h1 [label %handler2] unwind label %cleanup2
55 %h2 = catchpad within %cs2 [i8* null, i32 64, i8* null]
56 invoke void @print(i32 3) [ "funclet"(token %h2) ]
57 to label %cleanup unwind label %cleanup2
59 %cleanupval2 = phi i32 [%valueA, %catch.dispatch.2], [%valueB, %handler2]
60 cleanuppad within %h1 []
61 call void @print(i32 %cleanupval2)
64 ; Verifiers that a "dispatcher" cleanuppad is created.
66 ; catchswitch and all associated catchpads are required to have the same unwind
67 ; edge, but coro requires that PHI nodes are split up so that reload
68 ; instructions can be generated, therefore we create a new "dispatcher"
69 ; cleanuppad which forwards to individual blocks that contain the reload
70 ; instructions per catchswitch/catchpad and then all branch back to the
71 ; original cleanuppad block.
73 ; CHECK: catch.dispatch.2:
74 ; CHECK: %cs2 = catchswitch within %h1 [label %handler2] unwind label %cleanup2.corodispatch
77 ; CHECK: invoke void @print(i32 3)
78 ; CHECK: to label %cleanup unwind label %cleanup2.corodispatch
80 ; CHECK: cleanup2.corodispatch:
81 ; CHECK: %1 = phi i8 [ 0, %handler2 ], [ 1, %catch.dispatch.2 ]
82 ; CHECK: %2 = cleanuppad within %h1 []
83 ; CHECK: %switch = icmp ult i8 %1, 1
84 ; CHECK: br i1 %switch, label %cleanup2.from.handler2, label %cleanup2.from.catch.dispatch.2
86 ; CHECK: cleanup2.from.handler2:
87 ; CHECK: %valueB.reload = load i32, i32* %valueB.spill.addr, align 4
88 ; CHECK: br label %cleanup2
90 ; CHECK: cleanup2.from.catch.dispatch.2:
91 ; CHECK: %valueA.reload = load i32, i32* %valueA.spill.addr, align 4
92 ; CHECK: br label %cleanup2
95 ; CHECK: %cleanupval2 = phi i32 [ %valueA.reload, %cleanup2.from.catch.dispatch.2 ], [ %valueB.reload, %cleanup2.from.handler2 ]
96 ; CHECK: call void @print(i32 %cleanupval2)
97 ; CHECK: br label %cleanup
100 declare i8* @llvm.coro.free(token, i8*)
101 declare i32 @llvm.coro.size.i32()
102 declare i8 @llvm.coro.suspend(token, i1)
103 declare void @llvm.coro.resume(i8*)
104 declare void @llvm.coro.destroy(i8*)
106 declare token @llvm.coro.id(i32, i8*, i8*, i8*)
107 declare i1 @llvm.coro.alloc(token)
108 declare i8* @llvm.coro.begin(token, i8*)
109 declare i1 @llvm.coro.end(i8*, i1)
111 declare noalias i8* @malloc(i32)
112 declare void @print(i32)
113 declare void @free(i8*)