diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -1023,6 +1023,16 @@ UNW_RISCV_F29 = 61, UNW_RISCV_F30 = 62, UNW_RISCV_F31 = 63, + // 65-95 -- Reserved for future standard extensions + // 96-127 -- v0-v31 (Vector registers) + // 128-3071 -- Reserved for future standard extensions + // 3072-4095 -- Reserved for custom extensions + // 4096-8191 -- CSRs + // + // VLENB CSR number: 0xC22 -- defined by section 3 of v-spec: + // https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#3-vector-extension-programmers-model + // VLENB DWARF number: 0x1000 + 0xC22 + UNW_RISCV_VLENB = 0x1C22, }; // VE register numbers diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -4085,6 +4085,8 @@ return true; if (regNum < 0) return false; + if (regNum == UNW_RISCV_VLENB) + return true; if (regNum > UNW_RISCV_F31) return false; return true; @@ -4099,6 +4101,11 @@ return 0; if ((regNum > 0) && (regNum < 32)) return _registers[regNum]; + if (regNum == UNW_RISCV_VLENB) { + reg_t vlenb; + __asm__("csrr %0, 0xC22" : "=r"(vlenb)); + return vlenb; + } _LIBUNWIND_ABORT("unsupported riscv register"); } @@ -4250,6 +4257,8 @@ return "ft10"; case UNW_RISCV_F31: return "ft11"; + case UNW_RISCV_VLENB: + return "vlenb"; default: return "unknown register"; } diff --git a/libunwind/test/unwind_scalable_vectors.pass.cpp b/libunwind/test/unwind_scalable_vectors.pass.cpp new file mode 100644 --- /dev/null +++ b/libunwind/test/unwind_scalable_vectors.pass.cpp @@ -0,0 +1,50 @@ +// -*- 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={{riscv64-.+}} + +#undef NDEBUG +#include +#include + +// Check correct unwinding of frame with VLENB-sized objects (vector registers): +// 1. Save return address (ra) in temporary register. +// 2. Load VLENB (vector length in bytes) and substract it from current stack +// pointer (sp) - equivalent to one vector register on stack frame. +// 3. Set DWARF cannonical frame address (CFA) to "sp + vlenb" expresssion so it +// can be correctly unwinded. +// 4. Call stepper() function and check that 2 unwind steps are successful - +// from stepper() into foo() and from foo() into main(). +// 5. Restore stack pointer and return address. +__attribute__((naked)) static void foo() { + __asm__(".cfi_startproc\n" + "mv s0, ra\n" + "csrr s1, vlenb\n" + "sub sp, sp, s1\n" + "# .cfi_def_cfa_expression sp + vlenb\n" + ".cfi_escape 0x0f, 0x07, 0x72, 0x00, 0x92, 0xa2, 0x38, 0x00, 0x22\n" + "call stepper\n" + "add sp, sp, s1\n" + "mv ra, s0\n" + "ret\n" + ".cfi_endproc\n"); +} + +extern "C" void stepper() { + unw_cursor_t cursor; + unw_context_t uc; + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + // Stepping into foo() should succeed. + assert(unw_step(&cursor) > 0); + // Stepping past foo() should succeed, too. + assert(unw_step(&cursor) > 0); +} + +int main() { foo(); }