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