1; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s 2 3; WinEH requires funclet tokens on nounwind intrinsics if they can lower to 4; regular function calls in the course of IR transformations. 5; 6; Test that the code generator will emit the function call and not consider it 7; an "implausible instruciton". In the past this silently truncated code on 8; exception paths and caused crashes at runtime. 9; 10; Reduced IR generated from ObjC++ source: 11; 12; @class Ety; 13; void opaque(void); 14; void test_catch_with_objc_intrinsic(void) { 15; @try { 16; opaque(); 17; } @catch (Ety *ex) { 18; // Destroy ex when leaving catchpad. This would emit calls to two 19; // intrinsic functions: llvm.objc.retain and llvm.objc.storeStrong 20; } 21; } 22; 23; llvm.objc.retain and llvm.objc.storeStrong both lower into regular function 24; calls before ISel. We only need one of them to trigger funclet truncation 25; during codegen: 26 27define void @test_catch_with_objc_intrinsic() personality ptr @__CxxFrameHandler3 { 28entry: 29 %exn.slot = alloca ptr, align 8 30 %ex2 = alloca ptr, align 8 31 invoke void @opaque() to label %invoke.cont unwind label %catch.dispatch 32 33catch.dispatch: ; preds = %entry 34 %0 = catchswitch within none [label %catch] unwind to caller 35 36invoke.cont: ; preds = %entry 37 unreachable 38 39catch: ; preds = %catch.dispatch 40 %1 = catchpad within %0 [ptr null, i32 64, ptr %exn.slot] 41 %exn = load ptr, ptr %exn.slot, align 8 42 %2 = call ptr @llvm.objc.retain(ptr %exn) [ "funclet"(token %1) ] 43 store ptr %2, ptr %ex2, align 8 44 catchret from %1 to label %catchret.dest 45 46catchret.dest: ; preds = %catch 47 ret void 48} 49 50declare void @opaque() 51declare ptr @llvm.objc.retain(ptr) #0 52declare i32 @__CxxFrameHandler3(...) 53 54attributes #0 = { nounwind } 55 56; EH catchpad with SEH prologue: 57; CHECK-LABEL: # %catch 58; CHECK: pushq %rbp 59; CHECK: .seh_pushreg %rbp 60; ... 61; CHECK: .seh_endprologue 62; 63; At this point the code used to be truncated (and sometimes terminated with an 64; int3 opcode): 65; CHECK-NOT: int3 66; 67; Instead, the runtime call to retain should be emitted: 68; CHECK: movq -8(%rbp), %rcx 69; CHECK: callq objc_retain 70; ... 71; 72; This is the end of the funclet: 73; CHECK: popq %rbp 74; CHECK: retq # CATCHRET 75; ... 76; CHECK: .seh_handlerdata 77; ... 78; CHECK: .seh_endproc 79