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