| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sme2 -aarch64-new-sme-abi -verify-machineinstrs < %s | FileCheck %s |
| ; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sme2 -verify-machineinstrs < %s | FileCheck %s --check-prefix=CHECK-SDAG |
| |
| ; 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 Folded 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 Folded 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 |
| ; |
| ; CHECK-SDAG-LABEL: za_with_raii: |
| ; CHECK-SDAG: .Lfunc_begin0: |
| ; CHECK-SDAG-NEXT: .cfi_startproc |
| ; CHECK-SDAG-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 |
| ; CHECK-SDAG-NEXT: .cfi_lsda 28, .Lexception0 |
| ; CHECK-SDAG-NEXT: // %bb.0: |
| ; CHECK-SDAG-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill |
| ; CHECK-SDAG-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill |
| ; CHECK-SDAG-NEXT: mov x29, sp |
| ; CHECK-SDAG-NEXT: sub sp, sp, #16 |
| ; CHECK-SDAG-NEXT: .cfi_def_cfa w29, 32 |
| ; CHECK-SDAG-NEXT: .cfi_offset w19, -8 |
| ; CHECK-SDAG-NEXT: .cfi_offset w20, -16 |
| ; CHECK-SDAG-NEXT: .cfi_offset w30, -24 |
| ; CHECK-SDAG-NEXT: .cfi_offset w29, -32 |
| ; CHECK-SDAG-NEXT: rdsvl x8, #1 |
| ; CHECK-SDAG-NEXT: mov x9, sp |
| ; CHECK-SDAG-NEXT: msub x9, x8, x8, x9 |
| ; CHECK-SDAG-NEXT: mov sp, x9 |
| ; CHECK-SDAG-NEXT: stp x9, x8, [x29, #-16] |
| ; CHECK-SDAG-NEXT: tbnz w0, #0, .LBB0_2 |
| ; CHECK-SDAG-NEXT: // %bb.1: // %return_normally |
| ; CHECK-SDAG-NEXT: mov sp, x29 |
| ; CHECK-SDAG-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload |
| ; CHECK-SDAG-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload |
| ; CHECK-SDAG-NEXT: b shared_za_call |
| ; CHECK-SDAG-NEXT: .LBB0_2: // %throw_exception |
| ; CHECK-SDAG-NEXT: sub x20, x29, #16 |
| ; CHECK-SDAG-NEXT: mov w0, #8 // =0x8 |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, x20 |
| ; CHECK-SDAG-NEXT: bl __cxa_allocate_exception |
| ; CHECK-SDAG-NEXT: mov x8, x0 |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x9, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x9, .LBB0_4 |
| ; CHECK-SDAG-NEXT: // %bb.3: // %throw_exception |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB0_4: // %throw_exception |
| ; CHECK-SDAG-NEXT: adrp x9, .L.str |
| ; CHECK-SDAG-NEXT: add x9, x9, :lo12:.L.str |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-NEXT: str x9, [x8] |
| ; CHECK-SDAG-NEXT: .Ltmp0: // EH_LABEL |
| ; CHECK-SDAG-NEXT: adrp x1, :got:typeinfo_for_char_const_ptr |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, x20 |
| ; CHECK-SDAG-NEXT: mov x0, x8 |
| ; CHECK-SDAG-NEXT: ldr x1, [x1, :got_lo12:typeinfo_for_char_const_ptr] |
| ; CHECK-SDAG-NEXT: mov x2, xzr |
| ; CHECK-SDAG-NEXT: bl __cxa_throw |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB0_6 |
| ; CHECK-SDAG-NEXT: // %bb.5: // %throw_exception |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB0_6: // %throw_exception |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-NEXT: .Ltmp1: // EH_LABEL |
| ; CHECK-SDAG-NEXT: // %bb.7: // %throw_fail |
| ; CHECK-SDAG-NEXT: .LBB0_8: // %unwind_dtors |
| ; CHECK-SDAG-NEXT: .Ltmp2: // EH_LABEL |
| ; CHECK-SDAG-NEXT: mov x19, x0 |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB0_10 |
| ; CHECK-SDAG-NEXT: // %bb.9: // %unwind_dtors |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB0_10: // %unwind_dtors |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-NEXT: bl shared_za_call |
| ; CHECK-SDAG-NEXT: mov x0, x19 |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, x20 |
| ; CHECK-SDAG-NEXT: bl _Unwind_Resume |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB0_12 |
| ; CHECK-SDAG-NEXT: // %bb.11: // %unwind_dtors |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB0_12: // %unwind_dtors |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| 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: .LBB1_1: // %after_catch |
| ; CHECK-NEXT: smstart za |
| ; CHECK-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-NEXT: sub x0, x29, #16 |
| ; CHECK-NEXT: cbnz x8, .LBB1_3 |
| ; CHECK-NEXT: // %bb.2: // %after_catch |
| ; CHECK-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-NEXT: .LBB1_3: // %after_catch |
| ; CHECK-NEXT: msr TPIDR2_EL0, xzr |
| ; 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: b .LBB1_1 |
| ; |
| ; CHECK-SDAG-LABEL: try_catch: |
| ; CHECK-SDAG: .Lfunc_begin1: |
| ; CHECK-SDAG-NEXT: .cfi_startproc |
| ; CHECK-SDAG-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 |
| ; CHECK-SDAG-NEXT: .cfi_lsda 28, .Lexception1 |
| ; CHECK-SDAG-NEXT: // %bb.0: |
| ; CHECK-SDAG-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill |
| ; CHECK-SDAG-NEXT: str x19, [sp, #16] // 8-byte Folded Spill |
| ; CHECK-SDAG-NEXT: mov x29, sp |
| ; CHECK-SDAG-NEXT: sub sp, sp, #16 |
| ; CHECK-SDAG-NEXT: .cfi_def_cfa w29, 32 |
| ; CHECK-SDAG-NEXT: .cfi_offset w19, -16 |
| ; CHECK-SDAG-NEXT: .cfi_offset w30, -24 |
| ; CHECK-SDAG-NEXT: .cfi_offset w29, -32 |
| ; CHECK-SDAG-NEXT: rdsvl x8, #1 |
| ; CHECK-SDAG-NEXT: mov x9, sp |
| ; CHECK-SDAG-NEXT: msub x9, x8, x8, x9 |
| ; CHECK-SDAG-NEXT: mov sp, x9 |
| ; CHECK-SDAG-NEXT: stp x9, x8, [x29, #-16] |
| ; CHECK-SDAG-NEXT: .Ltmp3: // EH_LABEL |
| ; CHECK-SDAG-NEXT: sub x19, x29, #16 |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, x19 |
| ; CHECK-SDAG-NEXT: bl may_throw |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB1_2 |
| ; CHECK-SDAG-NEXT: // %bb.1: |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB1_2: |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-NEXT: .Ltmp4: // EH_LABEL |
| ; CHECK-SDAG-NEXT: .LBB1_3: // %after_catch |
| ; CHECK-SDAG-NEXT: mov sp, x29 |
| ; CHECK-SDAG-NEXT: ldr x19, [sp, #16] // 8-byte Folded Reload |
| ; CHECK-SDAG-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload |
| ; CHECK-SDAG-NEXT: b shared_za_call |
| ; CHECK-SDAG-NEXT: .LBB1_4: // %catch |
| ; CHECK-SDAG-NEXT: .Ltmp5: // EH_LABEL |
| ; CHECK-SDAG-NEXT: mov x1, x0 |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB1_6 |
| ; CHECK-SDAG-NEXT: // %bb.5: // %catch |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB1_6: // %catch |
| ; CHECK-SDAG-NEXT: mov x0, x1 |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, x19 |
| ; CHECK-SDAG-NEXT: bl __cxa_begin_catch |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB1_8 |
| ; CHECK-SDAG-NEXT: // %bb.7: // %catch |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB1_8: // %catch |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-NEXT: bl shared_za_call |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, x19 |
| ; CHECK-SDAG-NEXT: bl __cxa_end_catch |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB1_10 |
| ; CHECK-SDAG-NEXT: // %bb.9: // %catch |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB1_10: // %catch |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-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: .LBB2_3: // %exit |
| ; CHECK-NEXT: smstop za |
| ; 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: b .LBB2_3 |
| ; |
| ; CHECK-SDAG-LABEL: try_catch_shared_za_callee: |
| ; CHECK-SDAG: .Lfunc_begin2: |
| ; CHECK-SDAG-NEXT: .cfi_startproc |
| ; CHECK-SDAG-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 |
| ; CHECK-SDAG-NEXT: .cfi_lsda 28, .Lexception2 |
| ; CHECK-SDAG-NEXT: // %bb.0: // %prelude |
| ; CHECK-SDAG-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill |
| ; CHECK-SDAG-NEXT: str x19, [sp, #16] // 8-byte Folded Spill |
| ; CHECK-SDAG-NEXT: mov x29, sp |
| ; CHECK-SDAG-NEXT: sub sp, sp, #16 |
| ; CHECK-SDAG-NEXT: .cfi_def_cfa w29, 32 |
| ; CHECK-SDAG-NEXT: .cfi_offset w19, -16 |
| ; CHECK-SDAG-NEXT: .cfi_offset w30, -24 |
| ; CHECK-SDAG-NEXT: .cfi_offset w29, -32 |
| ; CHECK-SDAG-NEXT: rdsvl x8, #1 |
| ; CHECK-SDAG-NEXT: mov x9, sp |
| ; CHECK-SDAG-NEXT: msub x9, x8, x8, x9 |
| ; CHECK-SDAG-NEXT: mov sp, x9 |
| ; CHECK-SDAG-NEXT: stp x9, x8, [x29, #-16] |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: cbz x8, .LBB2_2 |
| ; CHECK-SDAG-NEXT: // %bb.1: // %save.za |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_save |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-NEXT: .LBB2_2: |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: zero {za} |
| ; CHECK-SDAG-NEXT: .Ltmp6: // EH_LABEL |
| ; CHECK-SDAG-NEXT: bl shared_za_call |
| ; CHECK-SDAG-NEXT: .Ltmp7: // EH_LABEL |
| ; CHECK-SDAG-NEXT: .LBB2_3: // %exit |
| ; CHECK-SDAG-NEXT: smstop za |
| ; CHECK-SDAG-NEXT: mov sp, x29 |
| ; CHECK-SDAG-NEXT: ldr x19, [sp, #16] // 8-byte Folded Reload |
| ; CHECK-SDAG-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload |
| ; CHECK-SDAG-NEXT: ret |
| ; CHECK-SDAG-NEXT: .LBB2_4: // %catch |
| ; CHECK-SDAG-NEXT: .Ltmp8: // EH_LABEL |
| ; CHECK-SDAG-NEXT: mov x1, x0 |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: sub x19, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB2_6 |
| ; CHECK-SDAG-NEXT: // %bb.5: // %catch |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB2_6: // %catch |
| ; CHECK-SDAG-NEXT: mov x0, x1 |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, x19 |
| ; CHECK-SDAG-NEXT: bl __cxa_begin_catch |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB2_8 |
| ; CHECK-SDAG-NEXT: // %bb.7: // %catch |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB2_8: // %catch |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-NEXT: bl noexcept_shared_za_call |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, x19 |
| ; CHECK-SDAG-NEXT: bl __cxa_end_catch |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-SDAG-NEXT: sub x0, x29, #16 |
| ; CHECK-SDAG-NEXT: cbnz x8, .LBB2_10 |
| ; CHECK-SDAG-NEXT: // %bb.9: // %catch |
| ; CHECK-SDAG-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-SDAG-NEXT: .LBB2_10: // %catch |
| ; CHECK-SDAG-NEXT: msr TPIDR2_EL0, xzr |
| ; CHECK-SDAG-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(). |
| ; |
| ; FIXME: Codegen with `-aarch64-new-sme-abi` is broken with ZT0 (as it is not implemented). |
| 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: 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: stp x9, x8, [x29, #-80] |
| ; CHECK-NEXT: .Ltmp9: // EH_LABEL |
| ; CHECK-NEXT: sub x19, x29, #64 |
| ; CHECK-NEXT: str zt0, [x19] |
| ; CHECK-NEXT: smstop za |
| ; CHECK-NEXT: bl may_throw |
| ; CHECK-NEXT: smstart za |
| ; CHECK-NEXT: ldr zt0, [x19] |
| ; CHECK-NEXT: .Ltmp10: // EH_LABEL |
| ; CHECK-NEXT: // %bb.1: // %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: .LBB3_2: // %unwind_dtors |
| ; CHECK-NEXT: .Ltmp11: // EH_LABEL |
| ; CHECK-NEXT: sub x20, x29, #64 |
| ; CHECK-NEXT: mov x19, x0 |
| ; CHECK-NEXT: smstart za |
| ; CHECK-NEXT: mrs x8, TPIDR2_EL0 |
| ; CHECK-NEXT: sub x0, x29, #80 |
| ; CHECK-NEXT: cbnz x8, .LBB3_4 |
| ; CHECK-NEXT: // %bb.3: // %unwind_dtors |
| ; CHECK-NEXT: bl __arm_tpidr2_restore |
| ; CHECK-NEXT: .LBB3_4: // %unwind_dtors |
| ; CHECK-NEXT: msr TPIDR2_EL0, xzr |
| ; 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 |
| ; CHECK-NEXT: smstart za |
| ; CHECK-NEXT: ldr zt0, [x20] |
| ; |
| ; CHECK-SDAG-LABEL: try_catch_shared_zt0_callee: |
| ; CHECK-SDAG: .Lfunc_begin3: |
| ; CHECK-SDAG-NEXT: .cfi_startproc |
| ; CHECK-SDAG-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 |
| ; CHECK-SDAG-NEXT: .cfi_lsda 28, .Lexception3 |
| ; CHECK-SDAG-NEXT: // %bb.0: |
| ; CHECK-SDAG-NEXT: sub sp, sp, #96 |
| ; CHECK-SDAG-NEXT: str x30, [sp, #64] // 8-byte Folded Spill |
| ; CHECK-SDAG-NEXT: stp x20, x19, [sp, #80] // 16-byte Folded Spill |
| ; CHECK-SDAG-NEXT: .cfi_def_cfa_offset 96 |
| ; CHECK-SDAG-NEXT: .cfi_offset w19, -8 |
| ; CHECK-SDAG-NEXT: .cfi_offset w20, -16 |
| ; CHECK-SDAG-NEXT: .cfi_offset w30, -32 |
| ; CHECK-SDAG-NEXT: .Ltmp9: // EH_LABEL |
| ; CHECK-SDAG-NEXT: mov x19, sp |
| ; CHECK-SDAG-NEXT: str zt0, [x19] |
| ; CHECK-SDAG-NEXT: smstop za |
| ; CHECK-SDAG-NEXT: bl may_throw |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: ldr zt0, [x19] |
| ; CHECK-SDAG-NEXT: .Ltmp10: // EH_LABEL |
| ; CHECK-SDAG-NEXT: // %bb.1: // %return_normally |
| ; CHECK-SDAG-NEXT: ldp x20, x19, [sp, #80] // 16-byte Folded Reload |
| ; CHECK-SDAG-NEXT: ldr x30, [sp, #64] // 8-byte Folded Reload |
| ; CHECK-SDAG-NEXT: add sp, sp, #96 |
| ; CHECK-SDAG-NEXT: ret |
| ; CHECK-SDAG-NEXT: .LBB3_2: // %unwind_dtors |
| ; CHECK-SDAG-NEXT: .Ltmp11: // EH_LABEL |
| ; CHECK-SDAG-NEXT: mov x20, sp |
| ; CHECK-SDAG-NEXT: mov x19, x0 |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: ldr zt0, [x20] |
| ; CHECK-SDAG-NEXT: bl shared_zt0_call |
| ; CHECK-SDAG-NEXT: str zt0, [x20] |
| ; CHECK-SDAG-NEXT: smstop za |
| ; CHECK-SDAG-NEXT: mov x0, x19 |
| ; CHECK-SDAG-NEXT: bl _Unwind_Resume |
| ; CHECK-SDAG-NEXT: smstart za |
| ; CHECK-SDAG-NEXT: ldr zt0, [x20] |
| 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 Folded 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: .LBB4_1: // %exit |
| ; CHECK-NEXT: mov x0, x19 |
| ; CHECK-NEXT: bl __arm_sme_restore |
| ; CHECK-NEXT: mov sp, x29 |
| ; CHECK-NEXT: ldr x19, [sp, #16] // 8-byte Folded 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: b .LBB4_1 |
| ; |
| ; CHECK-SDAG-LABEL: try_catch_agnostic_za: |
| ; CHECK-SDAG: .Lfunc_begin4: |
| ; CHECK-SDAG-NEXT: .cfi_startproc |
| ; CHECK-SDAG-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 |
| ; CHECK-SDAG-NEXT: .cfi_lsda 28, .Lexception4 |
| ; CHECK-SDAG-NEXT: // %bb.0: |
| ; CHECK-SDAG-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill |
| ; CHECK-SDAG-NEXT: str x19, [sp, #16] // 8-byte Folded Spill |
| ; CHECK-SDAG-NEXT: mov x29, sp |
| ; CHECK-SDAG-NEXT: .cfi_def_cfa w29, 32 |
| ; CHECK-SDAG-NEXT: .cfi_offset w19, -16 |
| ; CHECK-SDAG-NEXT: .cfi_offset w30, -24 |
| ; CHECK-SDAG-NEXT: .cfi_offset w29, -32 |
| ; CHECK-SDAG-NEXT: bl __arm_sme_state_size |
| ; CHECK-SDAG-NEXT: sub sp, sp, x0 |
| ; CHECK-SDAG-NEXT: mov x19, sp |
| ; CHECK-SDAG-NEXT: .Ltmp12: // EH_LABEL |
| ; CHECK-SDAG-NEXT: mov x0, x19 |
| ; CHECK-SDAG-NEXT: bl __arm_sme_save |
| ; CHECK-SDAG-NEXT: bl may_throw |
| ; CHECK-SDAG-NEXT: mov x0, x19 |
| ; CHECK-SDAG-NEXT: bl __arm_sme_restore |
| ; CHECK-SDAG-NEXT: .Ltmp13: // EH_LABEL |
| ; CHECK-SDAG-NEXT: .LBB4_1: // %exit |
| ; CHECK-SDAG-NEXT: mov sp, x29 |
| ; CHECK-SDAG-NEXT: ldr x19, [sp, #16] // 8-byte Folded Reload |
| ; CHECK-SDAG-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload |
| ; CHECK-SDAG-NEXT: ret |
| ; CHECK-SDAG-NEXT: .LBB4_2: // %catch |
| ; CHECK-SDAG-NEXT: .Ltmp14: // EH_LABEL |
| ; CHECK-SDAG-NEXT: mov x1, x0 |
| ; CHECK-SDAG-NEXT: mov x0, x19 |
| ; CHECK-SDAG-NEXT: bl __arm_sme_restore |
| ; CHECK-SDAG-NEXT: mov x0, x19 |
| ; CHECK-SDAG-NEXT: bl __arm_sme_save |
| ; CHECK-SDAG-NEXT: mov x0, x1 |
| ; CHECK-SDAG-NEXT: bl __cxa_begin_catch |
| ; CHECK-SDAG-NEXT: mov x0, x19 |
| ; CHECK-SDAG-NEXT: bl __arm_sme_restore |
| ; CHECK-SDAG-NEXT: mov x0, x19 |
| ; CHECK-SDAG-NEXT: bl __arm_sme_save |
| ; CHECK-SDAG-NEXT: bl __cxa_end_catch |
| ; CHECK-SDAG-NEXT: mov x0, x19 |
| ; CHECK-SDAG-NEXT: bl __arm_sme_restore |
| ; CHECK-SDAG-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 |
| } |
| |
| 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" |