Home | History | Annotate | Download | only in WinEH
      1 ; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare  < %s | FileCheck %s
      2 
      3 declare i32 @__CxxFrameHandler3(...)
      4 
      5 declare void @f()
      6 
      7 declare i32 @g()
      8 
      9 declare void @h(i32)
     10 
     11 declare i1 @i()
     12 
     13 declare void @llvm.bar() nounwind
     14 
     15 ; CHECK-LABEL: @test1(
     16 define void @test1(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
     17 entry:
     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
     25 left:
     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
     31 right:
     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
     37 merge:
     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 
     43 catch:
     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 
     51 exit:
     52   ret void
     53 }
     54 
     55 ; CHECK-LABEL: @test2(
     56 define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
     57 entry:
     58   br i1 %B, label %left, label %right
     59 left:
     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
     67 right:
     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
     75 merge.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 
     82 catch.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 
     92 catchret.inner:
     93   catchret from %cpinner to label %exit
     94 
     95 merge.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 
    102 catch.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 
    115 exit:
    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(
    122 define void @test4(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
    123 entry:
    124   ; CHECK:      entry:
    125   ; CHECK:        [[Slot:%[^ ]+]] = alloca
    126   ; CHECK-NEXT:   br
    127   br i1 %B, label %left, label %right
    128 left:
    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
    136 right:
    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
    144 catchpad.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
    149 catch.inner:
    150    %cp1 = catchpad within %cs1 []
    151    catchret from %cp1 to label %join
    152 join:
    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 
    161 catchpad.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
    166 catch.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
    173 exit:
    174    ret void
    175 }
    176 
    177 ; CHECK-LABEL: @test5(
    178 define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
    179 entry:
    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 
    187 invoke.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 
    195 cleanup:
    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 
    205 left:
    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 
    211 right:
    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 
    217 merge:
    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 
    224 invoke.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 
    232 catchswitch:
    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 
    238 catch:
    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 
    247 exit:
    248   ret void
    249 }
    250 
    251 ; We used to demote %x, but we don't need to anymore.
    252 ; CHECK-LABEL: @test6(
    253 define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
    254 entry:
    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
    260 to_caller:
    261   %cp1 = cleanuppad within none []
    262   cleanupret from %cp1 unwind to caller
    263 loop:
    264   invoke void @f()
    265           to label %loop unwind label %cleanup
    266 cleanup:
    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(
    275 define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
    276 entry:
    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
    283 invoke.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
    290 catchpad:
    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
    296 catch:
    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
    302 left:
    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
    311 right:
    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
    319 join:
    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
    325 exit:
    326   ret void
    327 }
    328 
    329 ; CHECK-LABEL: @test8(
    330 define 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 
    336 done:
    337   ret void
    338 
    339 cleanup1:
    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 
    346 cleanup2:
    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 
    353 cleanupexit:
    354   call void @llvm.bar()
    355   cleanupret from %cp0 unwind label %cleanup2
    356 }
    357