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