; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 ; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sme2 -verify-machineinstrs < %s | FileCheck %s ; A simple EH test case that corresponds to the following C++ source: ; ; struct ZAResource { ; ~ZAResource() __arm_inout("za") { ; shared_za_call(); // simulate cleanup in destructor ; } ; }; ; ; void za_with_raii(bool fail) __arm_inout("za") { ; ZAResource r; ; if (fail) ; throw "Unwinding needs ZA state reload"; ; } ; ; Here if an exception is thrown we must call the ~ZAResource destructor while ; unwinding the stack. That requires us to restore ZA state before the ; shared_za_call in the cleanup block. @.str = private unnamed_addr constant [32 x i8] c"Unwinding needs ZA state reload\00", align 1 @typeinfo_for_char_const_ptr = external constant ptr define void @za_with_raii(i1 %fail) "aarch64_inout_za" personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: za_with_raii: ; CHECK: .Lfunc_begin0: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 ; CHECK-NEXT: .cfi_lsda 28, .Lexception0 ; CHECK-NEXT: // %bb.0: ; CHECK-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill ; CHECK-NEXT: str x19, [sp, #16] // 8-byte Spill ; CHECK-NEXT: mov x29, sp ; CHECK-NEXT: sub sp, sp, #16 ; CHECK-NEXT: .cfi_def_cfa w29, 32 ; CHECK-NEXT: .cfi_offset w19, -16 ; CHECK-NEXT: .cfi_offset w30, -24 ; CHECK-NEXT: .cfi_offset w29, -32 ; CHECK-NEXT: rdsvl x8, #1 ; CHECK-NEXT: mov x9, sp ; CHECK-NEXT: msub x9, x8, x8, x9 ; CHECK-NEXT: mov sp, x9 ; CHECK-NEXT: stp x9, x8, [x29, #-16] ; CHECK-NEXT: tbnz w0, #0, .LBB0_2 ; CHECK-NEXT: // %bb.1: // %return_normally ; CHECK-NEXT: mov sp, x29 ; CHECK-NEXT: ldr x19, [sp, #16] // 8-byte Reload ; CHECK-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload ; CHECK-NEXT: b shared_za_call ; CHECK-NEXT: .LBB0_2: // %throw_exception ; CHECK-NEXT: sub x8, x29, #16 ; CHECK-NEXT: mov w0, #8 // =0x8 ; CHECK-NEXT: msr TPIDR2_EL0, x8 ; CHECK-NEXT: bl __cxa_allocate_exception ; CHECK-NEXT: adrp x8, .L.str ; CHECK-NEXT: add x8, x8, :lo12:.L.str ; CHECK-NEXT: str x8, [x0] ; CHECK-NEXT: .Ltmp0: // EH_LABEL ; CHECK-NEXT: adrp x1, :got:typeinfo_for_char_const_ptr ; CHECK-NEXT: mov x2, xzr ; CHECK-NEXT: ldr x1, [x1, :got_lo12:typeinfo_for_char_const_ptr] ; CHECK-NEXT: bl __cxa_throw ; CHECK-NEXT: .Ltmp1: // EH_LABEL ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #16 ; CHECK-NEXT: cbnz x8, .LBB0_4 ; CHECK-NEXT: // %bb.3: // %throw_exception ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB0_4: // %throw_exception ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: // %bb.5: // %throw_fail ; CHECK-NEXT: .LBB0_6: // %unwind_dtors ; CHECK-NEXT: .Ltmp2: // EH_LABEL ; CHECK-NEXT: mov x19, x0 ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #16 ; CHECK-NEXT: cbnz x8, .LBB0_8 ; CHECK-NEXT: // %bb.7: // %unwind_dtors ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB0_8: // %unwind_dtors ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: bl shared_za_call ; CHECK-NEXT: sub x8, x29, #16 ; CHECK-NEXT: mov x0, x19 ; CHECK-NEXT: msr TPIDR2_EL0, x8 ; CHECK-NEXT: bl _Unwind_Resume br i1 %fail, label %throw_exception, label %return_normally throw_exception: %exception_ptr = tail call ptr @__cxa_allocate_exception(i64 8) #3 store ptr @.str, ptr %exception_ptr, align 16 invoke void @__cxa_throw(ptr nonnull %exception_ptr, ptr nonnull @typeinfo_for_char_const_ptr, ptr null) to label %throw_fail unwind label %unwind_dtors unwind_dtors: %5 = landingpad { ptr, i32 } cleanup tail call void @shared_za_call() resume { ptr, i32 } %5 return_normally: tail call void @shared_za_call() ret void throw_fail: unreachable } ; Another simple exception handling example. Here we need to restore ZA in two ; places. After the may_throw() call to handle the case it does not throw, and ; within the catch block for the shared_za_call(). We also need to setup the ; lazy save around C++ exception ABI routines (to handle the _very_ unlikely ; case they use ZA state). ; ; void za_try_catch() __arm_inout("za") { ; try { ; may_throw(); ; } catch (...) { ; shared_za_call(); ; } ; shared_za_call(); ; } define void @try_catch() "aarch64_inout_za" personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: try_catch: ; CHECK: .Lfunc_begin1: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 ; CHECK-NEXT: .cfi_lsda 28, .Lexception1 ; CHECK-NEXT: // %bb.0: ; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill ; CHECK-NEXT: mov x29, sp ; CHECK-NEXT: sub sp, sp, #16 ; CHECK-NEXT: .cfi_def_cfa w29, 16 ; CHECK-NEXT: .cfi_offset w30, -8 ; CHECK-NEXT: .cfi_offset w29, -16 ; CHECK-NEXT: rdsvl x8, #1 ; CHECK-NEXT: mov x9, sp ; CHECK-NEXT: msub x9, x8, x8, x9 ; CHECK-NEXT: mov sp, x9 ; CHECK-NEXT: stp x9, x8, [x29, #-16] ; CHECK-NEXT: .Ltmp3: // EH_LABEL ; CHECK-NEXT: sub x8, x29, #16 ; CHECK-NEXT: msr TPIDR2_EL0, x8 ; CHECK-NEXT: bl may_throw ; CHECK-NEXT: .Ltmp4: // EH_LABEL ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #16 ; CHECK-NEXT: cbnz x8, .LBB1_2 ; CHECK-NEXT: // %bb.1: ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB1_2: ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: .LBB1_3: // %after_catch ; CHECK-NEXT: mov sp, x29 ; CHECK-NEXT: ldp x29, x30, [sp], #16 // 16-byte Folded Reload ; CHECK-NEXT: b shared_za_call ; CHECK-NEXT: .LBB1_4: // %catch ; CHECK-NEXT: .Ltmp5: // EH_LABEL ; CHECK-NEXT: bl __cxa_begin_catch ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #16 ; CHECK-NEXT: cbnz x8, .LBB1_6 ; CHECK-NEXT: // %bb.5: // %catch ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB1_6: // %catch ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: bl shared_za_call ; CHECK-NEXT: sub x8, x29, #16 ; CHECK-NEXT: msr TPIDR2_EL0, x8 ; CHECK-NEXT: bl __cxa_end_catch ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #16 ; CHECK-NEXT: cbnz x8, .LBB1_8 ; CHECK-NEXT: // %bb.7: // %catch ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB1_8: // %catch ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: b .LBB1_3 invoke void @may_throw() to label %after_catch unwind label %catch catch: ; preds = %0 %eh_info = landingpad { ptr, i32 } catch ptr null %exception_ptr = extractvalue { ptr, i32 } %eh_info, 0 tail call ptr @__cxa_begin_catch(ptr %exception_ptr) tail call void @shared_za_call() tail call void @__cxa_end_catch() br label %after_catch after_catch: tail call void @shared_za_call() ret void } ; This example corresponds to: ; ; __arm_new("za") void try_catch_shared_za_callee() ; { ; try { ; shared_za_call(); ; } catch(...) { ; noexcept_shared_za_call(); ; } ; } ; ; In this example we don't setup a lazy save before shared_za_call(), however, ; we still enter the catch block in a ZA off state. This leads to us emitting a ; restore of a uninitialized save buffer in the catch block. This is not ideal ; but is valid in the SME ABI. Ideally, we would omit the save buffer and ; restore and simply set ZA to "on" in the catch block. define void @try_catch_shared_za_callee() "aarch64_new_za" personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: try_catch_shared_za_callee: ; CHECK: .Lfunc_begin2: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 ; CHECK-NEXT: .cfi_lsda 28, .Lexception2 ; CHECK-NEXT: // %bb.0: ; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill ; CHECK-NEXT: mov x29, sp ; CHECK-NEXT: sub sp, sp, #16 ; CHECK-NEXT: .cfi_def_cfa w29, 16 ; CHECK-NEXT: .cfi_offset w30, -8 ; CHECK-NEXT: .cfi_offset w29, -16 ; CHECK-NEXT: rdsvl x8, #1 ; CHECK-NEXT: mov x9, sp ; CHECK-NEXT: msub x9, x8, x8, x9 ; CHECK-NEXT: mov sp, x9 ; CHECK-NEXT: stp x9, x8, [x29, #-16] ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: cbz x8, .LBB2_2 ; CHECK-NEXT: // %bb.1: ; CHECK-NEXT: bl __arm_tpidr2_save ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: zero {za} ; CHECK-NEXT: .LBB2_2: ; CHECK-NEXT: smstart za ; CHECK-NEXT: .Ltmp6: // EH_LABEL ; CHECK-NEXT: bl shared_za_call ; CHECK-NEXT: .Ltmp7: // EH_LABEL ; CHECK-NEXT: smstop za ; CHECK-NEXT: .LBB2_3: // %exit ; CHECK-NEXT: mov sp, x29 ; CHECK-NEXT: ldp x29, x30, [sp], #16 // 16-byte Folded Reload ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB2_4: // %catch ; CHECK-NEXT: .Ltmp8: // EH_LABEL ; CHECK-NEXT: bl __cxa_begin_catch ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #16 ; CHECK-NEXT: cbnz x8, .LBB2_6 ; CHECK-NEXT: // %bb.5: // %catch ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB2_6: // %catch ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: bl noexcept_shared_za_call ; CHECK-NEXT: sub x8, x29, #16 ; CHECK-NEXT: msr TPIDR2_EL0, x8 ; CHECK-NEXT: bl __cxa_end_catch ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: smstop za ; CHECK-NEXT: b .LBB2_3 invoke void @shared_za_call() #4 to label %exit unwind label %catch catch: %eh_info = landingpad { ptr, i32 } catch ptr null %exception_ptr = extractvalue { ptr, i32 } %eh_info, 0 tail call ptr @__cxa_begin_catch(ptr %exception_ptr) tail call void @noexcept_shared_za_call() tail call void @__cxa_end_catch() br label %exit exit: ret void } ; A simple ZT0 exception example that corresponds to: ; ; struct ZT0Resource { ; ~ZT0Resource() __arm_inout("zt0") { ; shared_zt0_call(); // simulate cleanup in destructor ; } ; }; ; ; void za_with_raii() __arm_inout("zt0") { ; ZT0Resource r; ; may_throw(); ; } ; ; This code may require reloading ZT0 in the cleanup for ~ZT0Resource(). ; define void @try_catch_shared_zt0_callee() "aarch64_inout_zt0" personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: try_catch_shared_zt0_callee: ; CHECK: .Lfunc_begin3: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 ; CHECK-NEXT: .cfi_lsda 28, .Lexception3 ; CHECK-NEXT: // %bb.0: ; CHECK-NEXT: sub sp, sp, #96 ; CHECK-NEXT: str x30, [sp, #64] // 8-byte Spill ; CHECK-NEXT: stp x20, x19, [sp, #80] // 16-byte Folded Spill ; CHECK-NEXT: .cfi_def_cfa_offset 96 ; CHECK-NEXT: .cfi_offset w19, -8 ; CHECK-NEXT: .cfi_offset w20, -16 ; CHECK-NEXT: .cfi_offset w30, -32 ; CHECK-NEXT: .Ltmp9: // EH_LABEL ; CHECK-NEXT: mov x19, sp ; CHECK-NEXT: str zt0, [x19] ; CHECK-NEXT: smstop za ; CHECK-NEXT: bl may_throw ; CHECK-NEXT: .Ltmp10: // EH_LABEL ; CHECK-NEXT: smstart za ; CHECK-NEXT: ldr zt0, [x19] ; CHECK-NEXT: // %bb.1: // %return_normally ; CHECK-NEXT: ldp x20, x19, [sp, #80] // 16-byte Folded Reload ; CHECK-NEXT: ldr x30, [sp, #64] // 8-byte Reload ; CHECK-NEXT: add sp, sp, #96 ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB3_2: // %unwind_dtors ; CHECK-NEXT: .Ltmp11: // EH_LABEL ; CHECK-NEXT: mov x20, sp ; CHECK-NEXT: mov x19, x0 ; CHECK-NEXT: smstart za ; CHECK-NEXT: ldr zt0, [x20] ; CHECK-NEXT: bl shared_zt0_call ; CHECK-NEXT: str zt0, [x20] ; CHECK-NEXT: smstop za ; CHECK-NEXT: mov x0, x19 ; CHECK-NEXT: bl _Unwind_Resume invoke void @may_throw() to label %return_normally unwind label %unwind_dtors unwind_dtors: %5 = landingpad { ptr, i32 } cleanup tail call void @shared_zt0_call() resume { ptr, i32 } %5 return_normally: ret void } ; This example corresponds to: ; ; __arm_agnostic("sme_za_state") void try_catch_agnostic_za() ; { ; try { ; may_throw(); ; } catch(...) { ; } ; } ; ; In this example we must execute __arm_sme_restore once we enter the catch block ; (before executing __arm_sme_save again, which would invalidate the prior save). define void @try_catch_agnostic_za() "aarch64_za_state_agnostic" personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: try_catch_agnostic_za: ; CHECK: .Lfunc_begin4: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 ; CHECK-NEXT: .cfi_lsda 28, .Lexception4 ; CHECK-NEXT: // %bb.0: ; CHECK-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill ; CHECK-NEXT: str x19, [sp, #16] // 8-byte Spill ; CHECK-NEXT: mov x29, sp ; CHECK-NEXT: .cfi_def_cfa w29, 32 ; CHECK-NEXT: .cfi_offset w19, -16 ; CHECK-NEXT: .cfi_offset w30, -24 ; CHECK-NEXT: .cfi_offset w29, -32 ; CHECK-NEXT: bl __arm_sme_state_size ; CHECK-NEXT: sub sp, sp, x0 ; CHECK-NEXT: mov x19, sp ; CHECK-NEXT: .Ltmp12: // EH_LABEL ; CHECK-NEXT: mov x0, x19 ; CHECK-NEXT: bl __arm_sme_save ; CHECK-NEXT: bl may_throw ; CHECK-NEXT: .Ltmp13: // EH_LABEL ; CHECK-NEXT: mov x0, x19 ; CHECK-NEXT: bl __arm_sme_restore ; CHECK-NEXT: .LBB4_1: // %exit ; CHECK-NEXT: mov sp, x29 ; CHECK-NEXT: ldr x19, [sp, #16] // 8-byte Reload ; CHECK-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB4_2: // %catch ; CHECK-NEXT: .Ltmp14: // EH_LABEL ; CHECK-NEXT: bl __cxa_begin_catch ; CHECK-NEXT: bl __cxa_end_catch ; CHECK-NEXT: mov x0, x19 ; CHECK-NEXT: bl __arm_sme_restore ; CHECK-NEXT: b .LBB4_1 invoke void @may_throw() to label %exit unwind label %catch catch: %eh_info = landingpad { ptr, i32 } catch ptr null %exception_ptr = extractvalue { ptr, i32 } %eh_info, 0 tail call ptr @__cxa_begin_catch(ptr %exception_ptr) tail call void @__cxa_end_catch() br label %exit exit: ret void } ; This example corresponds to: ; ; __arm_agnostic("sme_za_state") void try_catch_agnostic_za_invoke() ; { ; try { ; agnostic_za_call(); ; } catch(...) { ; } ; } ; ; In this example we preserve all SME state enabled by PSTATE.ZA using ; `__arm_sme_save` before agnostic_za_call(). This is because on all normal ; returns from an agnostic ZA function ZA state should be preserved. That means ; we need to make sure ZA state is saved in case agnostic_za_call() throws, and ; we need to restore ZA state after unwinding to the catch block. define void @try_catch_agnostic_za_invoke() "aarch64_za_state_agnostic" personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: try_catch_agnostic_za_invoke: ; CHECK: .Lfunc_begin5: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 ; CHECK-NEXT: .cfi_lsda 28, .Lexception5 ; CHECK-NEXT: // %bb.0: // %entry ; CHECK-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill ; CHECK-NEXT: str x19, [sp, #16] // 8-byte Spill ; CHECK-NEXT: mov x29, sp ; CHECK-NEXT: .cfi_def_cfa w29, 32 ; CHECK-NEXT: .cfi_offset w19, -16 ; CHECK-NEXT: .cfi_offset w30, -24 ; CHECK-NEXT: .cfi_offset w29, -32 ; CHECK-NEXT: bl __arm_sme_state_size ; CHECK-NEXT: sub sp, sp, x0 ; CHECK-NEXT: mov x19, sp ; CHECK-NEXT: .Ltmp15: // EH_LABEL ; CHECK-NEXT: mov x0, x19 ; CHECK-NEXT: bl __arm_sme_save ; CHECK-NEXT: bl agnostic_za_call ; CHECK-NEXT: .Ltmp16: // EH_LABEL ; CHECK-NEXT: mov x0, x19 ; CHECK-NEXT: bl __arm_sme_restore ; CHECK-NEXT: .LBB5_1: // %exit ; CHECK-NEXT: mov sp, x29 ; CHECK-NEXT: ldr x19, [sp, #16] // 8-byte Reload ; CHECK-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB5_2: // %catch ; CHECK-NEXT: .Ltmp17: // EH_LABEL ; CHECK-NEXT: bl __cxa_begin_catch ; CHECK-NEXT: bl __cxa_end_catch ; CHECK-NEXT: mov x0, x19 ; CHECK-NEXT: bl __arm_sme_restore ; CHECK-NEXT: b .LBB5_1 entry: invoke void @agnostic_za_call() "aarch64_za_state_agnostic" to label %exit unwind label %catch catch: %eh_info = landingpad { ptr, i32 } catch ptr null %exception_ptr = extractvalue { ptr, i32 } %eh_info, 0 tail call ptr @__cxa_begin_catch(ptr %exception_ptr) tail call void @__cxa_end_catch() br label %exit exit: ret void } ; This is the same `try_catch_agnostic_za_invoke`, but shows a lazy save would ; also need to be committed in a shared-ZA function calling an agnostic-ZA function. define void @try_catch_inout_za_agnostic_za_callee() "aarch64_inout_za" personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: try_catch_inout_za_agnostic_za_callee: ; CHECK: .Lfunc_begin6: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 ; CHECK-NEXT: .cfi_lsda 28, .Lexception6 ; CHECK-NEXT: // %bb.0: // %entry ; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill ; CHECK-NEXT: mov x29, sp ; CHECK-NEXT: sub sp, sp, #16 ; CHECK-NEXT: .cfi_def_cfa w29, 16 ; CHECK-NEXT: .cfi_offset w30, -8 ; CHECK-NEXT: .cfi_offset w29, -16 ; CHECK-NEXT: rdsvl x8, #1 ; CHECK-NEXT: mov x9, sp ; CHECK-NEXT: msub x9, x8, x8, x9 ; CHECK-NEXT: mov sp, x9 ; CHECK-NEXT: stp x9, x8, [x29, #-16] ; CHECK-NEXT: .Ltmp18: // EH_LABEL ; CHECK-NEXT: sub x8, x29, #16 ; CHECK-NEXT: msr TPIDR2_EL0, x8 ; CHECK-NEXT: bl agnostic_za_call ; CHECK-NEXT: .Ltmp19: // EH_LABEL ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #16 ; CHECK-NEXT: cbnz x8, .LBB6_2 ; CHECK-NEXT: // %bb.1: // %entry ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB6_2: // %entry ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: .LBB6_3: // %exit ; CHECK-NEXT: mov sp, x29 ; CHECK-NEXT: ldp x29, x30, [sp], #16 // 16-byte Folded Reload ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB6_4: // %catch ; CHECK-NEXT: .Ltmp20: // EH_LABEL ; CHECK-NEXT: bl __cxa_begin_catch ; CHECK-NEXT: bl __cxa_end_catch ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #16 ; CHECK-NEXT: cbnz x8, .LBB6_6 ; CHECK-NEXT: // %bb.5: // %catch ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB6_6: // %catch ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: b .LBB6_3 entry: invoke void @agnostic_za_call() to label %exit unwind label %catch catch: %eh_info = landingpad { ptr, i32 } catch ptr null %exception_ptr = extractvalue { ptr, i32 } %eh_info, 0 tail call ptr @__cxa_begin_catch(ptr %exception_ptr) tail call void @__cxa_end_catch() br label %exit exit: ret void } define void @try_catch_inout_zt0() "aarch64_inout_zt0" personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: try_catch_inout_zt0: ; CHECK: .Lfunc_begin7: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 ; CHECK-NEXT: .cfi_lsda 28, .Lexception7 ; CHECK-NEXT: // %bb.0: // %entry ; CHECK-NEXT: sub sp, sp, #80 ; CHECK-NEXT: stp x30, x19, [sp, #64] // 16-byte Folded Spill ; CHECK-NEXT: .cfi_def_cfa_offset 80 ; CHECK-NEXT: .cfi_offset w19, -8 ; CHECK-NEXT: .cfi_offset w30, -16 ; CHECK-NEXT: .Ltmp21: // EH_LABEL ; CHECK-NEXT: mov x19, sp ; CHECK-NEXT: str zt0, [x19] ; CHECK-NEXT: smstop za ; CHECK-NEXT: bl may_throw ; CHECK-NEXT: .Ltmp22: // EH_LABEL ; CHECK-NEXT: smstart za ; CHECK-NEXT: ldr zt0, [x19] ; CHECK-NEXT: .LBB7_1: // %exit ; CHECK-NEXT: ldp x30, x19, [sp, #64] // 16-byte Folded Reload ; CHECK-NEXT: add sp, sp, #80 ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB7_2: // %catch ; CHECK-NEXT: .Ltmp23: // EH_LABEL ; CHECK-NEXT: bl __cxa_begin_catch ; CHECK-NEXT: bl __cxa_end_catch ; CHECK-NEXT: smstart za ; CHECK-NEXT: ldr zt0, [x19] ; CHECK-NEXT: b .LBB7_1 entry: invoke void @may_throw() to label %exit unwind label %catch catch: %eh_info = landingpad { ptr, i32 } catch ptr null %exception_ptr = extractvalue { ptr, i32 } %eh_info, 0 tail call ptr @__cxa_begin_catch(ptr %exception_ptr) tail call void @__cxa_end_catch() br label %exit exit: ret void } define void @try_catch_shared_za_callee_zt0_saved(ptr %callee) "aarch64_inout_za" "aarch64_in_zt0" personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: try_catch_shared_za_callee_zt0_saved: ; CHECK: .Lfunc_begin8: ; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 ; CHECK-NEXT: .cfi_lsda 28, .Lexception8 ; CHECK-NEXT: // %bb.0: ; CHECK-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill ; CHECK-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill ; CHECK-NEXT: mov x29, sp ; CHECK-NEXT: sub sp, sp, #80 ; CHECK-NEXT: .cfi_def_cfa w29, 32 ; CHECK-NEXT: .cfi_offset w19, -8 ; CHECK-NEXT: .cfi_offset w20, -16 ; CHECK-NEXT: .cfi_offset w30, -24 ; CHECK-NEXT: .cfi_offset w29, -32 ; CHECK-NEXT: rdsvl x8, #1 ; CHECK-NEXT: mov x9, sp ; CHECK-NEXT: msub x9, x8, x8, x9 ; CHECK-NEXT: mov sp, x9 ; CHECK-NEXT: mov x19, x0 ; CHECK-NEXT: stp x9, x8, [x29, #-80] ; CHECK-NEXT: .Ltmp24: // EH_LABEL ; CHECK-NEXT: sub x20, x29, #64 ; CHECK-NEXT: sub x8, x29, #80 ; CHECK-NEXT: str zt0, [x20] ; CHECK-NEXT: msr TPIDR2_EL0, x8 ; CHECK-NEXT: bl may_throw ; CHECK-NEXT: .Ltmp25: // EH_LABEL ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #80 ; CHECK-NEXT: cbnz x8, .LBB8_2 ; CHECK-NEXT: // %bb.1: ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB8_2: ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: ldr zt0, [x20] ; CHECK-NEXT: // %bb.3: // %return_normally ; CHECK-NEXT: mov sp, x29 ; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload ; CHECK-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB8_4: // %unwind_dtors ; CHECK-NEXT: .Ltmp26: // EH_LABEL ; CHECK-NEXT: mov x20, x0 ; CHECK-NEXT: smstart za ; CHECK-NEXT: mrs x8, TPIDR2_EL0 ; CHECK-NEXT: sub x0, x29, #80 ; CHECK-NEXT: cbnz x8, .LBB8_6 ; CHECK-NEXT: // %bb.5: // %unwind_dtors ; CHECK-NEXT: bl __arm_tpidr2_restore ; CHECK-NEXT: .LBB8_6: // %unwind_dtors ; CHECK-NEXT: msr TPIDR2_EL0, xzr ; CHECK-NEXT: blr x19 ; CHECK-NEXT: sub x8, x29, #80 ; CHECK-NEXT: mov x0, x20 ; CHECK-NEXT: msr TPIDR2_EL0, x8 ; CHECK-NEXT: bl _Unwind_Resume invoke void @may_throw() to label %return_normally unwind label %unwind_dtors unwind_dtors: %5 = landingpad { ptr, i32 } cleanup call void %callee() "aarch64_inout_za" resume { ptr, i32 } %5 return_normally: ret void } declare ptr @__cxa_allocate_exception(i64) declare void @__cxa_throw(ptr, ptr, ptr) declare ptr @__cxa_begin_catch(ptr) declare void @__cxa_end_catch() declare i32 @__gxx_personality_v0(...) declare void @may_throw() declare void @shared_za_call() "aarch64_inout_za" declare void @noexcept_shared_za_call() "aarch64_inout_za" declare void @shared_zt0_call() "aarch64_inout_zt0" declare void @agnostic_za_call() "aarch64_za_state_agnostic"