
The vector granule (AArch64 DWARF register 46) is a pseudo-register that contains the available size in bits of SVE vector registers in the current call frame, divided by 64. The vector granule can be used in DWARF expressions to describe SVE/SME stack frame layouts (e.g., the location of SVE callee-saves). The first time VG is evaluated (if not already set), it is initialized to the result of evaluating a "CNTD" instruction (this assumes SVE is available). To support SME, the value of VG can change per call frame; this is currently handled like any other callee-save and is intended to support the unwind information implemented in #152283. This limits how VG is used in the CFI information of functions with "streaming-mode changes" (mode changes that change the SVE vector length), to make the unwinder's job easier.
66 lines
1.8 KiB
C++
66 lines
1.8 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// REQUIRES: linux && target={{aarch64-.+}}
|
|
|
|
#include <libunwind.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
// Basic test of VG (Vector Granule) unwinding. This is meant to mimic SVE/SME
|
|
// unwind info without requiring those features for this test.
|
|
|
|
#define VG_REGNUM 46
|
|
|
|
__attribute__((noinline)) void baz() {
|
|
// The previous value of VG is 2
|
|
asm(".cfi_escape 0x16, 0x2e, 0x01, 0x32");
|
|
|
|
unw_context_t context;
|
|
unw_cursor_t cursor;
|
|
unw_getcontext(&context);
|
|
unw_init_local(&cursor, &context);
|
|
|
|
// Note: At this point VG is not defined (until we unw_step).
|
|
|
|
uint16_t expected_vgs[]{/*qux*/ 2, /*bar*/ 2, /*foo*/ 8, /*main*/ 2};
|
|
for (uint16_t expected_vg : expected_vgs) {
|
|
unw_step(&cursor);
|
|
unw_word_t vg;
|
|
unw_get_reg(&cursor, VG_REGNUM, &vg);
|
|
if (vg != expected_vg)
|
|
exit(1);
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
__attribute__((noinline)) void qux() { baz(); }
|
|
|
|
__attribute__((noinline)) void bar() {
|
|
// The previous value of VG is 8
|
|
asm(".cfi_escape 0x16, 0x2e, 0x01, 0x38");
|
|
// The previous value of W21 is VG (used to force an evaluation of VG).
|
|
asm(".cfi_escape 0x16, 0x15, 0x03, 0x92, 0x2e, 0x00");
|
|
|
|
// smstop sm
|
|
qux();
|
|
// smstart sm
|
|
}
|
|
__attribute__((noinline)) void foo() {
|
|
// The previous value of VG is 2
|
|
asm(".cfi_escape 0x16, 0x2e, 0x01, 0x32");
|
|
// The previous value of W21 is VG (used to force an evaluation of VG).
|
|
asm(".cfi_escape 0x16, 0x15, 0x03, 0x92, 0x2e, 0x00");
|
|
|
|
// smstart sm
|
|
bar();
|
|
// smstop sm
|
|
}
|
|
|
|
int main() { foo(); }
|