360 lines · plain
1; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -win-eh-prepare < %s | FileCheck %s2; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -passes=win-eh-prepare < %s | FileCheck %s3; RUN: %if aarch64-registered-target %{ opt -mtriple=aarch64-pc-windows-msvc -S -win-eh-prepare < %s | FileCheck %s %}4; RUN: %if aarch64-registered-target %{ opt -mtriple=aarch64-pc-windows-msvc -S -passes=win-eh-prepare < %s | FileCheck %s %}5 6declare i32 @__CxxFrameHandler3(...)7 8declare void @f()9 10declare i32 @g()11 12declare void @h(i32)13 14declare i1 @i()15 16declare void @llvm.bar() nounwind17 18; CHECK-LABEL: @test1(19define void @test1(i1 %B) personality ptr @__CxxFrameHandler3 {20entry:21 ; Spill slot should be inserted here22 ; CHECK: [[Slot:%[^ ]+]] = alloca23 ; Can't store for %phi at these defs because the lifetimes overlap24 ; CHECK-NOT: store25 %x = call i32 @g()26 %y = call i32 @g()27 br i1 %B, label %left, label %right28left:29 ; CHECK: left:30 ; CHECK-NEXT: store i32 %x, ptr [[Slot]]31 ; CHECK-NEXT: invoke void @f32 invoke void @f()33 to label %exit unwind label %merge34right:35 ; CHECK: right:36 ; CHECK-NEXT: store i32 %y, ptr [[Slot]]37 ; CHECK-NEXT: invoke void @f38 invoke void @f()39 to label %exit unwind label %merge40merge:41 ; CHECK: merge:42 ; CHECK-NOT: = phi43 %phi = phi i32 [ %x, %left ], [ %y, %right ]44 %cs1 = catchswitch within none [label %catch] unwind to caller45 46catch:47 %cp = catchpad within %cs1 []48 ; CHECK: catch:49 ; CHECK: [[Reload:%[^ ]+]] = load i32, ptr [[Slot]]50 ; CHECK-NEXT: call void @h(i32 [[Reload]])51 call void @h(i32 %phi) [ "funclet"(token %cp) ]52 catchret from %cp to label %exit53 54exit:55 ret void56}57 58; CHECK-LABEL: @test2(59define void @test2(i1 %B) personality ptr @__CxxFrameHandler3 {60entry:61 br i1 %B, label %left, label %right62left:63 ; Need two stores here because %x and %y interfere so they need 2 slots64 ; CHECK: left:65 ; CHECK: store i32 1, ptr [[Slot1:%[^ ]+]]66 ; CHECK: store i32 1, ptr [[Slot2:%[^ ]+]]67 ; CHECK-NEXT: invoke void @f68 invoke void @f()69 to label %exit unwind label %merge.inner70right:71 ; Need two stores here because %x and %y interfere so they need 2 slots72 ; CHECK: right:73 ; CHECK-DAG: store i32 2, ptr [[Slot1]]74 ; CHECK-DAG: store i32 2, ptr [[Slot2]]75 ; CHECK: invoke void @f76 invoke void @f()77 to label %exit unwind label %merge.inner78merge.inner:79 ; CHECK: merge.inner:80 ; CHECK-NOT: = phi81 ; CHECK: catchswitch within none82 %x = phi i32 [ 1, %left ], [ 2, %right ]83 %cs1 = catchswitch within none [label %catch.inner] unwind label %merge.outer84 85catch.inner:86 %cpinner = catchpad within %cs1 []87 ; Need just one store here because only %y is affected88 ; CHECK: catch.inner:89 %z = call i32 @g() [ "funclet"(token %cpinner) ]90 ; CHECK: store i32 %z91 ; CHECK-NEXT: invoke void @f92 invoke void @f() [ "funclet"(token %cpinner) ]93 to label %catchret.inner unwind label %merge.outer94 95catchret.inner:96 catchret from %cpinner to label %exit97 98merge.outer:99 %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]100 ; CHECK: merge.outer:101 ; CHECK-NOT: = phi102 ; CHECK: catchswitch within none103 %cs2 = catchswitch within none [label %catch.outer] unwind to caller104 105catch.outer:106 %cpouter = catchpad within %cs2 []107 ; CHECK: catch.outer:108 ; CHECK: [[CatchPad:%[^ ]+]] = catchpad within %cs2 []109 ; Need to load x and y from two different slots since they're both live110 ; and can have different values (if we came from catch.inner)111 ; CHECK-DAG: load i32, ptr [[Slot1]]112 ; CHECK-DAG: load i32, ptr [[Slot2]]113 ; CHECK: catchret from [[CatchPad]] to label114 call void @h(i32 %x) [ "funclet"(token %cpouter) ]115 call void @h(i32 %y) [ "funclet"(token %cpouter) ]116 catchret from %cpouter to label %exit117 118exit:119 ret void120}121 122; test4: don't need stores for %phi.inner, as its only use is to feed %phi.outer123; %phi.outer needs stores in %left, %right, and %join124; CHECK-LABEL: @test4(125define void @test4(i1 %B) personality ptr @__CxxFrameHandler3 {126entry:127 ; CHECK: entry:128 ; CHECK: [[Slot:%[^ ]+]] = alloca129 ; CHECK-NEXT: br130 br i1 %B, label %left, label %right131left:132 ; CHECK: left:133 ; CHECK-NOT: store134 ; CHECK: store i32 %l, ptr [[Slot]]135 ; CHECK-NEXT: invoke void @f136 %l = call i32 @g()137 invoke void @f()138 to label %join unwind label %catchpad.inner139right:140 ; CHECK: right:141 ; CHECK-NOT: store142 ; CHECK: store i32 %r, ptr [[Slot]]143 ; CHECK-NEXT: invoke void @f144 %r = call i32 @g()145 invoke void @f()146 to label %join unwind label %catchpad.inner147catchpad.inner:148 ; CHECK: catchpad.inner:149 ; CHECK-NEXT: catchswitch within none150 %phi.inner = phi i32 [ %l, %left ], [ %r, %right ]151 %cs1 = catchswitch within none [label %catch.inner] unwind label %catchpad.outer152catch.inner:153 %cp1 = catchpad within %cs1 []154 catchret from %cp1 to label %join155join:156 ; CHECK: join:157 ; CHECK-NOT: store158 ; CHECK: store i32 %j, ptr [[Slot]]159 ; CHECK-NEXT: invoke void @f160 %j = call i32 @g()161 invoke void @f()162 to label %exit unwind label %catchpad.outer163 164catchpad.outer:165 ; CHECK: catchpad.outer:166 ; CHECK-NEXT: catchswitch within none167 %phi.outer = phi i32 [ %phi.inner, %catchpad.inner ], [ %j, %join ]168 %cs2 = catchswitch within none [label %catch.outer] unwind to caller169catch.outer:170 ; CHECK: catch.outer:171 ; CHECK: [[Reload:%[^ ]+]] = load i32, ptr [[Slot]]172 ; CHECK: call void @h(i32 [[Reload]])173 %cp2 = catchpad within %cs2 []174 call void @h(i32 %phi.outer) [ "funclet"(token %cp2) ]175 catchret from %cp2 to label %exit176exit:177 ret void178}179 180; CHECK-LABEL: @test5(181define void @test5() personality ptr @__CxxFrameHandler3 {182entry:183 ; need store for %phi.cleanup184 ; CHECK: entry:185 ; CHECK: store i32 1, ptr [[CleanupSlot:%[^ ]+]]186 ; CHECK-NEXT: invoke void @f187 invoke void @f()188 to label %invoke.cont unwind label %cleanup189 190invoke.cont:191 ; need store for %phi.cleanup192 ; CHECK: invoke.cont:193 ; CHECK-NEXT: store i32 2, ptr [[CleanupSlot]]194 ; CHECK-NEXT: invoke void @f195 invoke void @f()196 to label %invoke.cont2 unwind label %cleanup197 198cleanup:199 ; cleanup phi can be loaded at cleanup entry200 ; CHECK: cleanup:201 ; CHECK-NEXT: cleanuppad within none []202 ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, ptr [[CleanupSlot]]203 %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]204 %cp = cleanuppad within none []205 %b = call i1 @i() [ "funclet"(token %cp) ]206 br i1 %b, label %left, label %right207 208left:209 ; CHECK: left:210 ; CHECK: call void @h(i32 [[CleanupReload]]211 call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]212 br label %merge213 214right:215 ; CHECK: right:216 ; CHECK: call void @h(i32 [[CleanupReload]]217 call void @h(i32 %phi.cleanup) [ "funclet"(token %cp) ]218 br label %merge219 220merge:221 ; need store for %phi.catch222 ; CHECK: merge:223 ; CHECK-NEXT: store i32 [[CleanupReload]], ptr [[CatchSlot:%[^ ]+]]224 ; CHECK-NEXT: cleanupret225 cleanupret from %cp unwind label %catchswitch226 227invoke.cont2:228 ; need store for %phi.catch229 ; CHECK: invoke.cont2:230 ; CHECK-NEXT: store i32 3, ptr [[CatchSlot]]231 ; CHECK-NEXT: invoke void @f232 invoke void @f()233 to label %exit unwind label %catchswitch234 235catchswitch:236 ; CHECK: catchswitch:237 ; CHECK-NEXT: catchswitch within none238 %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]239 %cs1 = catchswitch within none [label %catch] unwind to caller240 241catch:242 ; CHECK: catch:243 ; CHECK: catchpad within %cs1244 ; CHECK: [[CatchReload:%[^ ]+]] = load i32, ptr [[CatchSlot]]245 ; CHECK: call void @h(i32 [[CatchReload]]246 %cp2 = catchpad within %cs1 []247 call void @h(i32 %phi.catch) [ "funclet"(token %cp2) ]248 catchret from %cp2 to label %exit249 250exit:251 ret void252}253 254; We used to demote %x, but we don't need to anymore.255; CHECK-LABEL: @test6(256define void @test6() personality ptr @__CxxFrameHandler3 {257entry:258 ; CHECK: entry:259 ; CHECK: %x = invoke i32 @g()260 ; CHECK-NEXT: to label %loop unwind label %to_caller261 %x = invoke i32 @g()262 to label %loop unwind label %to_caller263to_caller:264 %cp1 = cleanuppad within none []265 cleanupret from %cp1 unwind to caller266loop:267 invoke void @f()268 to label %loop unwind label %cleanup269cleanup:270 ; CHECK: cleanup:271 ; CHECK: call void @h(i32 %x)272 %cp2 = cleanuppad within none []273 call void @h(i32 %x) [ "funclet"(token %cp2) ]274 cleanupret from %cp2 unwind to caller275}276 277; CHECK-LABEL: @test7(278define void @test7() personality ptr @__CxxFrameHandler3 {279entry:280 ; %x is an EH pad phi, so gets stored in pred here281 ; CHECK: entry:282 ; CHECK: store i32 1, ptr [[SlotX:%[^ ]+]]283 ; CHECK: invoke void @f()284 invoke void @f()285 to label %invoke.cont unwind label %catchpad286invoke.cont:287 ; %x is an EH pad phi, so gets stored in pred here288 ; CHECK: invoke.cont:289 ; CHECK: store i32 2, ptr [[SlotX]]290 ; CHECK: invoke void @f()291 invoke void @f()292 to label %exit unwind label %catchpad293catchpad:294 ; %x phi should be eliminated295 ; CHECK: catchpad:296 ; CHECK-NEXT: catchswitch within none297 %x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]298 %cs1 = catchswitch within none [label %catch] unwind to caller299catch:300 ; CHECK: catch:301 ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad within %cs1 []302 %cp = catchpad within %cs1 []303 %b = call i1 @i() [ "funclet"(token %cp) ]304 br i1 %b, label %left, label %right305left:306 ; Edge from %left to %join needs to be split so that307 ; the load of %x can be inserted *after* the catchret308 ; CHECK: left:309 ; CHECK-NEXT: catchret from %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]310 catchret from %cp to label %join311 ; CHECK: [[SplitLeft]]:312 ; CHECK: [[LoadX:%[^ ]+]] = load i32, ptr [[SlotX]]313 ; CHECK: br label %join314right:315 ; Edge from %right to %join needs to be split so that316 ; the load of %y can be inserted *after* the catchret317 ; CHECK: right:318 ; CHECK: %y = call i32 @g()319 ; CHECK: catchret from %[[CatchPad]] to label %join320 %y = call i32 @g() [ "funclet"(token %cp) ]321 catchret from %cp to label %join322join:323 ; CHECK: join:324 ; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]325 %phi = phi i32 [ %x, %left ], [ %y, %right ]326 call void @h(i32 %phi)327 br label %exit328exit:329 ret void330}331 332; CHECK-LABEL: @test8(333define void @test8() personality ptr @__CxxFrameHandler3 { entry:334 invoke void @f()335 to label %done unwind label %cleanup1336 invoke void @f()337 to label %done unwind label %cleanup2338 339done:340 ret void341 342cleanup1:343 ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad within none []344 ; CHECK-NEXT: call void @llvm.bar()345 ; CHECK-NEXT: cleanupret from [[CleanupPad1]]346 %cp0 = cleanuppad within none []347 br label %cleanupexit348 349cleanup2:350 ; CHECK: cleanuppad within none []351 ; CHECK-NEXT: call void @llvm.bar()352 ; CHECK-NEXT: unreachable353 %cp1 = cleanuppad within none []354 br label %cleanupexit355 356cleanupexit:357 call void @llvm.bar()358 cleanupret from %cp0 unwind label %cleanup2359}360