1 | //===-- RegisterInfoPOSIX_arm64.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 <cassert> |
10 | #include <cstddef> |
11 | #include <vector> |
12 | |
13 | #include "lldb/lldb-defines.h" |
14 | #include "llvm/Support/Compiler.h" |
15 | |
16 | #include "RegisterInfoPOSIX_arm64.h" |
17 | |
18 | // Based on RegisterContextDarwin_arm64.cpp |
19 | #define GPR_OFFSET(idx) ((idx)*8) |
20 | #define GPR_OFFSET_NAME(reg) \ |
21 | (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::GPR, reg)) |
22 | |
23 | #define FPU_OFFSET(idx) ((idx)*16 + sizeof(RegisterInfoPOSIX_arm64::GPR)) |
24 | #define FPU_OFFSET_NAME(reg) \ |
25 | (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::FPU, reg) + \ |
26 | sizeof(RegisterInfoPOSIX_arm64::GPR)) |
27 | |
28 | // This information is based on AArch64 with SVE architecture reference manual. |
29 | // AArch64 with SVE has 32 Z and 16 P vector registers. There is also an FFR |
30 | // (First Fault) register and a VG (Vector Granule) pseudo register. |
31 | |
32 | // SVE 16-byte quad word is the basic unit of expansion in vector length. |
33 | #define SVE_QUAD_WORD_BYTES 16 |
34 | |
35 | // Vector length is the multiplier which decides the no of quad words, |
36 | // (multiples of 128-bits or 16-bytes) present in a Z register. Vector length |
37 | // is decided during execution and can change at runtime. SVE AArch64 register |
38 | // infos have modes one for each valid value of vector length. A change in |
39 | // vector length requires register context to update sizes of SVE Z, P and FFR. |
40 | // Also register context needs to update byte offsets of all registers affected |
41 | // by the change in vector length. |
42 | #define SVE_REGS_DEFAULT_OFFSET_LINUX sizeof(RegisterInfoPOSIX_arm64::GPR) |
43 | |
44 | #define SVE_OFFSET_VG SVE_REGS_DEFAULT_OFFSET_LINUX |
45 | |
46 | #define EXC_OFFSET_NAME(reg) \ |
47 | (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::EXC, reg) + \ |
48 | sizeof(RegisterInfoPOSIX_arm64::GPR) + \ |
49 | sizeof(RegisterInfoPOSIX_arm64::FPU)) |
50 | #define DBG_OFFSET_NAME(reg) \ |
51 | (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::DBG, reg) + \ |
52 | sizeof(RegisterInfoPOSIX_arm64::GPR) + \ |
53 | sizeof(RegisterInfoPOSIX_arm64::FPU) + \ |
54 | sizeof(RegisterInfoPOSIX_arm64::EXC)) |
55 | |
56 | #define DEFINE_DBG(reg, i) \ |
57 | #reg, NULL, \ |
58 | sizeof(((RegisterInfoPOSIX_arm64::DBG *) NULL)->reg[i]), \ |
59 | DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, \ |
60 | {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ |
61 | LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ |
62 | dbg_##reg##i }, \ |
63 | NULL, NULL, NULL, |
64 | #define REG_CONTEXT_SIZE \ |
65 | (sizeof(RegisterInfoPOSIX_arm64::GPR) + \ |
66 | sizeof(RegisterInfoPOSIX_arm64::FPU) + \ |
67 | sizeof(RegisterInfoPOSIX_arm64::EXC)) |
68 | |
69 | // Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. |
70 | #define DECLARE_REGISTER_INFOS_ARM64_STRUCT |
71 | #include "RegisterInfos_arm64.h" |
72 | #include "RegisterInfos_arm64_sve.h" |
73 | #undef DECLARE_REGISTER_INFOS_ARM64_STRUCT |
74 | |
75 | static lldb_private::RegisterInfo g_register_infos_pauth[] = { |
76 | DEFINE_EXTENSION_REG(data_mask), DEFINE_EXTENSION_REG(code_mask)}; |
77 | |
78 | static lldb_private::RegisterInfo g_register_infos_mte[] = { |
79 | DEFINE_EXTENSION_REG(mte_ctrl)}; |
80 | |
81 | static lldb_private::RegisterInfo g_register_infos_tls[] = { |
82 | DEFINE_EXTENSION_REG(tpidr), |
83 | // Only present when SME is present |
84 | DEFINE_EXTENSION_REG(tpidr2)}; |
85 | |
86 | static lldb_private::RegisterInfo g_register_infos_sme[] = { |
87 | DEFINE_EXTENSION_REG(svcr), |
88 | DEFINE_EXTENSION_REG(svg), |
89 | // 16 is a default size we will change later. |
90 | {.name: "za" , .alt_name: nullptr, .byte_size: 16, .byte_offset: 0, .encoding: lldb::eEncodingVector, .format: lldb::eFormatVectorOfUInt8, |
91 | KIND_ALL_INVALID, .value_regs: nullptr, .invalidate_regs: nullptr, .flags_type: nullptr}}; |
92 | |
93 | static lldb_private::RegisterInfo g_register_infos_sme2[] = { |
94 | {.name: "zt0" , .alt_name: nullptr, .byte_size: 64, .byte_offset: 0, .encoding: lldb::eEncodingVector, .format: lldb::eFormatVectorOfUInt8, |
95 | KIND_ALL_INVALID, .value_regs: nullptr, .invalidate_regs: nullptr, .flags_type: nullptr}}; |
96 | |
97 | // Number of register sets provided by this context. |
98 | enum { |
99 | k_num_gpr_registers = gpr_w28 - gpr_x0 + 1, |
100 | k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1, |
101 | k_num_sve_registers = sve_ffr - sve_vg + 1, |
102 | k_num_mte_register = 1, |
103 | // Number of TLS registers is dynamic so it is not listed here. |
104 | k_num_pauth_register = 2, |
105 | // SME2's ZT0 will also be added to this set if present. So this number is |
106 | // only for SME1 registers. |
107 | k_num_sme_register = 3, |
108 | k_num_register_sets_default = 2, |
109 | k_num_register_sets = 3 |
110 | }; |
111 | |
112 | // ARM64 general purpose registers. |
113 | static const uint32_t g_gpr_regnums_arm64[] = { |
114 | gpr_x0, gpr_x1, gpr_x2, gpr_x3, |
115 | gpr_x4, gpr_x5, gpr_x6, gpr_x7, |
116 | gpr_x8, gpr_x9, gpr_x10, gpr_x11, |
117 | gpr_x12, gpr_x13, gpr_x14, gpr_x15, |
118 | gpr_x16, gpr_x17, gpr_x18, gpr_x19, |
119 | gpr_x20, gpr_x21, gpr_x22, gpr_x23, |
120 | gpr_x24, gpr_x25, gpr_x26, gpr_x27, |
121 | gpr_x28, gpr_fp, gpr_lr, gpr_sp, |
122 | gpr_pc, gpr_cpsr, gpr_w0, gpr_w1, |
123 | gpr_w2, gpr_w3, gpr_w4, gpr_w5, |
124 | gpr_w6, gpr_w7, gpr_w8, gpr_w9, |
125 | gpr_w10, gpr_w11, gpr_w12, gpr_w13, |
126 | gpr_w14, gpr_w15, gpr_w16, gpr_w17, |
127 | gpr_w18, gpr_w19, gpr_w20, gpr_w21, |
128 | gpr_w22, gpr_w23, gpr_w24, gpr_w25, |
129 | gpr_w26, gpr_w27, gpr_w28, LLDB_INVALID_REGNUM}; |
130 | |
131 | static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - |
132 | 1) == k_num_gpr_registers, |
133 | "g_gpr_regnums_arm64 has wrong number of register infos" ); |
134 | |
135 | // ARM64 floating point registers. |
136 | static const uint32_t g_fpu_regnums_arm64[] = { |
137 | fpu_v0, fpu_v1, fpu_v2, |
138 | fpu_v3, fpu_v4, fpu_v5, |
139 | fpu_v6, fpu_v7, fpu_v8, |
140 | fpu_v9, fpu_v10, fpu_v11, |
141 | fpu_v12, fpu_v13, fpu_v14, |
142 | fpu_v15, fpu_v16, fpu_v17, |
143 | fpu_v18, fpu_v19, fpu_v20, |
144 | fpu_v21, fpu_v22, fpu_v23, |
145 | fpu_v24, fpu_v25, fpu_v26, |
146 | fpu_v27, fpu_v28, fpu_v29, |
147 | fpu_v30, fpu_v31, fpu_s0, |
148 | fpu_s1, fpu_s2, fpu_s3, |
149 | fpu_s4, fpu_s5, fpu_s6, |
150 | fpu_s7, fpu_s8, fpu_s9, |
151 | fpu_s10, fpu_s11, fpu_s12, |
152 | fpu_s13, fpu_s14, fpu_s15, |
153 | fpu_s16, fpu_s17, fpu_s18, |
154 | fpu_s19, fpu_s20, fpu_s21, |
155 | fpu_s22, fpu_s23, fpu_s24, |
156 | fpu_s25, fpu_s26, fpu_s27, |
157 | fpu_s28, fpu_s29, fpu_s30, |
158 | fpu_s31, fpu_d0, fpu_d1, |
159 | fpu_d2, fpu_d3, fpu_d4, |
160 | fpu_d5, fpu_d6, fpu_d7, |
161 | fpu_d8, fpu_d9, fpu_d10, |
162 | fpu_d11, fpu_d12, fpu_d13, |
163 | fpu_d14, fpu_d15, fpu_d16, |
164 | fpu_d17, fpu_d18, fpu_d19, |
165 | fpu_d20, fpu_d21, fpu_d22, |
166 | fpu_d23, fpu_d24, fpu_d25, |
167 | fpu_d26, fpu_d27, fpu_d28, |
168 | fpu_d29, fpu_d30, fpu_d31, |
169 | fpu_fpsr, fpu_fpcr, LLDB_INVALID_REGNUM}; |
170 | static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - |
171 | 1) == k_num_fpr_registers, |
172 | "g_fpu_regnums_arm64 has wrong number of register infos" ); |
173 | |
174 | // ARM64 SVE registers. |
175 | static const uint32_t g_sve_regnums_arm64[] = { |
176 | sve_vg, sve_z0, sve_z1, |
177 | sve_z2, sve_z3, sve_z4, |
178 | sve_z5, sve_z6, sve_z7, |
179 | sve_z8, sve_z9, sve_z10, |
180 | sve_z11, sve_z12, sve_z13, |
181 | sve_z14, sve_z15, sve_z16, |
182 | sve_z17, sve_z18, sve_z19, |
183 | sve_z20, sve_z21, sve_z22, |
184 | sve_z23, sve_z24, sve_z25, |
185 | sve_z26, sve_z27, sve_z28, |
186 | sve_z29, sve_z30, sve_z31, |
187 | sve_p0, sve_p1, sve_p2, |
188 | sve_p3, sve_p4, sve_p5, |
189 | sve_p6, sve_p7, sve_p8, |
190 | sve_p9, sve_p10, sve_p11, |
191 | sve_p12, sve_p13, sve_p14, |
192 | sve_p15, sve_ffr, LLDB_INVALID_REGNUM}; |
193 | static_assert(((sizeof g_sve_regnums_arm64 / sizeof g_sve_regnums_arm64[0]) - |
194 | 1) == k_num_sve_registers, |
195 | "g_sve_regnums_arm64 has wrong number of register infos" ); |
196 | |
197 | // Register sets for ARM64. |
198 | static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = { |
199 | {.name: "General Purpose Registers" , .short_name: "gpr" , .num_registers: k_num_gpr_registers, |
200 | .registers: g_gpr_regnums_arm64}, |
201 | {.name: "Floating Point Registers" , .short_name: "fpu" , .num_registers: k_num_fpr_registers, |
202 | .registers: g_fpu_regnums_arm64}, |
203 | {.name: "Scalable Vector Extension Registers" , .short_name: "sve" , .num_registers: k_num_sve_registers, |
204 | .registers: g_sve_regnums_arm64}}; |
205 | |
206 | static const lldb_private::RegisterSet g_reg_set_pauth_arm64 = { |
207 | .name: "Pointer Authentication Registers" , .short_name: "pauth" , .num_registers: k_num_pauth_register, .registers: nullptr}; |
208 | |
209 | static const lldb_private::RegisterSet g_reg_set_mte_arm64 = { |
210 | .name: "MTE Control Register" , .short_name: "mte" , .num_registers: k_num_mte_register, .registers: nullptr}; |
211 | |
212 | // The size of the TLS set is dynamic, so not listed here. |
213 | |
214 | static const lldb_private::RegisterSet g_reg_set_sme_arm64 = { |
215 | .name: "Scalable Matrix Extension Registers" , .short_name: "sme" , .num_registers: k_num_sme_register, .registers: nullptr}; |
216 | |
217 | RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( |
218 | const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets) |
219 | : lldb_private::RegisterInfoAndSetInterface(target_arch), |
220 | m_opt_regsets(opt_regsets) { |
221 | switch (target_arch.GetMachine()) { |
222 | case llvm::Triple::aarch64: |
223 | case llvm::Triple::aarch64_32: { |
224 | m_register_set_p = g_reg_sets_arm64; |
225 | m_register_set_count = k_num_register_sets_default; |
226 | m_per_regset_regnum_range[GPRegSet] = std::make_pair(x: gpr_x0, y: gpr_w28 + 1); |
227 | m_per_regset_regnum_range[FPRegSet] = std::make_pair(x: fpu_v0, y: fpu_fpcr + 1); |
228 | |
229 | // Now configure register sets supported by current target. If we have a |
230 | // dynamic register set like MTE, Pointer Authentication regset then we need |
231 | // to create dynamic register infos and regset array. Push back all optional |
232 | // register infos and regset and calculate register offsets accordingly. |
233 | if (m_opt_regsets.AnySet(mask: eRegsetMaskSVE | eRegsetMaskSSVE)) { |
234 | m_register_info_p = g_register_infos_arm64_sve_le; |
235 | m_register_info_count = sve_ffr + 1; |
236 | m_per_regset_regnum_range[m_register_set_count++] = |
237 | std::make_pair(x: sve_vg, y: sve_ffr + 1); |
238 | } else { |
239 | m_register_info_p = g_register_infos_arm64_le; |
240 | m_register_info_count = fpu_fpcr + 1; |
241 | } |
242 | |
243 | if (m_opt_regsets.AnySet(mask: eRegsetMaskDynamic)) { |
244 | llvm::ArrayRef<lldb_private::RegisterInfo> reg_infos_ref = |
245 | llvm::ArrayRef(m_register_info_p, m_register_info_count); |
246 | llvm::ArrayRef<lldb_private::RegisterSet> reg_sets_ref = |
247 | llvm::ArrayRef(m_register_set_p, m_register_set_count); |
248 | llvm::copy(Range&: reg_infos_ref, Out: std::back_inserter(x&: m_dynamic_reg_infos)); |
249 | llvm::copy(Range&: reg_sets_ref, Out: std::back_inserter(x&: m_dynamic_reg_sets)); |
250 | |
251 | if (m_opt_regsets.AllSet(mask: eRegsetMaskPAuth)) |
252 | AddRegSetPAuth(); |
253 | |
254 | if (m_opt_regsets.AllSet(mask: eRegsetMaskMTE)) |
255 | AddRegSetMTE(); |
256 | |
257 | // The TLS set always contains tpidr but only has tpidr2 when SME is |
258 | // present. |
259 | AddRegSetTLS(has_tpidr2: m_opt_regsets.AllSet(mask: eRegsetMaskSSVE)); |
260 | |
261 | if (m_opt_regsets.AnySet(mask: eRegsetMaskSSVE)) |
262 | AddRegSetSME(has_zt: m_opt_regsets.AnySet(mask: eRegsetMaskZT)); |
263 | |
264 | m_register_info_count = m_dynamic_reg_infos.size(); |
265 | m_register_info_p = m_dynamic_reg_infos.data(); |
266 | m_register_set_p = m_dynamic_reg_sets.data(); |
267 | m_register_set_count = m_dynamic_reg_sets.size(); |
268 | } |
269 | break; |
270 | } |
271 | default: |
272 | assert(false && "Unhandled target architecture." ); |
273 | } |
274 | } |
275 | |
276 | uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const { |
277 | return m_register_info_count; |
278 | } |
279 | |
280 | size_t RegisterInfoPOSIX_arm64::GetGPRSizeStatic() { |
281 | return sizeof(struct RegisterInfoPOSIX_arm64::GPR); |
282 | } |
283 | |
284 | size_t RegisterInfoPOSIX_arm64::GetFPRSize() const { |
285 | return sizeof(struct RegisterInfoPOSIX_arm64::FPU); |
286 | } |
287 | |
288 | const lldb_private::RegisterInfo * |
289 | RegisterInfoPOSIX_arm64::GetRegisterInfo() const { |
290 | return m_register_info_p; |
291 | } |
292 | |
293 | size_t RegisterInfoPOSIX_arm64::GetRegisterSetCount() const { |
294 | return m_register_set_count; |
295 | } |
296 | |
297 | size_t RegisterInfoPOSIX_arm64::GetRegisterSetFromRegisterIndex( |
298 | uint32_t reg_index) const { |
299 | for (const auto ®set_range : m_per_regset_regnum_range) { |
300 | if (reg_index >= regset_range.second.first && |
301 | reg_index < regset_range.second.second) |
302 | return regset_range.first; |
303 | } |
304 | return LLDB_INVALID_REGNUM; |
305 | } |
306 | |
307 | const lldb_private::RegisterSet * |
308 | RegisterInfoPOSIX_arm64::GetRegisterSet(size_t set_index) const { |
309 | if (set_index < GetRegisterSetCount()) |
310 | return &m_register_set_p[set_index]; |
311 | return nullptr; |
312 | } |
313 | |
314 | void RegisterInfoPOSIX_arm64::AddRegSetPAuth() { |
315 | uint32_t pa_regnum = m_dynamic_reg_infos.size(); |
316 | for (uint32_t i = 0; i < k_num_pauth_register; i++) { |
317 | pauth_regnum_collection.push_back(x: pa_regnum + i); |
318 | m_dynamic_reg_infos.push_back(x: g_register_infos_pauth[i]); |
319 | m_dynamic_reg_infos[pa_regnum + i].byte_offset = |
320 | m_dynamic_reg_infos[pa_regnum + i - 1].byte_offset + |
321 | m_dynamic_reg_infos[pa_regnum + i - 1].byte_size; |
322 | m_dynamic_reg_infos[pa_regnum + i].kinds[lldb::eRegisterKindLLDB] = |
323 | pa_regnum + i; |
324 | } |
325 | |
326 | m_per_regset_regnum_range[m_register_set_count] = |
327 | std::make_pair(x&: pa_regnum, y: m_dynamic_reg_infos.size()); |
328 | m_dynamic_reg_sets.push_back(x: g_reg_set_pauth_arm64); |
329 | m_dynamic_reg_sets.back().registers = pauth_regnum_collection.data(); |
330 | } |
331 | |
332 | void RegisterInfoPOSIX_arm64::AddRegSetMTE() { |
333 | uint32_t mte_regnum = m_dynamic_reg_infos.size(); |
334 | m_mte_regnum_collection.push_back(x: mte_regnum); |
335 | m_dynamic_reg_infos.push_back(x: g_register_infos_mte[0]); |
336 | m_dynamic_reg_infos[mte_regnum].byte_offset = |
337 | m_dynamic_reg_infos[mte_regnum - 1].byte_offset + |
338 | m_dynamic_reg_infos[mte_regnum - 1].byte_size; |
339 | m_dynamic_reg_infos[mte_regnum].kinds[lldb::eRegisterKindLLDB] = mte_regnum; |
340 | |
341 | m_per_regset_regnum_range[m_register_set_count] = |
342 | std::make_pair(x&: mte_regnum, y: mte_regnum + 1); |
343 | m_dynamic_reg_sets.push_back(x: g_reg_set_mte_arm64); |
344 | m_dynamic_reg_sets.back().registers = m_mte_regnum_collection.data(); |
345 | } |
346 | |
347 | void RegisterInfoPOSIX_arm64::AddRegSetTLS(bool has_tpidr2) { |
348 | uint32_t tls_regnum = m_dynamic_reg_infos.size(); |
349 | uint32_t num_regs = has_tpidr2 ? 2 : 1; |
350 | for (uint32_t i = 0; i < num_regs; i++) { |
351 | m_tls_regnum_collection.push_back(x: tls_regnum + i); |
352 | m_dynamic_reg_infos.push_back(x: g_register_infos_tls[i]); |
353 | m_dynamic_reg_infos[tls_regnum + i].byte_offset = |
354 | m_dynamic_reg_infos[tls_regnum + i - 1].byte_offset + |
355 | m_dynamic_reg_infos[tls_regnum + i - 1].byte_size; |
356 | m_dynamic_reg_infos[tls_regnum + i].kinds[lldb::eRegisterKindLLDB] = |
357 | tls_regnum + i; |
358 | } |
359 | |
360 | m_per_regset_regnum_range[m_register_set_count] = |
361 | std::make_pair(x&: tls_regnum, y: m_dynamic_reg_infos.size()); |
362 | m_dynamic_reg_sets.push_back( |
363 | x: {.name: "Thread Local Storage Registers" , .short_name: "tls" , .num_registers: num_regs, .registers: nullptr}); |
364 | m_dynamic_reg_sets.back().registers = m_tls_regnum_collection.data(); |
365 | } |
366 | |
367 | void RegisterInfoPOSIX_arm64::AddRegSetSME(bool has_zt) { |
368 | const uint32_t first_sme_regnum = m_dynamic_reg_infos.size(); |
369 | uint32_t sme_regnum = first_sme_regnum; |
370 | |
371 | for (uint32_t i = 0; i < k_num_sme_register; ++i, ++sme_regnum) { |
372 | m_sme_regnum_collection.push_back(x: sme_regnum); |
373 | m_dynamic_reg_infos.push_back(x: g_register_infos_sme[i]); |
374 | m_dynamic_reg_infos[sme_regnum].byte_offset = |
375 | m_dynamic_reg_infos[sme_regnum - 1].byte_offset + |
376 | m_dynamic_reg_infos[sme_regnum - 1].byte_size; |
377 | m_dynamic_reg_infos[sme_regnum].kinds[lldb::eRegisterKindLLDB] = sme_regnum; |
378 | } |
379 | |
380 | lldb_private::RegisterSet sme_regset = g_reg_set_sme_arm64; |
381 | |
382 | if (has_zt) { |
383 | m_sme_regnum_collection.push_back(x: sme_regnum); |
384 | m_dynamic_reg_infos.push_back(x: g_register_infos_sme2[0]); |
385 | m_dynamic_reg_infos[sme_regnum].byte_offset = |
386 | m_dynamic_reg_infos[sme_regnum - 1].byte_offset + |
387 | m_dynamic_reg_infos[sme_regnum - 1].byte_size; |
388 | m_dynamic_reg_infos[sme_regnum].kinds[lldb::eRegisterKindLLDB] = sme_regnum; |
389 | |
390 | sme_regset.num_registers += 1; |
391 | } |
392 | |
393 | m_per_regset_regnum_range[m_register_set_count] = |
394 | std::make_pair(x: first_sme_regnum, y: m_dynamic_reg_infos.size()); |
395 | m_dynamic_reg_sets.push_back(x: sme_regset); |
396 | m_dynamic_reg_sets.back().registers = m_sme_regnum_collection.data(); |
397 | |
398 | // When vg is written during streaming mode, svg will also change, as vg and |
399 | // svg in this state are both showing the streaming vector length. |
400 | // We model this as vg invalidating svg. In non-streaming mode this doesn't |
401 | // happen but to keep things simple we will invalidate svg anyway. |
402 | // |
403 | // This must be added now, rather than when vg is defined because SME is a |
404 | // dynamic set that may or may not be present. |
405 | static uint32_t vg_invalidates[] = {sme_regnum + 1 /*svg*/, |
406 | LLDB_INVALID_REGNUM}; |
407 | m_dynamic_reg_infos[GetRegNumSVEVG()].invalidate_regs = vg_invalidates; |
408 | } |
409 | |
410 | uint32_t RegisterInfoPOSIX_arm64::ConfigureVectorLengthSVE(uint32_t sve_vq) { |
411 | // sve_vq contains SVE Quad vector length in context of AArch64 SVE. |
412 | // SVE register infos if enabled cannot be disabled by selecting sve_vq = 0. |
413 | // Also if an invalid or previously set vector length is passed to this |
414 | // function then it will exit immediately with previously set vector length. |
415 | if (!VectorSizeIsValid(vq: sve_vq) || m_vector_reg_vq == sve_vq) |
416 | return m_vector_reg_vq; |
417 | |
418 | // We cannot enable AArch64 only mode if SVE was enabled. |
419 | if (sve_vq == eVectorQuadwordAArch64 && |
420 | m_vector_reg_vq > eVectorQuadwordAArch64) |
421 | sve_vq = eVectorQuadwordAArch64SVE; |
422 | |
423 | m_vector_reg_vq = sve_vq; |
424 | |
425 | if (sve_vq == eVectorQuadwordAArch64) |
426 | return m_vector_reg_vq; |
427 | std::vector<lldb_private::RegisterInfo> ®_info_ref = |
428 | m_per_vq_reg_infos[sve_vq]; |
429 | |
430 | if (reg_info_ref.empty()) { |
431 | reg_info_ref = llvm::ArrayRef(m_register_info_p, m_register_info_count); |
432 | |
433 | uint32_t offset = SVE_REGS_DEFAULT_OFFSET_LINUX; |
434 | reg_info_ref[fpu_fpsr].byte_offset = offset; |
435 | reg_info_ref[fpu_fpcr].byte_offset = offset + 4; |
436 | reg_info_ref[sve_vg].byte_offset = offset + 8; |
437 | offset += 16; |
438 | |
439 | // Update Z registers size and offset |
440 | uint32_t s_reg_base = fpu_s0; |
441 | uint32_t d_reg_base = fpu_d0; |
442 | uint32_t v_reg_base = fpu_v0; |
443 | uint32_t z_reg_base = sve_z0; |
444 | |
445 | for (uint32_t index = 0; index < 32; index++) { |
446 | reg_info_ref[s_reg_base + index].byte_offset = offset; |
447 | reg_info_ref[d_reg_base + index].byte_offset = offset; |
448 | reg_info_ref[v_reg_base + index].byte_offset = offset; |
449 | reg_info_ref[z_reg_base + index].byte_offset = offset; |
450 | |
451 | reg_info_ref[z_reg_base + index].byte_size = sve_vq * SVE_QUAD_WORD_BYTES; |
452 | offset += reg_info_ref[z_reg_base + index].byte_size; |
453 | } |
454 | |
455 | // Update P registers and FFR size and offset |
456 | for (uint32_t it = sve_p0; it <= sve_ffr; it++) { |
457 | reg_info_ref[it].byte_offset = offset; |
458 | reg_info_ref[it].byte_size = sve_vq * SVE_QUAD_WORD_BYTES / 8; |
459 | offset += reg_info_ref[it].byte_size; |
460 | } |
461 | |
462 | for (uint32_t it = sve_ffr + 1; it < m_register_info_count; it++) { |
463 | reg_info_ref[it].byte_offset = offset; |
464 | offset += reg_info_ref[it].byte_size; |
465 | } |
466 | |
467 | m_per_vq_reg_infos[sve_vq] = reg_info_ref; |
468 | } |
469 | |
470 | m_register_info_p = m_per_vq_reg_infos[sve_vq].data(); |
471 | return m_vector_reg_vq; |
472 | } |
473 | |
474 | void RegisterInfoPOSIX_arm64::ConfigureVectorLengthZA(uint32_t za_vq) { |
475 | if (!VectorSizeIsValid(vq: za_vq) || m_za_reg_vq == za_vq) |
476 | return; |
477 | |
478 | m_za_reg_vq = za_vq; |
479 | |
480 | // For SVE changes, we replace m_register_info_p completely. ZA is in a |
481 | // dynamic set and is just 1 register so we make an exception to const here. |
482 | lldb_private::RegisterInfo *non_const_reginfo = |
483 | const_cast<lldb_private::RegisterInfo *>(m_register_info_p); |
484 | non_const_reginfo[m_sme_regnum_collection[2]].byte_size = |
485 | (za_vq * 16) * (za_vq * 16); |
486 | } |
487 | |
488 | bool RegisterInfoPOSIX_arm64::IsSVEReg(unsigned reg) const { |
489 | if (m_vector_reg_vq > eVectorQuadwordAArch64) |
490 | return (sve_vg <= reg && reg <= sve_ffr); |
491 | else |
492 | return false; |
493 | } |
494 | |
495 | bool RegisterInfoPOSIX_arm64::IsSVEZReg(unsigned reg) const { |
496 | return (sve_z0 <= reg && reg <= sve_z31); |
497 | } |
498 | |
499 | bool RegisterInfoPOSIX_arm64::IsSVEPReg(unsigned reg) const { |
500 | return (sve_p0 <= reg && reg <= sve_p15); |
501 | } |
502 | |
503 | bool RegisterInfoPOSIX_arm64::IsSVERegVG(unsigned reg) const { |
504 | return sve_vg == reg; |
505 | } |
506 | |
507 | bool RegisterInfoPOSIX_arm64::IsSMERegZA(unsigned reg) const { |
508 | return reg == m_sme_regnum_collection[2]; |
509 | } |
510 | |
511 | bool RegisterInfoPOSIX_arm64::IsSMERegZT(unsigned reg) const { |
512 | // ZT0 is part of the SME register set only if SME2 is present. |
513 | return m_sme_regnum_collection.size() >= 4 && |
514 | reg == m_sme_regnum_collection[3]; |
515 | } |
516 | |
517 | bool RegisterInfoPOSIX_arm64::IsPAuthReg(unsigned reg) const { |
518 | return llvm::is_contained(Range: pauth_regnum_collection, Element: reg); |
519 | } |
520 | |
521 | bool RegisterInfoPOSIX_arm64::IsMTEReg(unsigned reg) const { |
522 | return llvm::is_contained(Range: m_mte_regnum_collection, Element: reg); |
523 | } |
524 | |
525 | bool RegisterInfoPOSIX_arm64::IsTLSReg(unsigned reg) const { |
526 | return llvm::is_contained(Range: m_tls_regnum_collection, Element: reg); |
527 | } |
528 | |
529 | bool RegisterInfoPOSIX_arm64::IsSMEReg(unsigned reg) const { |
530 | return llvm::is_contained(Range: m_sme_regnum_collection, Element: reg); |
531 | } |
532 | |
533 | uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; } |
534 | |
535 | uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEFFR() const { return sve_ffr; } |
536 | |
537 | uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPCR() const { return fpu_fpcr; } |
538 | |
539 | uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPSR() const { return fpu_fpsr; } |
540 | |
541 | uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEVG() const { return sve_vg; } |
542 | |
543 | uint32_t RegisterInfoPOSIX_arm64::GetRegNumSMESVG() const { |
544 | return m_sme_regnum_collection[1]; |
545 | } |
546 | |
547 | uint32_t RegisterInfoPOSIX_arm64::GetPAuthOffset() const { |
548 | return m_register_info_p[pauth_regnum_collection[0]].byte_offset; |
549 | } |
550 | |
551 | uint32_t RegisterInfoPOSIX_arm64::GetMTEOffset() const { |
552 | return m_register_info_p[m_mte_regnum_collection[0]].byte_offset; |
553 | } |
554 | |
555 | uint32_t RegisterInfoPOSIX_arm64::GetTLSOffset() const { |
556 | return m_register_info_p[m_tls_regnum_collection[0]].byte_offset; |
557 | } |
558 | |
559 | uint32_t RegisterInfoPOSIX_arm64::GetSMEOffset() const { |
560 | return m_register_info_p[m_sme_regnum_collection[0]].byte_offset; |
561 | } |
562 | |