| ; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: llc -mtriple=aarch64 -aarch64-streaming-hazard-size=0 -mattr=+sme,+sve -stop-before=finalize-isel -verify-machineinstrs < %s | FileCheck %s |
| |
| target triple = "aarch64-unknown-linux-gnu" |
| |
| declare void @"StreamingCleanup::~StreamingCleanup"(ptr %this) nounwind "aarch64_pstate_sm_enabled" |
| declare void @"StreamingCompatCleanup::~StreamingCompatCleanup"(ptr %this) nounwind "aarch64_pstate_sm_compatible" |
| |
| declare void @may_throw() "aarch64_pstate_sm_compatible" |
| |
| ; This test models the kind of IR clang would emit for the following C++: |
| ; |
| ; struct StreamingCleanup { |
| ; ~StreamingCleanup() __arm_streaming |
| ; }; |
| ; |
| ; void may_throw() __arm_streaming_compatible; |
| ; |
| ; void streaming_with_cleanup() __arm_streaming { |
| ; StreamingCleanup cleanup; |
| ; may_throw(); |
| ; } |
| ; |
| ; This is a streaming function and all callees of this function are streaming[-compatible] |
| ; functions (including the StreamingCleanup destructor). This means call lowering will not |
| ; insert any streaming mode switches. However, if "may_throw" throws an exception, the |
| ; unwinder can re-enter this function (in %unwind_cleanup) to run the "StreamingCleanup" |
| ; destructor. The unwinder will always re-enter functions with streaming-mode disabled, so |
| ; we must ensure streaming-mode is enabled on entry to exception handlers. |
| define void @streaming_with_cleanup() "aarch64_pstate_sm_enabled" personality ptr @__gxx_personality_v0 { |
| ; CHECK-LABEL: name: streaming_with_cleanup |
| ; CHECK: bb.0 (%ir-block.0): |
| ; CHECK-NEXT: successors: %bb.1(0x7ffff800), %bb.2(0x00000800) |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: EH_LABEL <mcsymbol > |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: BL @may_throw, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: EH_LABEL <mcsymbol > |
| ; CHECK-NEXT: B %bb.1 |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: bb.1.normal_return: |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: [[ADDXri:%[0-9]+]]:gpr64sp = ADDXri %stack.0.cleanup, 0, 0 |
| ; CHECK-NEXT: $x0 = COPY [[ADDXri]] |
| ; CHECK-NEXT: BL @"StreamingCleanup::~StreamingCleanup", csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: RET_ReallyLR |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: bb.2.unwind_cleanup (landing-pad): |
| ; CHECK-NEXT: liveins: $x0, $x1 |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: EH_LABEL <mcsymbol > |
| ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64all = COPY killed $x1 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64all = COPY killed $x0 |
| ; CHECK-NEXT: MSRpstatesvcrImm1 1, 1, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: [[ADDXri1:%[0-9]+]]:gpr64sp = ADDXri %stack.0.cleanup, 0, 0 |
| ; CHECK-NEXT: $x0 = COPY [[ADDXri1]] |
| ; CHECK-NEXT: BL @"StreamingCleanup::~StreamingCleanup", csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: MSRpstatesvcrImm1 1, 0, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit-def $sp, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| ; CHECK-NEXT: $x0 = COPY [[COPY1]] |
| ; CHECK-NEXT: BL @_Unwind_Resume, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: MSRpstatesvcrImm1 1, 1, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| %cleanup = alloca i8, align 1 |
| invoke void @may_throw() |
| to label %normal_return unwind label %unwind_cleanup |
| |
| normal_return: |
| call void @"StreamingCleanup::~StreamingCleanup"(ptr %cleanup) |
| ret void |
| |
| unwind_cleanup: |
| %eh_info = landingpad { ptr, i32 } |
| cleanup |
| call void @"StreamingCleanup::~StreamingCleanup"(ptr %cleanup) |
| resume { ptr, i32 } %eh_info |
| } |
| |
| ; This test is the same as "streaming_with_cleanup", but now the function and destructor |
| ; are streaming-compatible functions. In this case, when we enter the exception handler, |
| ; we must switch to streaming-mode "streaming_compatible_with_cleanup" was entered with |
| ; during normal execution (i.e., EntryPStateSM). |
| define void @streaming_compatible_with_cleanup() "aarch64_pstate_sm_compatible" personality ptr @__gxx_personality_v0 { |
| ; CHECK-LABEL: name: streaming_compatible_with_cleanup |
| ; CHECK: bb.0 (%ir-block.0): |
| ; CHECK-NEXT: successors: %bb.1(0x7ffff800), %bb.2(0x00000800) |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: [[EntryPStateSM:%[0-9]+]]:gpr64 = EntryPStateSM |
| ; CHECK-NEXT: EH_LABEL <mcsymbol > |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: BL @may_throw, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: EH_LABEL <mcsymbol > |
| ; CHECK-NEXT: B %bb.1 |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: bb.1.normal_return: |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: [[ADDXri:%[0-9]+]]:gpr64sp = ADDXri %stack.0.cleanup, 0, 0 |
| ; CHECK-NEXT: $x0 = COPY [[ADDXri]] |
| ; CHECK-NEXT: BL @"StreamingCompatCleanup::~StreamingCompatCleanup", csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: RET_ReallyLR |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: bb.2.unwind_cleanup (landing-pad): |
| ; CHECK-NEXT: liveins: $x0, $x1 |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: EH_LABEL <mcsymbol > |
| ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64all = COPY killed $x1 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64all = COPY killed $x0 |
| ; CHECK-NEXT: MSRpstatePseudo 1, 1, 1, [[EntryPStateSM]], csr_aarch64_smstartstop, implicit-def dead $vg, implicit $vg, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: [[ADDXri1:%[0-9]+]]:gpr64sp = ADDXri %stack.0.cleanup, 0, 0 |
| ; CHECK-NEXT: $x0 = COPY [[ADDXri1]] |
| ; CHECK-NEXT: BL @"StreamingCompatCleanup::~StreamingCompatCleanup", csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: MSRpstatePseudo 1, 0, 1, [[EntryPStateSM]], csr_aarch64_smstartstop, implicit-def $vg, implicit $vg, implicit-def $sp, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| ; CHECK-NEXT: $x0 = COPY [[COPY1]] |
| ; CHECK-NEXT: BL @_Unwind_Resume, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp, implicit-def $vg |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: MSRpstatePseudo 1, 1, 1, [[EntryPStateSM]], csr_aarch64_smstartstop, implicit-def dead $vg, implicit $vg, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| %cleanup = alloca i8, align 1 |
| invoke void @may_throw() |
| to label %normal_return unwind label %unwind_cleanup |
| |
| normal_return: |
| call void @"StreamingCompatCleanup::~StreamingCompatCleanup"(ptr %cleanup) |
| ret void |
| |
| unwind_cleanup: |
| %eh_info = landingpad { ptr, i32 } |
| cleanup |
| call void @"StreamingCompatCleanup::~StreamingCompatCleanup"(ptr %cleanup) |
| resume { ptr, i32 } %eh_info |
| } |
| |
| ; This is the same as "streaming_with_cleanup" but for a locally streaming function. |
| ; The lowering of "unwind_cleanup" is expected to match "streaming_with_cleanup". |
| define void @locally_streaming_with_cleanup() "aarch64_pstate_sm_body" personality ptr @__gxx_personality_v0 { |
| ; CHECK-LABEL: name: locally_streaming_with_cleanup |
| ; CHECK: bb.0 (%ir-block.0): |
| ; CHECK-NEXT: successors: %bb.1(0x7ffff800), %bb.2(0x00000800) |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: MSRpstatesvcrImm1 1, 1, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| ; CHECK-NEXT: EH_LABEL <mcsymbol > |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: BL @may_throw, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: EH_LABEL <mcsymbol > |
| ; CHECK-NEXT: B %bb.1 |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: bb.1.normal_return: |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: [[ADDXri:%[0-9]+]]:gpr64sp = ADDXri %stack.0.cleanup, 0, 0 |
| ; CHECK-NEXT: $x0 = COPY [[ADDXri]] |
| ; CHECK-NEXT: BL @"StreamingCleanup::~StreamingCleanup", csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: MSRpstatesvcrImm1 1, 0, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| ; CHECK-NEXT: RET_ReallyLR |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: bb.2.unwind_cleanup (landing-pad): |
| ; CHECK-NEXT: liveins: $x0, $x1 |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: EH_LABEL <mcsymbol > |
| ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64all = COPY killed $x1 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64all = COPY killed $x0 |
| ; CHECK-NEXT: MSRpstatesvcrImm1 1, 1, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: [[ADDXri1:%[0-9]+]]:gpr64sp = ADDXri %stack.0.cleanup, 0, 0 |
| ; CHECK-NEXT: $x0 = COPY [[ADDXri1]] |
| ; CHECK-NEXT: BL @"StreamingCleanup::~StreamingCleanup", csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: MSRpstatesvcrImm1 1, 0, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit-def $sp, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| ; CHECK-NEXT: $x0 = COPY [[COPY1]] |
| ; CHECK-NEXT: BL @_Unwind_Resume, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp |
| ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp |
| ; CHECK-NEXT: MSRpstatesvcrImm1 1, 1, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit $vg, implicit-def $vg, implicit-def $fpmr |
| %cleanup = alloca i8, align 1 |
| invoke void @may_throw() |
| to label %normal_return unwind label %unwind_cleanup |
| |
| normal_return: |
| call void @"StreamingCleanup::~StreamingCleanup"(ptr %cleanup) |
| ret void |
| |
| unwind_cleanup: |
| %eh_info = landingpad { ptr, i32 } |
| cleanup |
| call void @"StreamingCleanup::~StreamingCleanup"(ptr %cleanup) |
| resume { ptr, i32 } %eh_info |
| } |
| |
| declare i32 @__gxx_personality_v0(...) |