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