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