1; RUN: opt < %s -simplifycfg -S | FileCheck %s 2 3; ModuleID = 'cppeh-simplify.cpp' 4target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" 5target 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; 26define void @f1() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { 27entry: 28 invoke void @g() to label %invoke.cont unwind label %ehcleanup 29 30invoke.cont: ; preds = %entry 31 ret void 32 33ehcleanup: ; preds = %entry 34 %0 = cleanuppad within none [] 35 cleanupret from %0 unwind label %ehcleanup.1 36 37ehcleanup.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; 74define void @f2() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { 75entry: 76 %b = alloca %struct.S2, align 1 77 invoke void @g() to label %invoke.cont unwind label %ehcleanup 78 79invoke.cont: ; preds = %entry 80 br label %try.cont 81 82ehcleanup: ; 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 87catch.dispatch: ; preds = %ehcleanup 88 %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1 89 90catch: ; preds = %catch.dispatch 91 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] 92 catchret from %1 to label %catchret.dest 93 94catchret.dest: ; preds = %catch 95 br label %try.cont 96 97try.cont: ; preds = %catchret.dest, %invoke.cont 98 ret void 99 100ehcleanup.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; 136define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { 137entry: 138 %a = alloca %struct.S2, align 1 139 invoke void @g() to label %invoke.cont unwind label %ehcleanup 140 141invoke.cont: ; preds = %entry 142 br label %try.cont 143 144ehcleanup: ; preds = %entry 145 %0 = cleanuppad within none [] 146 cleanupret from %0 unwind label %catch.dispatch 147 148catch.dispatch: ; preds = %ehcleanup 149 %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1 150 151catch: ; preds = %catch.dispatch 152 %cp2 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] 153 catchret from %cp2 to label %catchret.dest 154 155catchret.dest: ; preds = %catch 156 br label %try.cont 157 158try.cont: ; preds = %catchret.dest, %invoke.cont 159 ret void 160 161ehcleanup.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; 198define void @f4() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { 199entry: 200 invoke void @g() 201 to label %invoke.cont unwind label %ehcleanup 202 203invoke.cont: ; preds = %entry 204 invoke void @g() 205 to label %try.cont unwind label %catch.dispatch 206 207catch.dispatch: ; preds = %invoke.cont 208 %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup 209 210catch: ; preds = %catch.dispatch 211 %0 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] 212 catchret from %0 to label %try.cont 213 214try.cont: ; preds = %catch, %invoke.cont 215 ret void 216 217ehcleanup: 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: } 251define i32 @f6() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { 252entry: 253 invoke void @g() 254 to label %invoke.cont unwind label %ehcleanup 255 256invoke.cont: ; preds = %entry 257 invoke void @g() 258 to label %return unwind label %ehcleanup 259 260ehcleanup: ; 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 265catch.dispatch: ; preds = %ehcleanup 266 %cs1 = catchswitch within none [label %catch] unwind to caller 267 268catch: ; preds = %catch.dispatch 269 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] 270 catchret from %1 to label %return 271 272return: ; 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: } 310define i32 @f7() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { 311entry: 312 invoke void @g() 313 to label %invoke.cont unwind label %catch.dispatch 314 315invoke.cont: ; preds = %entry 316 invoke void @g() 317 to label %invoke.cont.1 unwind label %ehcleanup 318 319invoke.cont.1: ; preds = %invoke.cont 320 invoke void @g() 321 to label %return unwind label %ehcleanup 322 323ehcleanup: ; 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 328catch.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 332catch: ; preds = %catch.dispatch 333 %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] 334 catchret from %1 to label %return 335 336return: ; 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: } 378define void @f8() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { 379entry: 380 invoke void @g() 381 to label %invoke.cont unwind label %ehcleanup 382 383invoke.cont: ; preds = %entry 384 invoke void @g() 385 to label %return unwind label %ehcleanup 386 387ehcleanup: ; 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 392catch.dispatch: ; preds = %ehcleanup, %catch.cont 393 %cs1 = catchswitch within none [label %catch] unwind to caller 394 395catch: ; 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 400catch.cont: ; preds = %catch 401 invoke void @g() 402 to label %return unwind label %catch.dispatch 403 404return: ; preds = %invoke.cont, %catch.cont 405 ret void 406} 407; CHECK-LABEL: define i32 @f9() 408; CHECK: entry: 409; CHECK: invoke void @"\01??1S2@@QEAA@XZ"( 410; CHECK-NOT: cleanuppad 411; CHECK: catch.dispatch: 412; CHECK: } 413define i32 @f9() personality i32 (...)* @__CxxFrameHandler3 { 414entry: 415 %s = alloca i8, align 1 416 call void @llvm.lifetime.start(i64 1, i8* nonnull %s) 417 %bc = bitcast i8* %s to %struct.S2* 418 invoke void @"\01??1S2@@QEAA@XZ"(%struct.S2* %bc) 419 to label %try.cont unwind label %ehcleanup 420 421ehcleanup: 422 %cleanup.pad = cleanuppad within none [] 423 call void @llvm.lifetime.end(i64 1, i8* nonnull %s) 424 cleanupret from %cleanup.pad unwind label %catch.dispatch 425 426catch.dispatch: 427 %catch.switch = catchswitch within none [label %catch] unwind to caller 428 429catch: 430 %catch.pad = catchpad within %catch.switch [i8* null, i32 0, i8* null] 431 catchret from %catch.pad to label %try.cont 432 433try.cont: 434 ret i32 0 435} 436 437; CHECK-LABEL: define void @f10( 438define void @f10(i32 %V) personality i32 (...)* @__CxxFrameHandler3 { 439entry: 440 invoke void @g() 441 to label %unreachable unwind label %cleanup 442; CHECK: call void @g() 443; CHECK-NEXT: unreachable 444 445unreachable: 446 unreachable 447 448cleanup: 449 %cp = cleanuppad within none [] 450 switch i32 %V, label %cleanupret1 [ 451 i32 0, label %cleanupret2 452 ] 453 454cleanupret1: 455 cleanupret from %cp unwind to caller 456 457cleanupret2: 458 cleanupret from %cp unwind to caller 459} 460 461%struct.S = type { i8 } 462%struct.S2 = type { i8 } 463declare void @"\01??1S2@@QEAA@XZ"(%struct.S2*) 464declare void @g() 465declare void @use_x(i32 %x) 466 467declare i32 @__CxxFrameHandler3(...) 468 469declare void @llvm.lifetime.start(i64, i8* nocapture) 470declare void @llvm.lifetime.end(i64, i8* nocapture) 471