1; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -win-eh-prepare < %s | FileCheck %s 2; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -passes=win-eh-prepare < %s | FileCheck %s 3 4declare i32 @__CxxFrameHandler3(...) 5 6declare void @f() 7 8declare i32 @g() 9 10declare void @h(i32) 11 12declare i1 @i() 13 14declare void @llvm.bar() nounwind 15 16; CHECK-LABEL: @test1( 17define void @test1(i1 %B) personality ptr @__CxxFrameHandler3 { 18entry: 19 ; Spill slot should be inserted here 20 ; CHECK: [[Slot:%[^ ]+]] = alloca 21 ; Can't store for %phi at these defs because the lifetimes overlap 22 ; CHECK-NOT: store 23 %x = call i32 @g() 24 %y = call i32 @g() 25 br i1 %B, label %left, label %right 26left: 27 ; CHECK: left: 28 ; CHECK-NEXT: store i32 %x, ptr [[Slot]] 29 ; CHECK-NEXT: invoke void @f 30 invoke void @f() 31 to label %exit unwind label %merge 32right: 33 ; CHECK: right: 34 ; CHECK-NEXT: store i32 %y, ptr [[Slot]] 35 ; CHECK-NEXT: invoke void @f 36 invoke void @f() 37 to label %exit unwind label %merge 38merge: 39 ; CHECK: merge: 40 ; CHECK-NOT: = phi 41 %phi = phi i32 [ %x, %left ], [ %y, %right ] 42 %cs1 = catchswitch within none [label %catch] unwind to caller 43 44catch: 45 %cp = catchpad within %cs1 [] 46 ; CHECK: catch: 47 ; CHECK: [[Reload:%[^ ]+]] = load i32, ptr [[Slot]] 48 ; CHECK-NEXT: call void @h(i32 [[Reload]]) 49 call void @h(i32 %phi) [ "funclet"(token %cp) ] 50 catchret from %cp to label %exit 51 52exit: 53 ret void 54} 55 56; CHECK-LABEL: @test2( 57define void @test2(i1 %B) personality ptr @__CxxFrameHandler3 { 58entry: 59 br i1 %B, label %left, label %right 60left: 61 ; Need two stores here because %x and %y interfere so they need 2 slots 62 ; CHECK: left: 63 ; CHECK: store i32 1, ptr [[Slot1:%[^ ]+]] 64 ; CHECK: store i32 1, ptr [[Slot2:%[^ ]+]] 65 ; CHECK-NEXT: invoke void @f 66 invoke void @f() 67 to label %exit unwind label %merge.inner 68right: 69 ; Need two stores here because %x and %y interfere so they need 2 slots 70 ; CHECK: right: 71 ; CHECK-DAG: store i32 2, ptr [[Slot1]] 72 ; CHECK-DAG: store i32 2, ptr [[Slot2]] 73 ; CHECK: invoke void @f 74 invoke void @f() 75 to label %exit unwind label %merge.inner 76merge.inner: 77 ; CHECK: merge.inner: 78 ; CHECK-NOT: = phi 79 ; CHECK: catchswitch within none 80 %x = phi i32 [ 1, %left ], [ 2, %right ] 81 %cs1 = catchswitch within none [label %catch.inner] unwind label %merge.outer 82 83catch.inner: 84 %cpinner = catchpad within %cs1 [] 85 ; Need just one store here because only %y is affected 86 ; CHECK: catch.inner: 87 %z = call i32 @g() [ "funclet"(token %cpinner) ] 88 ; CHECK: store i32 %z 89 ; CHECK-NEXT: invoke void @f 90 invoke void @f() [ "funclet"(token %cpinner) ] 91 to label %catchret.inner unwind label %merge.outer 92 93catchret.inner: 94 catchret from %cpinner to label %exit 95 96merge.outer: 97 %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ] 98 ; CHECK: merge.outer: 99 ; CHECK-NOT: = phi 100 ; CHECK: catchswitch within none 101 %cs2 = catchswitch within none [label %catch.outer] unwind to caller 102 103catch.outer: 104 %cpouter = catchpad within %cs2 [] 105 ; CHECK: catch.outer: 106 ; CHECK: [[CatchPad:%[^ ]+]] = catchpad within %cs2 [] 107 ; Need to load x and y from two different slots since they're both live 108 ; and can have different values (if we came from catch.inner) 109 ; CHECK-DAG: load i32, ptr [[Slot1]] 110 ; CHECK-DAG: load i32, ptr [[Slot2]] 111 ; CHECK: catchret from [[CatchPad]] to label 112 call void @h(i32 %x) [ "funclet"(token %cpouter) ] 113 call void @h(i32 %y) [ "funclet"(token %cpouter) ] 114 catchret from %cpouter to label %exit 115 116exit: 117 ret void 118} 119 120; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer 121; %phi.outer needs stores in %left, %right, and %join 122; CHECK-LABEL: @test4( 123define void @test4(i1 %B) personality ptr @__CxxFrameHandler3 { 124entry: 125 ; CHECK: entry: 126 ; CHECK: [[Slot:%[^ ]+]] = alloca 127 ; CHECK-NEXT: br 128 br i1 %B, label %left, label %right 129left: 130 ; CHECK: left: 131 ; CHECK-NOT: store 132 ; CHECK: store i32 %l, ptr [[Slot]] 133 ; CHECK-NEXT: invoke void @f 134 %l = call i32 @g() 135 invoke void @f() 136 to label %join unwind label %catchpad.inner 137right: 138 ; CHECK: right: 139 ; CHECK-NOT: store 140 ; CHECK: store i32 %r, ptr [[Slot]] 141 ; CHECK-NEXT: invoke void @f 142 %r = call i32 @g() 143 invoke void @f() 144 to label %join unwind label %catchpad.inner 145catchpad.inner: 146 ; CHECK: catchpad.inner: 147 ; CHECK-NEXT: catchswitch within none 148 %phi.inner = phi i32 [ %l, %left ], [ %r, %right ] 149 %cs1 = catchswitch within none [label %catch.inner] unwind label %catchpad.outer 150catch.inner: 151 %cp1 = catchpad within %cs1 [] 152 catchret from %cp1 to label %join 153join: 154 ; CHECK: join: 155 ; CHECK-NOT: store 156 ; CHECK: store i32 %j, ptr [[Slot]] 157 ; CHECK-NEXT: invoke void @f 158 %j = call i32 @g() 159 invoke void @f() 160 to label %exit unwind label %catchpad.outer 161 162catchpad.outer: 163 ; CHECK: catchpad.outer: 164 ; CHECK-NEXT: catchswitch within none 165 %phi.outer = phi i32 [ %phi.inner, %catchpad.inner ], [ %j, %join ] 166 %cs2 = catchswitch within none [label %catch.outer] unwind to caller 167catch.outer: 168 ; CHECK: catch.outer: 169 ; CHECK: [[Reload:%[^ ]+]] = load i32, ptr [[Slot]] 170 ; CHECK: call void @h(i32 [[Reload]]) 171 %cp2 = catchpad within %cs2 [] 172 call void @h(i32 %phi.outer) [ "funclet"(token %cp2) ] 173 catchret from %cp2 to label %exit 174exit: 175 ret void 176} 177 178; CHECK-LABEL: @test5( 179define void @test5() personality ptr @__CxxFrameHandler3 { 180entry: 181 ; need store for %phi.cleanup 182 ; CHECK: entry: 183 ; CHECK: store i32 1, ptr [[CleanupSlot:%[^ ]+]] 184 ; CHECK-NEXT: invoke void @f 185 invoke void @f() 186 to label %invoke.cont unwind label %cleanup 187 188invoke.cont: 189 ; need store for %phi.cleanup 190 ; CHECK: invoke.cont: 191 ; CHECK-NEXT: store i32 2, ptr [[CleanupSlot]] 192 ; CHECK-NEXT: invoke void @f 193 invoke void @f() 194 to label %invoke.cont2 unwind label %cleanup 195 196cleanup: 197 ; cleanup phi can be loaded at cleanup entry 198 ; CHECK: cleanup: 199 ; CHECK-NEXT: cleanuppad within none [] 200 ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, ptr [[CleanupSlot]] 201 %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ] 202 %cp = cleanuppad within none [] 203 %b = call i1 @i() [ "funclet"(token %cp) ] 204 br i1 %b, label %left, label %right 205 206left: 207 ; CHECK: left: 208 ; CHECK: call void @h(i32 [[CleanupReload]] 209 call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ] 210 br label %merge 211 212right: 213 ; CHECK: right: 214 ; CHECK: call void @h(i32 [[CleanupReload]] 215 call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ] 216 br label %merge 217 218merge: 219 ; need store for %phi.catch 220 ; CHECK: merge: 221 ; CHECK-NEXT: store i32 [[CleanupReload]], ptr [[CatchSlot:%[^ ]+]] 222 ; CHECK-NEXT: cleanupret 223 cleanupret from %cp unwind label %catchswitch 224 225invoke.cont2: 226 ; need store for %phi.catch 227 ; CHECK: invoke.cont2: 228 ; CHECK-NEXT: store i32 3, ptr [[CatchSlot]] 229 ; CHECK-NEXT: invoke void @f 230 invoke void @f() 231 to label %exit unwind label %catchswitch 232 233catchswitch: 234 ; CHECK: catchswitch: 235 ; CHECK-NEXT: catchswitch within none 236 %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ] 237 %cs1 = catchswitch within none [label %catch] unwind to caller 238 239catch: 240 ; CHECK: catch: 241 ; CHECK: catchpad within %cs1 242 ; CHECK: [[CatchReload:%[^ ]+]] = load i32, ptr [[CatchSlot]] 243 ; CHECK: call void @h(i32 [[CatchReload]] 244 %cp2 = catchpad within %cs1 [] 245 call void @h(i32 %phi.catch) [ "funclet"(token %cp2) ] 246 catchret from %cp2 to label %exit 247 248exit: 249 ret void 250} 251 252; We used to demote %x, but we don't need to anymore. 253; CHECK-LABEL: @test6( 254define void @test6() personality ptr @__CxxFrameHandler3 { 255entry: 256 ; CHECK: entry: 257 ; CHECK: %x = invoke i32 @g() 258 ; CHECK-NEXT: to label %loop unwind label %to_caller 259 %x = invoke i32 @g() 260 to label %loop unwind label %to_caller 261to_caller: 262 %cp1 = cleanuppad within none [] 263 cleanupret from %cp1 unwind to caller 264loop: 265 invoke void @f() 266 to label %loop unwind label %cleanup 267cleanup: 268 ; CHECK: cleanup: 269 ; CHECK: call void @h(i32 %x) 270 %cp2 = cleanuppad within none [] 271 call void @h(i32 %x) [ "funclet"(token %cp2) ] 272 cleanupret from %cp2 unwind to caller 273} 274 275; CHECK-LABEL: @test7( 276define void @test7() personality ptr @__CxxFrameHandler3 { 277entry: 278 ; %x is an EH pad phi, so gets stored in pred here 279 ; CHECK: entry: 280 ; CHECK: store i32 1, ptr [[SlotX:%[^ ]+]] 281 ; CHECK: invoke void @f() 282 invoke void @f() 283 to label %invoke.cont unwind label %catchpad 284invoke.cont: 285 ; %x is an EH pad phi, so gets stored in pred here 286 ; CHECK: invoke.cont: 287 ; CHECK: store i32 2, ptr [[SlotX]] 288 ; CHECK: invoke void @f() 289 invoke void @f() 290 to label %exit unwind label %catchpad 291catchpad: 292 ; %x phi should be eliminated 293 ; CHECK: catchpad: 294 ; CHECK-NEXT: catchswitch within none 295 %x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ] 296 %cs1 = catchswitch within none [label %catch] unwind to caller 297catch: 298 ; CHECK: catch: 299 ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad within %cs1 [] 300 %cp = catchpad within %cs1 [] 301 %b = call i1 @i() [ "funclet"(token %cp) ] 302 br i1 %b, label %left, label %right 303left: 304 ; Edge from %left to %join needs to be split so that 305 ; the load of %x can be inserted *after* the catchret 306 ; CHECK: left: 307 ; CHECK-NEXT: catchret from %[[CatchPad]] to label %[[SplitLeft:[^ ]+]] 308 catchret from %cp to label %join 309 ; CHECK: [[SplitLeft]]: 310 ; CHECK: [[LoadX:%[^ ]+]] = load i32, ptr [[SlotX]] 311 ; CHECK: br label %join 312right: 313 ; Edge from %right to %join needs to be split so that 314 ; the load of %y can be inserted *after* the catchret 315 ; CHECK: right: 316 ; CHECK: %y = call i32 @g() 317 ; CHECK: catchret from %[[CatchPad]] to label %join 318 %y = call i32 @g() [ "funclet"(token %cp) ] 319 catchret from %cp to label %join 320join: 321 ; CHECK: join: 322 ; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ] 323 %phi = phi i32 [ %x, %left ], [ %y, %right ] 324 call void @h(i32 %phi) 325 br label %exit 326exit: 327 ret void 328} 329 330; CHECK-LABEL: @test8( 331define void @test8() personality ptr @__CxxFrameHandler3 { entry: 332 invoke void @f() 333 to label %done unwind label %cleanup1 334 invoke void @f() 335 to label %done unwind label %cleanup2 336 337done: 338 ret void 339 340cleanup1: 341 ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad within none [] 342 ; CHECK-NEXT: call void @llvm.bar() 343 ; CHECK-NEXT: cleanupret from [[CleanupPad1]] 344 %cp0 = cleanuppad within none [] 345 br label %cleanupexit 346 347cleanup2: 348 ; CHECK: cleanuppad within none [] 349 ; CHECK-NEXT: call void @llvm.bar() 350 ; CHECK-NEXT: unreachable 351 %cp1 = cleanuppad within none [] 352 br label %cleanupexit 353 354cleanupexit: 355 call void @llvm.bar() 356 cleanupret from %cp0 unwind label %cleanup2 357} 358