1 | //===---EmulateInstructionLoongArch.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 <cstdlib> |
10 | #include <optional> |
11 | |
12 | #include "EmulateInstructionLoongArch.h" |
13 | #include "Plugins/Process/Utility/InstructionUtils.h" |
14 | #include "Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h" |
15 | #include "Plugins/Process/Utility/lldb-loongarch-register-enums.h" |
16 | #include "lldb/Core/Address.h" |
17 | #include "lldb/Core/PluginManager.h" |
18 | #include "lldb/Interpreter/OptionValueArray.h" |
19 | #include "lldb/Interpreter/OptionValueDictionary.h" |
20 | #include "lldb/Symbol/UnwindPlan.h" |
21 | #include "lldb/Utility/ArchSpec.h" |
22 | #include "lldb/Utility/LLDBLog.h" |
23 | #include "lldb/Utility/RegisterValue.h" |
24 | #include "lldb/Utility/Stream.h" |
25 | #include "llvm/ADT/STLExtras.h" |
26 | #include "llvm/Support/MathExtras.h" |
27 | |
28 | using namespace lldb; |
29 | using namespace lldb_private; |
30 | |
31 | LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionLoongArch, InstructionLoongArch) |
32 | |
33 | namespace lldb_private { |
34 | |
35 | EmulateInstructionLoongArch::Opcode * |
36 | EmulateInstructionLoongArch::GetOpcodeForInstruction(uint32_t inst) { |
37 | // TODO: Add the mask for other instruction. |
38 | static EmulateInstructionLoongArch::Opcode g_opcodes[] = { |
39 | {.mask: 0xfc000000, .value: 0x40000000, .callback: &EmulateInstructionLoongArch::EmulateBEQZ, |
40 | .name: "beqz rj, offs21" }, |
41 | {.mask: 0xfc000000, .value: 0x44000000, .callback: &EmulateInstructionLoongArch::EmulateBNEZ, |
42 | .name: "bnez rj, offs21" }, |
43 | {.mask: 0xfc000300, .value: 0x48000000, .callback: &EmulateInstructionLoongArch::EmulateBCEQZ, |
44 | .name: "bceqz cj, offs21" }, |
45 | {.mask: 0xfc000300, .value: 0x48000100, .callback: &EmulateInstructionLoongArch::EmulateBCNEZ, |
46 | .name: "bcnez cj, offs21" }, |
47 | {.mask: 0xfc000000, .value: 0x4c000000, .callback: &EmulateInstructionLoongArch::EmulateJIRL, |
48 | .name: "jirl rd, rj, offs16" }, |
49 | {.mask: 0xfc000000, .value: 0x50000000, .callback: &EmulateInstructionLoongArch::EmulateB, |
50 | .name: " b offs26" }, |
51 | {.mask: 0xfc000000, .value: 0x54000000, .callback: &EmulateInstructionLoongArch::EmulateBL, |
52 | .name: "bl offs26" }, |
53 | {.mask: 0xfc000000, .value: 0x58000000, .callback: &EmulateInstructionLoongArch::EmulateBEQ, |
54 | .name: "beq rj, rd, offs16" }, |
55 | {.mask: 0xfc000000, .value: 0x5c000000, .callback: &EmulateInstructionLoongArch::EmulateBNE, |
56 | .name: "bne rj, rd, offs16" }, |
57 | {.mask: 0xfc000000, .value: 0x60000000, .callback: &EmulateInstructionLoongArch::EmulateBLT, |
58 | .name: "blt rj, rd, offs16" }, |
59 | {.mask: 0xfc000000, .value: 0x64000000, .callback: &EmulateInstructionLoongArch::EmulateBGE, |
60 | .name: "bge rj, rd, offs16" }, |
61 | {.mask: 0xfc000000, .value: 0x68000000, .callback: &EmulateInstructionLoongArch::EmulateBLTU, |
62 | .name: "bltu rj, rd, offs16" }, |
63 | {.mask: 0xfc000000, .value: 0x6c000000, .callback: &EmulateInstructionLoongArch::EmulateBGEU, |
64 | .name: "bgeu rj, rd, offs16" }, |
65 | {.mask: 0x00000000, .value: 0x00000000, .callback: &EmulateInstructionLoongArch::EmulateNonJMP, |
66 | .name: "NonJMP" }}; |
67 | static const size_t num_loongarch_opcodes = std::size(g_opcodes); |
68 | |
69 | for (size_t i = 0; i < num_loongarch_opcodes; ++i) |
70 | if ((g_opcodes[i].mask & inst) == g_opcodes[i].value) |
71 | return &g_opcodes[i]; |
72 | return nullptr; |
73 | } |
74 | |
75 | bool EmulateInstructionLoongArch::TestExecute(uint32_t inst) { |
76 | Opcode *opcode_data = GetOpcodeForInstruction(inst); |
77 | if (!opcode_data) |
78 | return false; |
79 | // Call the Emulate... function. |
80 | if (!(this->*opcode_data->callback)(inst)) |
81 | return false; |
82 | return true; |
83 | } |
84 | |
85 | bool EmulateInstructionLoongArch::EvaluateInstruction(uint32_t options) { |
86 | uint32_t inst_size = m_opcode.GetByteSize(); |
87 | uint32_t inst = m_opcode.GetOpcode32(); |
88 | bool increase_pc = options & eEmulateInstructionOptionAutoAdvancePC; |
89 | bool success = false; |
90 | |
91 | Opcode *opcode_data = GetOpcodeForInstruction(inst); |
92 | if (!opcode_data) |
93 | return false; |
94 | |
95 | lldb::addr_t old_pc = 0; |
96 | if (increase_pc) { |
97 | old_pc = ReadPC(success: &success); |
98 | if (!success) |
99 | return false; |
100 | } |
101 | |
102 | // Call the Emulate... function. |
103 | if (!(this->*opcode_data->callback)(inst)) |
104 | return false; |
105 | |
106 | if (increase_pc) { |
107 | lldb::addr_t new_pc = ReadPC(success: &success); |
108 | if (!success) |
109 | return false; |
110 | |
111 | if (new_pc == old_pc && !WritePC(pc: old_pc + inst_size)) |
112 | return false; |
113 | } |
114 | return true; |
115 | } |
116 | |
117 | bool EmulateInstructionLoongArch::ReadInstruction() { |
118 | bool success = false; |
119 | m_addr = ReadPC(success: &success); |
120 | if (!success) { |
121 | m_addr = LLDB_INVALID_ADDRESS; |
122 | return false; |
123 | } |
124 | |
125 | Context ctx; |
126 | ctx.type = eContextReadOpcode; |
127 | ctx.SetNoArgs(); |
128 | uint32_t inst = (uint32_t)ReadMemoryUnsigned(context: ctx, addr: m_addr, byte_size: 4, fail_value: 0, success_ptr: &success); |
129 | m_opcode.SetOpcode32(inst, order: GetByteOrder()); |
130 | |
131 | return true; |
132 | } |
133 | |
134 | lldb::addr_t EmulateInstructionLoongArch::ReadPC(bool *success) { |
135 | return ReadRegisterUnsigned(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, |
136 | LLDB_INVALID_ADDRESS, success_ptr: success); |
137 | } |
138 | |
139 | bool EmulateInstructionLoongArch::WritePC(lldb::addr_t pc) { |
140 | EmulateInstruction::Context ctx; |
141 | ctx.type = eContextAdvancePC; |
142 | ctx.SetNoArgs(); |
143 | return WriteRegisterUnsigned(context: ctx, reg_kind: eRegisterKindGeneric, |
144 | LLDB_REGNUM_GENERIC_PC, reg_value: pc); |
145 | } |
146 | |
147 | std::optional<RegisterInfo> |
148 | EmulateInstructionLoongArch::GetRegisterInfo(lldb::RegisterKind reg_kind, |
149 | uint32_t reg_index) { |
150 | if (reg_kind == eRegisterKindGeneric) { |
151 | switch (reg_index) { |
152 | case LLDB_REGNUM_GENERIC_PC: |
153 | reg_kind = eRegisterKindLLDB; |
154 | reg_index = gpr_pc_loongarch; |
155 | break; |
156 | case LLDB_REGNUM_GENERIC_SP: |
157 | reg_kind = eRegisterKindLLDB; |
158 | reg_index = gpr_sp_loongarch; |
159 | break; |
160 | case LLDB_REGNUM_GENERIC_FP: |
161 | reg_kind = eRegisterKindLLDB; |
162 | reg_index = gpr_fp_loongarch; |
163 | break; |
164 | case LLDB_REGNUM_GENERIC_RA: |
165 | reg_kind = eRegisterKindLLDB; |
166 | reg_index = gpr_ra_loongarch; |
167 | break; |
168 | // We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are |
169 | // supported. |
170 | default: |
171 | llvm_unreachable("unsupported register" ); |
172 | } |
173 | } |
174 | |
175 | const RegisterInfo *array = |
176 | RegisterInfoPOSIX_loongarch64::GetRegisterInfoPtr(target_arch: m_arch); |
177 | const uint32_t length = |
178 | RegisterInfoPOSIX_loongarch64::GetRegisterInfoCount(target_arch: m_arch); |
179 | |
180 | if (reg_index >= length || reg_kind != eRegisterKindLLDB) |
181 | return {}; |
182 | return array[reg_index]; |
183 | } |
184 | |
185 | bool EmulateInstructionLoongArch::SetTargetTriple(const ArchSpec &arch) { |
186 | return SupportsThisArch(arch); |
187 | } |
188 | |
189 | bool EmulateInstructionLoongArch::TestEmulation( |
190 | Stream &out_stream, ArchSpec &arch, OptionValueDictionary *test_data) { |
191 | return false; |
192 | } |
193 | |
194 | void EmulateInstructionLoongArch::Initialize() { |
195 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
196 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance); |
197 | } |
198 | |
199 | void EmulateInstructionLoongArch::Terminate() { |
200 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
201 | } |
202 | |
203 | lldb_private::EmulateInstruction * |
204 | EmulateInstructionLoongArch::CreateInstance(const ArchSpec &arch, |
205 | InstructionType inst_type) { |
206 | if (EmulateInstructionLoongArch::SupportsThisInstructionType(inst_type) && |
207 | SupportsThisArch(arch)) |
208 | return new EmulateInstructionLoongArch(arch); |
209 | return nullptr; |
210 | } |
211 | |
212 | bool EmulateInstructionLoongArch::SupportsThisArch(const ArchSpec &arch) { |
213 | return arch.GetTriple().isLoongArch(); |
214 | } |
215 | |
216 | bool EmulateInstructionLoongArch::EmulateBEQZ(uint32_t inst) { |
217 | return IsLoongArch64() ? EmulateBEQZ64(inst) : false; |
218 | } |
219 | |
220 | bool EmulateInstructionLoongArch::EmulateBNEZ(uint32_t inst) { |
221 | return IsLoongArch64() ? EmulateBNEZ64(inst) : false; |
222 | } |
223 | |
224 | bool EmulateInstructionLoongArch::EmulateBCEQZ(uint32_t inst) { |
225 | return IsLoongArch64() ? EmulateBCEQZ64(inst) : false; |
226 | } |
227 | |
228 | bool EmulateInstructionLoongArch::EmulateBCNEZ(uint32_t inst) { |
229 | return IsLoongArch64() ? EmulateBCNEZ64(inst) : false; |
230 | } |
231 | |
232 | bool EmulateInstructionLoongArch::EmulateJIRL(uint32_t inst) { |
233 | return IsLoongArch64() ? EmulateJIRL64(inst) : false; |
234 | } |
235 | |
236 | bool EmulateInstructionLoongArch::EmulateB(uint32_t inst) { |
237 | return IsLoongArch64() ? EmulateB64(inst) : false; |
238 | } |
239 | |
240 | bool EmulateInstructionLoongArch::EmulateBL(uint32_t inst) { |
241 | return IsLoongArch64() ? EmulateBL64(inst) : false; |
242 | } |
243 | |
244 | bool EmulateInstructionLoongArch::EmulateBEQ(uint32_t inst) { |
245 | return IsLoongArch64() ? EmulateBEQ64(inst) : false; |
246 | } |
247 | |
248 | bool EmulateInstructionLoongArch::EmulateBNE(uint32_t inst) { |
249 | return IsLoongArch64() ? EmulateBNE64(inst) : false; |
250 | } |
251 | |
252 | bool EmulateInstructionLoongArch::EmulateBLT(uint32_t inst) { |
253 | return IsLoongArch64() ? EmulateBLT64(inst) : false; |
254 | } |
255 | |
256 | bool EmulateInstructionLoongArch::EmulateBGE(uint32_t inst) { |
257 | return IsLoongArch64() ? EmulateBGE64(inst) : false; |
258 | } |
259 | |
260 | bool EmulateInstructionLoongArch::EmulateBLTU(uint32_t inst) { |
261 | return IsLoongArch64() ? EmulateBLTU64(inst) : false; |
262 | } |
263 | |
264 | bool EmulateInstructionLoongArch::EmulateBGEU(uint32_t inst) { |
265 | return IsLoongArch64() ? EmulateBGEU64(inst) : false; |
266 | } |
267 | |
268 | bool EmulateInstructionLoongArch::EmulateNonJMP(uint32_t inst) { return false; } |
269 | |
270 | // beqz rj, offs21 |
271 | // if GR[rj] == 0: |
272 | // PC = PC + SignExtend({offs21, 2'b0}, GRLEN) |
273 | bool EmulateInstructionLoongArch::EmulateBEQZ64(uint32_t inst) { |
274 | bool success = false; |
275 | uint32_t rj = Bits32(bits: inst, msbit: 9, lsbit: 5); |
276 | uint64_t pc = ReadPC(success: &success); |
277 | if (!success) |
278 | return false; |
279 | uint32_t offs21 = Bits32(bits: inst, msbit: 25, lsbit: 10) + (Bits32(bits: inst, msbit: 4, lsbit: 0) << 16); |
280 | uint64_t rj_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rj, fail_value: 0, success_ptr: &success); |
281 | if (!success) |
282 | return false; |
283 | if (rj_val == 0) { |
284 | uint64_t next_pc = pc + llvm::SignExtend64<23>(x: offs21 << 2); |
285 | return WritePC(pc: next_pc); |
286 | } else |
287 | return WritePC(pc: pc + 4); |
288 | } |
289 | |
290 | // bnez rj, offs21 |
291 | // if GR[rj] != 0: |
292 | // PC = PC + SignExtend({offs21, 2'b0}, GRLEN) |
293 | bool EmulateInstructionLoongArch::EmulateBNEZ64(uint32_t inst) { |
294 | bool success = false; |
295 | uint32_t rj = Bits32(bits: inst, msbit: 9, lsbit: 5); |
296 | uint64_t pc = ReadPC(success: &success); |
297 | if (!success) |
298 | return false; |
299 | uint32_t offs21 = Bits32(bits: inst, msbit: 25, lsbit: 10) + (Bits32(bits: inst, msbit: 4, lsbit: 0) << 16); |
300 | uint64_t rj_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rj, fail_value: 0, success_ptr: &success); |
301 | if (!success) |
302 | return false; |
303 | if (rj_val != 0) { |
304 | uint64_t next_pc = pc + llvm::SignExtend64<23>(x: offs21 << 2); |
305 | return WritePC(pc: next_pc); |
306 | } else |
307 | return WritePC(pc: pc + 4); |
308 | } |
309 | |
310 | // bceqz cj, offs21 |
311 | // if CFR[cj] == 0: |
312 | // PC = PC + SignExtend({offs21, 2'b0}, GRLEN) |
313 | bool EmulateInstructionLoongArch::EmulateBCEQZ64(uint32_t inst) { |
314 | bool success = false; |
315 | uint32_t cj = Bits32(bits: inst, msbit: 7, lsbit: 5) + fpr_fcc0_loongarch; |
316 | uint64_t pc = ReadPC(success: &success); |
317 | if (!success) |
318 | return false; |
319 | uint32_t offs21 = Bits32(bits: inst, msbit: 25, lsbit: 10) + (Bits32(bits: inst, msbit: 4, lsbit: 0) << 16); |
320 | uint8_t cj_val = |
321 | (uint8_t)ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: cj, fail_value: 0, success_ptr: &success); |
322 | if (!success) |
323 | return false; |
324 | if (cj_val == 0) { |
325 | uint64_t next_pc = pc + llvm::SignExtend64<23>(x: offs21 << 2); |
326 | return WritePC(pc: next_pc); |
327 | } else |
328 | return WritePC(pc: pc + 4); |
329 | return false; |
330 | } |
331 | |
332 | // bcnez cj, offs21 |
333 | // if CFR[cj] != 0: |
334 | // PC = PC + SignExtend({offs21, 2'b0}, GRLEN) |
335 | bool EmulateInstructionLoongArch::EmulateBCNEZ64(uint32_t inst) { |
336 | bool success = false; |
337 | uint32_t cj = Bits32(bits: inst, msbit: 7, lsbit: 5) + fpr_fcc0_loongarch; |
338 | uint64_t pc = ReadPC(success: &success); |
339 | if (!success) |
340 | return false; |
341 | uint32_t offs21 = Bits32(bits: inst, msbit: 25, lsbit: 10) + (Bits32(bits: inst, msbit: 4, lsbit: 0) << 16); |
342 | uint8_t cj_val = |
343 | (uint8_t)ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: cj, fail_value: 0, success_ptr: &success); |
344 | if (!success) |
345 | return false; |
346 | if (cj_val != 0) { |
347 | uint64_t next_pc = pc + llvm::SignExtend64<23>(x: offs21 << 2); |
348 | return WritePC(pc: next_pc); |
349 | } else |
350 | return WritePC(pc: pc + 4); |
351 | return false; |
352 | } |
353 | |
354 | // jirl rd, rj, offs16 |
355 | // GR[rd] = PC + 4 |
356 | // PC = GR[rj] + SignExtend({offs16, 2'b0}, GRLEN) |
357 | bool EmulateInstructionLoongArch::EmulateJIRL64(uint32_t inst) { |
358 | uint32_t rj = Bits32(bits: inst, msbit: 9, lsbit: 5); |
359 | uint32_t rd = Bits32(bits: inst, msbit: 4, lsbit: 0); |
360 | bool success = false; |
361 | uint64_t pc = ReadPC(success: &success); |
362 | if (!success) |
363 | return false; |
364 | EmulateInstruction::Context ctx; |
365 | if (!WriteRegisterUnsigned(context: ctx, reg_kind: eRegisterKindLLDB, reg_num: rd, reg_value: pc + 4)) |
366 | return false; |
367 | uint64_t rj_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rj, fail_value: 0, success_ptr: &success); |
368 | if (!success) |
369 | return false; |
370 | uint64_t next_pc = rj_val + llvm::SignExtend64<18>(x: Bits32(bits: inst, msbit: 25, lsbit: 10) << 2); |
371 | return WritePC(pc: next_pc); |
372 | } |
373 | |
374 | // b offs26 |
375 | // PC = PC + SignExtend({offs26, 2' b0}, GRLEN) |
376 | bool EmulateInstructionLoongArch::EmulateB64(uint32_t inst) { |
377 | bool success = false; |
378 | uint64_t pc = ReadPC(success: &success); |
379 | if (!success) |
380 | return false; |
381 | uint32_t offs26 = Bits32(bits: inst, msbit: 25, lsbit: 10) + (Bits32(bits: inst, msbit: 9, lsbit: 0) << 16); |
382 | uint64_t next_pc = pc + llvm::SignExtend64<28>(x: offs26 << 2); |
383 | return WritePC(pc: next_pc); |
384 | } |
385 | |
386 | // bl offs26 |
387 | // GR[1] = PC + 4 |
388 | // PC = PC + SignExtend({offs26, 2'b0}, GRLEN) |
389 | bool EmulateInstructionLoongArch::EmulateBL64(uint32_t inst) { |
390 | bool success = false; |
391 | uint64_t pc = ReadPC(success: &success); |
392 | if (!success) |
393 | return false; |
394 | EmulateInstruction::Context ctx; |
395 | if (!WriteRegisterUnsigned(context: ctx, reg_kind: eRegisterKindLLDB, reg_num: gpr_r1_loongarch, reg_value: pc + 4)) |
396 | return false; |
397 | uint32_t offs26 = Bits32(bits: inst, msbit: 25, lsbit: 10) + (Bits32(bits: inst, msbit: 9, lsbit: 0) << 16); |
398 | uint64_t next_pc = pc + llvm::SignExtend64<28>(x: offs26 << 2); |
399 | return WritePC(pc: next_pc); |
400 | } |
401 | |
402 | // beq rj, rd, offs16 |
403 | // if GR[rj] == GR[rd]: |
404 | // PC = PC + SignExtend({offs16, 2'b0}, GRLEN) |
405 | bool EmulateInstructionLoongArch::EmulateBEQ64(uint32_t inst) { |
406 | bool success = false; |
407 | uint32_t rj = Bits32(bits: inst, msbit: 9, lsbit: 5); |
408 | uint32_t rd = Bits32(bits: inst, msbit: 4, lsbit: 0); |
409 | uint64_t pc = ReadPC(success: &success); |
410 | if (!success) |
411 | return false; |
412 | uint64_t rj_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rj, fail_value: 0, success_ptr: &success); |
413 | if (!success) |
414 | return false; |
415 | uint64_t rd_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rd, fail_value: 0, success_ptr: &success); |
416 | if (!success) |
417 | return false; |
418 | if (rj_val == rd_val) { |
419 | uint64_t next_pc = pc + llvm::SignExtend64<18>(x: Bits32(bits: inst, msbit: 25, lsbit: 10) << 2); |
420 | return WritePC(pc: next_pc); |
421 | } else |
422 | return WritePC(pc: pc + 4); |
423 | } |
424 | |
425 | // bne rj, rd, offs16 |
426 | // if GR[rj] != GR[rd]: |
427 | // PC = PC + SignExtend({offs16, 2'b0}, GRLEN) |
428 | bool EmulateInstructionLoongArch::EmulateBNE64(uint32_t inst) { |
429 | bool success = false; |
430 | uint32_t rj = Bits32(bits: inst, msbit: 9, lsbit: 5); |
431 | uint32_t rd = Bits32(bits: inst, msbit: 4, lsbit: 0); |
432 | uint64_t pc = ReadPC(success: &success); |
433 | if (!success) |
434 | return false; |
435 | uint64_t rj_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rj, fail_value: 0, success_ptr: &success); |
436 | if (!success) |
437 | return false; |
438 | uint64_t rd_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rd, fail_value: 0, success_ptr: &success); |
439 | if (!success) |
440 | return false; |
441 | if (rj_val != rd_val) { |
442 | uint64_t next_pc = pc + llvm::SignExtend64<18>(x: Bits32(bits: inst, msbit: 25, lsbit: 10) << 2); |
443 | return WritePC(pc: next_pc); |
444 | } else |
445 | return WritePC(pc: pc + 4); |
446 | } |
447 | |
448 | // blt rj, rd, offs16 |
449 | // if signed(GR[rj]) < signed(GR[rd]): |
450 | // PC = PC + SignExtend({offs16, 2'b0}, GRLEN) |
451 | bool EmulateInstructionLoongArch::EmulateBLT64(uint32_t inst) { |
452 | bool success = false; |
453 | uint32_t rj = Bits32(bits: inst, msbit: 9, lsbit: 5); |
454 | uint32_t rd = Bits32(bits: inst, msbit: 4, lsbit: 0); |
455 | uint64_t pc = ReadPC(success: &success); |
456 | if (!success) |
457 | return false; |
458 | int64_t rj_val = |
459 | (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rj, fail_value: 0, success_ptr: &success); |
460 | if (!success) |
461 | return false; |
462 | int64_t rd_val = |
463 | (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rd, fail_value: 0, success_ptr: &success); |
464 | if (!success) |
465 | return false; |
466 | if (rj_val < rd_val) { |
467 | uint64_t next_pc = pc + llvm::SignExtend64<18>(x: Bits32(bits: inst, msbit: 25, lsbit: 10) << 2); |
468 | return WritePC(pc: next_pc); |
469 | } else |
470 | return WritePC(pc: pc + 4); |
471 | } |
472 | |
473 | // bge rj, rd, offs16 |
474 | // if signed(GR[rj]) >= signed(GR[rd]): |
475 | // PC = PC + SignExtend({offs16, 2'b0}, GRLEN) |
476 | bool EmulateInstructionLoongArch::EmulateBGE64(uint32_t inst) { |
477 | bool success = false; |
478 | uint32_t rj = Bits32(bits: inst, msbit: 9, lsbit: 5); |
479 | uint32_t rd = Bits32(bits: inst, msbit: 4, lsbit: 0); |
480 | uint64_t pc = ReadPC(success: &success); |
481 | if (!success) |
482 | return false; |
483 | int64_t rj_val = |
484 | (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rj, fail_value: 0, success_ptr: &success); |
485 | if (!success) |
486 | return false; |
487 | int64_t rd_val = |
488 | (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rd, fail_value: 0, success_ptr: &success); |
489 | if (!success) |
490 | return false; |
491 | if (rj_val >= rd_val) { |
492 | uint64_t next_pc = pc + llvm::SignExtend64<18>(x: Bits32(bits: inst, msbit: 25, lsbit: 10) << 2); |
493 | return WritePC(pc: next_pc); |
494 | } else |
495 | return WritePC(pc: pc + 4); |
496 | } |
497 | |
498 | // bltu rj, rd, offs16 |
499 | // if unsigned(GR[rj]) < unsigned(GR[rd]): |
500 | // PC = PC + SignExtend({offs16, 2'b0}, GRLEN) |
501 | bool EmulateInstructionLoongArch::EmulateBLTU64(uint32_t inst) { |
502 | bool success = false; |
503 | uint32_t rj = Bits32(bits: inst, msbit: 9, lsbit: 5); |
504 | uint32_t rd = Bits32(bits: inst, msbit: 4, lsbit: 0); |
505 | uint64_t pc = ReadPC(success: &success); |
506 | if (!success) |
507 | return false; |
508 | uint64_t rj_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rj, fail_value: 0, success_ptr: &success); |
509 | if (!success) |
510 | return false; |
511 | uint64_t rd_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rd, fail_value: 0, success_ptr: &success); |
512 | if (!success) |
513 | return false; |
514 | if (rj_val < rd_val) { |
515 | uint64_t next_pc = pc + llvm::SignExtend64<18>(x: Bits32(bits: inst, msbit: 25, lsbit: 10) << 2); |
516 | return WritePC(pc: next_pc); |
517 | } else |
518 | return WritePC(pc: pc + 4); |
519 | } |
520 | |
521 | // bgeu rj, rd, offs16 |
522 | // if unsigned(GR[rj]) >= unsigned(GR[rd]): |
523 | // PC = PC + SignExtend({offs16, 2'b0}, GRLEN) |
524 | bool EmulateInstructionLoongArch::EmulateBGEU64(uint32_t inst) { |
525 | bool success = false; |
526 | uint32_t rj = Bits32(bits: inst, msbit: 9, lsbit: 5); |
527 | uint32_t rd = Bits32(bits: inst, msbit: 4, lsbit: 0); |
528 | uint64_t pc = ReadPC(success: &success); |
529 | if (!success) |
530 | return false; |
531 | uint64_t rj_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rj, fail_value: 0, success_ptr: &success); |
532 | if (!success) |
533 | return false; |
534 | uint64_t rd_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: rd, fail_value: 0, success_ptr: &success); |
535 | if (!success) |
536 | return false; |
537 | if (rj_val >= rd_val) { |
538 | uint64_t next_pc = pc + llvm::SignExtend64<18>(x: Bits32(bits: inst, msbit: 25, lsbit: 10) << 2); |
539 | return WritePC(pc: next_pc); |
540 | } else |
541 | return WritePC(pc: pc + 4); |
542 | } |
543 | |
544 | } // namespace lldb_private |
545 | |