Home | History | Annotate | Download | only in SimplifyCFG
      1 ; RUN: opt < %s -simplifycfg -S | FileCheck %s
      2 
      3 ; ModuleID = 'cppeh-simplify.cpp'
      4 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
      5 target triple = "x86_64-pc-windows-msvc18.0.0"
      6 
      7 
      8 ; This case arises when two objects with empty destructors are cleaned up.
      9 ;
     10 ; void f1() { 
     11 ;   S a;
     12 ;   S b;
     13 ;   g(); 
     14 ; }
     15 ;
     16 ; In this case, both cleanup pads can be eliminated and the invoke can be
     17 ; converted to a call.
     18 ;
     19 ; CHECK: define void @f1()
     20 ; CHECK: entry:
     21 ; CHECK:   call void @g()
     22 ; CHECK:   ret void
     23 ; CHECK-NOT: cleanuppad
     24 ; CHECK: }
     25 ;
     26 define void @f1() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
     27 entry:
     28   invoke void @g() to label %invoke.cont unwind label %ehcleanup
     29 
     30 invoke.cont:                                      ; preds = %entry
     31   ret void
     32 
     33 ehcleanup:                                        ; preds = %entry
     34   %0 = cleanuppad within none []
     35   cleanupret from %0 unwind label %ehcleanup.1
     36 
     37 ehcleanup.1:                                      ; preds = %ehcleanup
     38   %1 = cleanuppad within none []
     39   cleanupret from %1 unwind to caller
     40 }
     41 
     42 
     43 ; This case arises when an object with an empty destructor must be cleaned up
     44 ; outside of a try-block and an object with a non-empty destructor must be
     45 ; cleaned up within the try-block.
     46 ;
     47 ; void f2() { 
     48 ;   S a;
     49 ;   try {
     50 ;     S2 b;
     51 ;     g();
     52 ;   } catch (...) {}
     53 ; }
     54 ;
     55 ; In this case, the outermost cleanup pad can be eliminated and the catch block
     56 ; should unwind to the caller (that is, exception handling continues with the
     57 ; parent frame of the caller).
     58 ;
     59 ; CHECK: define void @f2()
     60 ; CHECK: entry:
     61 ; CHECK:   invoke void @g()
     62 ; CHECK: ehcleanup:
     63 ; CHECK:   cleanuppad within none
     64 ; CHECK:   call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
     65 ; CHECK:   cleanupret from %0 unwind label %catch.dispatch
     66 ; CHECK: catch.dispatch:
     67 ; CHECK:   catchswitch within none [label %catch] unwind to caller
     68 ; CHECK: catch:
     69 ; CHECK:   catchpad
     70 ; CHECK:   catchret
     71 ; CHECK-NOT: cleanuppad
     72 ; CHECK: }
     73 ;
     74 define void @f2() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
     75 entry:
     76   %b = alloca %struct.S2, align 1
     77   invoke void @g() to label %invoke.cont unwind label %ehcleanup
     78 
     79 invoke.cont:                                      ; preds = %entry
     80   br label %try.cont
     81 
     82 ehcleanup:                                        ; preds = %entry
     83   %0 = cleanuppad within none []
     84   call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
     85   cleanupret from %0 unwind label %catch.dispatch
     86 
     87 catch.dispatch:                                   ; preds = %ehcleanup
     88   %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
     89 
     90 catch:                                            ; preds = %catch.dispatch
     91   %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
     92   catchret from %1 to label %catchret.dest
     93 
     94 catchret.dest:                                    ; preds = %catch
     95   br label %try.cont
     96 
     97 try.cont:                                         ; preds = %catchret.dest, %invoke.cont
     98   ret void
     99 
    100 ehcleanup.1:
    101   %2 = cleanuppad within none []
    102   cleanupret from %2 unwind to caller
    103 }
    104 
    105 
    106 ; This case arises when an object with a non-empty destructor must be cleaned up
    107 ; outside of a try-block and an object with an empty destructor must be cleaned
    108 ; within the try-block.
    109 ;
    110 ; void f3() { 
    111 ;   S2 a;
    112 ;   try {
    113 ;     S b;
    114 ;     g();
    115 ;   } catch (...) {}
    116 ; }
    117 ;
    118 ; In this case the inner cleanup pad should be eliminated and the invoke of g()
    119 ; should unwind directly to the catchpad.
    120 ;
    121 ; CHECK-LABEL: define void @f3()
    122 ; CHECK: entry:
    123 ; CHECK:   invoke void @g()
    124 ; CHECK:           to label %try.cont unwind label %catch.dispatch
    125 ; CHECK: catch.dispatch:
    126 ; CHECK-NEXT: catchswitch within none [label %catch] unwind label %ehcleanup.1
    127 ; CHECK: catch:
    128 ; CHECK:   catchpad within %cs1 [i8* null, i32 64, i8* null]
    129 ; CHECK:   catchret
    130 ; CHECK: ehcleanup.1:
    131 ; CHECK:   cleanuppad
    132 ; CHECK:   call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
    133 ; CHECK:   cleanupret from %cp3 unwind to caller
    134 ; CHECK: }
    135 ;
    136 define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
    137 entry:
    138   %a = alloca %struct.S2, align 1
    139   invoke void @g() to label %invoke.cont unwind label %ehcleanup
    140 
    141 invoke.cont:                                      ; preds = %entry
    142   br label %try.cont
    143 
    144 ehcleanup:                                        ; preds = %entry
    145   %0 = cleanuppad within none []
    146   cleanupret from %0 unwind label %catch.dispatch
    147 
    148 catch.dispatch:                                   ; preds = %ehcleanup
    149   %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
    150 
    151 catch:                                            ; preds = %catch.dispatch
    152   %cp2 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
    153   catchret from %cp2 to label %catchret.dest
    154 
    155 catchret.dest:                                    ; preds = %catch
    156   br label %try.cont
    157 
    158 try.cont:                                         ; preds = %catchret.dest, %invoke.cont
    159   ret void
    160 
    161 ehcleanup.1:
    162   %cp3 = cleanuppad within none []
    163   call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
    164   cleanupret from %cp3 unwind to caller
    165 }
    166 
    167 
    168 ; This case arises when an object with an empty destructor may require cleanup
    169 ; from either inside or outside of a try-block.
    170 ;
    171 ; void f4() { 
    172 ;   S a;
    173 ;   g();
    174 ;   try {
    175 ;     g();
    176 ;   } catch (...) {}
    177 ; }
    178 ;
    179 ; In this case, the cleanuppad should be eliminated, the invoke outside of the
    180 ; catch block should be converted to a call (that is, that is, exception
    181 ; handling continues with the parent frame of the caller).)
    182 ;
    183 ; CHECK-LABEL: define void @f4()
    184 ; CHECK: entry:
    185 ; CHECK:   call void @g
    186 ; Note: The cleanuppad simplification will insert an unconditional branch here
    187 ;       but it will be eliminated, placing the following invoke in the entry BB. 
    188 ; CHECK:   invoke void @g()
    189 ; CHECK:           to label %try.cont unwind label %catch.dispatch
    190 ; CHECK: catch.dispatch:
    191 ; CHECK:   catchswitch within none [label %catch] unwind to caller
    192 ; CHECK: catch:
    193 ; CHECK:   catchpad
    194 ; CHECK:   catchret
    195 ; CHECK-NOT: cleanuppad
    196 ; CHECK: }
    197 ;
    198 define void @f4() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
    199 entry:
    200   invoke void @g()
    201           to label %invoke.cont unwind label %ehcleanup
    202 
    203 invoke.cont:                                      ; preds = %entry
    204   invoke void @g()
    205           to label %try.cont unwind label %catch.dispatch
    206 
    207 catch.dispatch:                                   ; preds = %invoke.cont
    208   %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup
    209 
    210 catch:                                            ; preds = %catch.dispatch
    211   %0 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
    212   catchret from %0 to label %try.cont
    213 
    214 try.cont:                                         ; preds = %catch, %invoke.cont
    215   ret void
    216 
    217 ehcleanup:
    218   %cp2 = cleanuppad within none []
    219   cleanupret from %cp2 unwind to caller
    220 }
    221 
    222 ; This case tests simplification of an otherwise empty cleanup pad that contains
    223 ; a PHI node.
    224 ;
    225 ; int f6() {
    226 ;   int state = 1;
    227 ;   try {
    228 ;     S a;
    229 ;     g();
    230 ;     state = 2;
    231 ;     g();
    232 ;   } catch (...) {
    233 ;     return state;
    234 ;   }
    235 ;   return 0;
    236 ; }
    237 ;
    238 ; In this case, the cleanup pad should be eliminated and the PHI node in the
    239 ; cleanup pad should be sunk into the catch dispatch block.
    240 ;
    241 ; CHECK-LABEL: define i32 @f6()
    242 ; CHECK: entry:
    243 ; CHECK:   invoke void @g()
    244 ; CHECK: invoke.cont:
    245 ; CHECK:   invoke void @g()
    246 ; CHECK-NOT: ehcleanup:
    247 ; CHECK-NOT:   cleanuppad
    248 ; CHECK: catch.dispatch:
    249 ; CHECK:   %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
    250 ; CHECK: }
    251 define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
    252 entry:
    253   invoke void @g()
    254           to label %invoke.cont unwind label %ehcleanup
    255 
    256 invoke.cont:                                      ; preds = %entry
    257   invoke void @g()
    258           to label %return unwind label %ehcleanup
    259 
    260 ehcleanup:                                        ; preds = %invoke.cont, %entry
    261   %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
    262   %0 = cleanuppad within none []
    263   cleanupret from %0 unwind label %catch.dispatch
    264 
    265 catch.dispatch:                                   ; preds = %ehcleanup
    266   %cs1 = catchswitch within none [label %catch] unwind to caller
    267 
    268 catch:                                            ; preds = %catch.dispatch
    269   %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
    270   catchret from %1 to label %return
    271 
    272 return:                                           ; preds = %invoke.cont, %catch
    273   %retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ]
    274   ret i32 %retval.0
    275 }
    276 
    277 ; This case tests another variation of simplification of an otherwise empty
    278 ; cleanup pad that contains a PHI node.
    279 ;
    280 ; int f7() {
    281 ;   int state = 1;
    282 ;   try {
    283 ;     g();
    284 ;     state = 2;
    285 ;     S a;
    286 ;     g();
    287 ;     state = 3;
    288 ;     g();
    289 ;   } catch (...) {
    290 ;     return state;
    291 ;   }
    292 ;   return 0;
    293 ; }
    294 ;
    295 ; In this case, the cleanup pad should be eliminated and the PHI node in the
    296 ; cleanup pad should be merged with the PHI node in the catch dispatch block.
    297 ;
    298 ; CHECK-LABEL: define i32 @f7()
    299 ; CHECK: entry:
    300 ; CHECK:   invoke void @g()
    301 ; CHECK: invoke.cont:
    302 ; CHECK:   invoke void @g()
    303 ; CHECK: invoke.cont.1:
    304 ; CHECK:   invoke void @g()
    305 ; CHECK-NOT: ehcleanup:
    306 ; CHECK-NOT:   cleanuppad
    307 ; CHECK: catch.dispatch:
    308 ; CHECK:   %state.1 = phi i32 [ 1, %entry ], [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
    309 ; CHECK: }
    310 define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
    311 entry:
    312   invoke void @g()
    313           to label %invoke.cont unwind label %catch.dispatch
    314 
    315 invoke.cont:                                      ; preds = %entry
    316   invoke void @g()
    317           to label %invoke.cont.1 unwind label %ehcleanup
    318 
    319 invoke.cont.1:                                    ; preds = %invoke.cont
    320   invoke void @g()
    321           to label %return unwind label %ehcleanup
    322 
    323 ehcleanup:                                        ; preds = %invoke.cont.1, %invoke.cont
    324   %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
    325   %0 = cleanuppad within none []
    326   cleanupret from %0 unwind label %catch.dispatch
    327 
    328 catch.dispatch:                                   ; preds = %ehcleanup, %entry
    329   %state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ]
    330   %cs1 = catchswitch within none [label %catch] unwind to caller
    331 
    332 catch:                                            ; preds = %catch.dispatch
    333   %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
    334   catchret from %1 to label %return
    335 
    336 return:                                           ; preds = %invoke.cont.1, %catch
    337   %retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ]
    338   ret i32 %retval.0
    339 }
    340 
    341 ; This case tests a scenario where an empty cleanup pad is not dominated by all
    342 ; of the predecessors of its successor, but the successor references a PHI node
    343 ; in the empty cleanup pad.
    344 ;
    345 ; Conceptually, the case being modeled is something like this:
    346 ;
    347 ; int f8() {
    348 ;   int x = 1;
    349 ;   try {
    350 ;     S a;
    351 ;     g();
    352 ;     x = 2;
    353 ; retry:
    354 ;     g();
    355 ;     return
    356 ;   } catch (...) {
    357 ;     use_x(x);
    358 ;   }
    359 ;   goto retry;
    360 ; }
    361 ;
    362 ; While that C++ syntax isn't legal, the IR below is.
    363 ;
    364 ; In this case, the PHI node that is sunk from ehcleanup to catch.dispatch
    365 ; should have an incoming value entry for path from 'foo' that references the
    366 ; PHI node itself.
    367 ;
    368 ; CHECK-LABEL: define void @f8()
    369 ; CHECK: entry:
    370 ; CHECK:   invoke void @g()
    371 ; CHECK: invoke.cont:
    372 ; CHECK:   invoke void @g()
    373 ; CHECK-NOT: ehcleanup:
    374 ; CHECK-NOT:   cleanuppad
    375 ; CHECK: catch.dispatch:
    376 ; CHECK:   %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ], [ %x, %catch.cont ] 
    377 ; CHECK: }
    378 define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
    379 entry:
    380   invoke void @g()
    381           to label %invoke.cont unwind label %ehcleanup
    382 
    383 invoke.cont:                                      ; preds = %entry
    384   invoke void @g()
    385           to label %return unwind label %ehcleanup
    386 
    387 ehcleanup:                                        ; preds = %invoke.cont, %entry
    388   %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
    389   %0 = cleanuppad within none []
    390   cleanupret from %0 unwind label %catch.dispatch
    391 
    392 catch.dispatch:                                   ; preds = %ehcleanup, %catch.cont
    393   %cs1 = catchswitch within none [label %catch] unwind to caller
    394 
    395 catch:                                            ; preds = %catch.dispatch
    396   %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
    397   call void @use_x(i32 %x)
    398   catchret from %1 to label %catch.cont
    399 
    400 catch.cont:                                       ; preds = %catch
    401   invoke void @g()
    402           to label %return unwind label %catch.dispatch
    403 
    404 return:                                           ; preds = %invoke.cont, %catch.cont
    405   ret void
    406 }
    407 
    408 %struct.S = type { i8 }
    409 %struct.S2 = type { i8 }
    410 declare void @"\01??1S2@@QEAA@XZ"(%struct.S2*)
    411 declare void @g()
    412 declare void @use_x(i32 %x)
    413 
    414 declare i32 @__CxxFrameHandler3(...)
    415 
    416