xref: /llvm-project/llvm/test/CodeGen/X86/win64-funclet-preisel-intrinsics.ll (revision 4a617c426d80776afbf0cf375abfeded9399223f)
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