| 1 | //===-- RegisterInfoPOSIX_riscv64.cpp -------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===---------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "RegisterInfoPOSIX_riscv64.h" |
| 10 | #include "lldb/Utility/Flags.h" |
| 11 | #include "lldb/lldb-defines.h" |
| 12 | #include "llvm/Support/Compiler.h" |
| 13 | |
| 14 | #include <cassert> |
| 15 | #include <stddef.h> |
| 16 | |
| 17 | #define GPR_OFFSET(idx) ((idx)*8 + 0) |
| 18 | #define FPR_OFFSET(idx) ((idx)*8 + sizeof(RegisterInfoPOSIX_riscv64::GPR)) |
| 19 | |
| 20 | #define DECLARE_REGISTER_INFOS_RISCV64_STRUCT |
| 21 | #include "RegisterInfos_riscv64.h" |
| 22 | #undef DECLARE_REGISTER_INFOS_RISCV64_STRUCT |
| 23 | |
| 24 | // Number of register sets provided by this context. |
| 25 | enum { |
| 26 | k_num_gpr_registers = gpr_last_riscv - gpr_first_riscv + 1, |
| 27 | k_num_fpr_registers = fpr_last_riscv - fpr_first_riscv + 1, |
| 28 | k_num_register_sets_default = 1 |
| 29 | }; |
| 30 | |
| 31 | // RISC-V64 general purpose registers. |
| 32 | static const uint32_t g_gpr_regnums_riscv64[] = { |
| 33 | gpr_pc_riscv, gpr_ra_riscv, gpr_sp_riscv, gpr_x3_riscv, |
| 34 | gpr_x4_riscv, gpr_x5_riscv, gpr_x6_riscv, gpr_x7_riscv, |
| 35 | gpr_fp_riscv, gpr_x9_riscv, gpr_x10_riscv, gpr_x11_riscv, |
| 36 | gpr_x12_riscv, gpr_x13_riscv, gpr_x14_riscv, gpr_x15_riscv, |
| 37 | gpr_x16_riscv, gpr_x17_riscv, gpr_x18_riscv, gpr_x19_riscv, |
| 38 | gpr_x20_riscv, gpr_x21_riscv, gpr_x22_riscv, gpr_x23_riscv, |
| 39 | gpr_x24_riscv, gpr_x25_riscv, gpr_x26_riscv, gpr_x27_riscv, |
| 40 | gpr_x28_riscv, gpr_x29_riscv, gpr_x30_riscv, gpr_x31_riscv, |
| 41 | gpr_x0_riscv, LLDB_INVALID_REGNUM}; |
| 42 | |
| 43 | static_assert(((sizeof g_gpr_regnums_riscv64 / |
| 44 | sizeof g_gpr_regnums_riscv64[0]) - |
| 45 | 1) == k_num_gpr_registers, |
| 46 | "g_gpr_regnums_riscv64 has wrong number of register infos" ); |
| 47 | |
| 48 | // Register sets for RISC-V64. |
| 49 | static const lldb_private::RegisterSet g_reg_set_gpr_riscv64 = { |
| 50 | .name: "General Purpose Registers" , .short_name: "gpr" , .num_registers: k_num_gpr_registers, |
| 51 | .registers: g_gpr_regnums_riscv64}; |
| 52 | static const lldb_private::RegisterSet g_reg_set_fpr_riscv64 = { |
| 53 | .name: "Floating Point Registers" , .short_name: "fpr" , .num_registers: k_num_fpr_registers, .registers: nullptr}; |
| 54 | |
| 55 | RegisterInfoPOSIX_riscv64::RegisterInfoPOSIX_riscv64( |
| 56 | const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets) |
| 57 | : lldb_private::RegisterInfoAndSetInterface(target_arch), |
| 58 | m_opt_regsets(opt_regsets) { |
| 59 | switch (target_arch.GetMachine()) { |
| 60 | case llvm::Triple::riscv64: { |
| 61 | // By-default considering RISC-V has only GPR. |
| 62 | // Other register sets could be enabled optionally by opt_regsets. |
| 63 | AddRegSetGP(); |
| 64 | |
| 65 | if (m_opt_regsets.AnySet(mask: eRegsetMaskFP)) |
| 66 | AddRegSetFP(); |
| 67 | |
| 68 | break; |
| 69 | } |
| 70 | default: |
| 71 | assert(false && "Unhandled target architecture." ); |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | void RegisterInfoPOSIX_riscv64::AddRegSetGP() { |
| 76 | m_register_infos.resize(new_size: k_num_gpr_registers); |
| 77 | memcpy(dest: &m_register_infos[0], src: g_register_infos_riscv64_gpr, |
| 78 | n: sizeof(g_register_infos_riscv64_gpr)); |
| 79 | m_register_sets.push_back(x: g_reg_set_gpr_riscv64); |
| 80 | |
| 81 | m_per_regset_regnum_range[GPRegSet] = |
| 82 | std::make_pair(x: gpr_first_riscv, y: m_register_infos.size()); |
| 83 | } |
| 84 | |
| 85 | void RegisterInfoPOSIX_riscv64::AddRegSetFP() { |
| 86 | const uint32_t register_info_count = m_register_infos.size(); |
| 87 | const uint32_t register_set_count = m_register_sets.size(); |
| 88 | |
| 89 | // Filling m_register_infos. |
| 90 | // For FPR case we do not need to correct register offsets and kinds |
| 91 | // while for other further cases (like VPR), register offset/kind |
| 92 | // should be started counting from the last one in previously added |
| 93 | // regset. This is needed for the case e.g. when architecture has GPR + VPR |
| 94 | // sets only. |
| 95 | m_register_infos.resize(new_size: register_info_count + k_num_fpr_registers); |
| 96 | memcpy(dest: &m_register_infos[register_info_count], src: g_register_infos_riscv64_fpr, |
| 97 | n: sizeof(g_register_infos_riscv64_fpr)); |
| 98 | |
| 99 | // Filling m_register_sets with enabled register set |
| 100 | for (uint32_t i = 0; i < k_num_fpr_registers; i++) |
| 101 | m_fp_regnum_collection.push_back(x: register_info_count + i); |
| 102 | m_register_sets.push_back(x: g_reg_set_fpr_riscv64); |
| 103 | m_register_sets.back().registers = m_fp_regnum_collection.data(); |
| 104 | |
| 105 | m_per_regset_regnum_range[register_set_count] = |
| 106 | std::make_pair(x: register_info_count, y: m_register_infos.size()); |
| 107 | } |
| 108 | |
| 109 | uint32_t RegisterInfoPOSIX_riscv64::GetRegisterCount() const { |
| 110 | return m_register_infos.size(); |
| 111 | } |
| 112 | |
| 113 | size_t RegisterInfoPOSIX_riscv64::GetGPRSize() const { |
| 114 | return sizeof(struct RegisterInfoPOSIX_riscv64::GPR); |
| 115 | } |
| 116 | |
| 117 | size_t RegisterInfoPOSIX_riscv64::GetFPRSize() const { |
| 118 | return sizeof(struct RegisterInfoPOSIX_riscv64::FPR); |
| 119 | } |
| 120 | |
| 121 | const lldb_private::RegisterInfo * |
| 122 | RegisterInfoPOSIX_riscv64::GetRegisterInfo() const { |
| 123 | return m_register_infos.data(); |
| 124 | } |
| 125 | |
| 126 | size_t RegisterInfoPOSIX_riscv64::GetRegisterSetCount() const { |
| 127 | return m_register_sets.size(); |
| 128 | } |
| 129 | |
| 130 | size_t RegisterInfoPOSIX_riscv64::GetRegisterSetFromRegisterIndex( |
| 131 | uint32_t reg_index) const { |
| 132 | for (const auto ®set_range : m_per_regset_regnum_range) { |
| 133 | if (reg_index >= regset_range.second.first && |
| 134 | reg_index < regset_range.second.second) |
| 135 | return regset_range.first; |
| 136 | } |
| 137 | return LLDB_INVALID_REGNUM; |
| 138 | } |
| 139 | |
| 140 | bool RegisterInfoPOSIX_riscv64::IsFPReg(unsigned reg) const { |
| 141 | return llvm::is_contained(Range: m_fp_regnum_collection, Element: reg); |
| 142 | } |
| 143 | |
| 144 | const lldb_private::RegisterSet * |
| 145 | RegisterInfoPOSIX_riscv64::GetRegisterSet(size_t set_index) const { |
| 146 | if (set_index < GetRegisterSetCount()) |
| 147 | return &m_register_sets[set_index]; |
| 148 | return nullptr; |
| 149 | } |
| 150 | |