1 ; Tests the PHI nodes in cleanuppads for catchswitch instructions are correctly
3 ; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg<switch-range-to-icmp>,early-cse' -S | FileCheck %s
5 declare i32 @__CxxFrameHandler3(...)
6 define ptr @f2(i1 %val) presplitcoroutine personality ptr @__CxxFrameHandler3 {
8 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr 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 ptr @malloc(i32 %size)
20 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
21 %hdl = call ptr @llvm.coro.begin(token %id, ptr %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 ptr @llvm.coro.free(token %id, ptr %hdl)
36 call void @free(ptr %mem)
40 call i1 @llvm.coro.end(ptr %hdl, i1 0, token none)
44 %cs1 = catchswitch within none [label %handler1] unwind to caller
46 %h1 = catchpad within %cs1 [ptr null, i32 64, ptr 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 [ptr null, i32 64, ptr 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, ptr %valueB.spill.addr, align 4
88 ; CHECK: br label %cleanup2
90 ; CHECK: cleanup2.from.catch.dispatch.2:
91 ; CHECK: %valueA.reload = load i32, ptr %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 ptr @llvm.coro.free(token, ptr)
101 declare i32 @llvm.coro.size.i32()
102 declare i8 @llvm.coro.suspend(token, i1)
103 declare void @llvm.coro.resume(ptr)
104 declare void @llvm.coro.destroy(ptr)
106 declare token @llvm.coro.id(i32, ptr, ptr, ptr)
107 declare i1 @llvm.coro.alloc(token)
108 declare ptr @llvm.coro.begin(token, ptr)
109 declare i1 @llvm.coro.end(ptr, i1, token)
111 declare noalias ptr @malloc(i32)
112 declare void @print(i32)
113 declare void @free(ptr)