mirror of
https://github.com/intel/llvm.git
synced 2026-02-01 17:07:36 +08:00
[LLDB][LoongArch] Add unittests for EmulateInstructionLoongArch
Add unit tests For EmulateInstructionLoongArch existing branch instruction. Add 19 test cases in total. Without this patch: ``` $ ninja check-lldb-unit [0/1] Running lldb unit test suite Testing Time: 10.55s Passed: 1025 ``` With this patch: ``` $ ninja check-lldb-unit [0/1] Running lldb unit test suite Testing Time: 10.45s Passed: 1044 ``` Reviewed By: DavidSpickett Differential Revision: https://reviews.llvm.org/D140386
This commit is contained in:
@@ -68,6 +68,16 @@ EmulateInstructionLoongArch::GetOpcodeForInstruction(uint32_t inst) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool EmulateInstructionLoongArch::TestExecute(uint32_t inst) {
|
||||
Opcode *opcode_data = GetOpcodeForInstruction(inst);
|
||||
if (!opcode_data)
|
||||
return false;
|
||||
// Call the Emulate... function.
|
||||
if (!(this->*opcode_data->callback)(inst))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmulateInstructionLoongArch::EvaluateInstruction(uint32_t options) {
|
||||
uint32_t inst_size = m_opcode.GetByteSize();
|
||||
uint32_t inst = m_opcode.GetOpcode32();
|
||||
|
||||
@@ -60,6 +60,7 @@ public:
|
||||
lldb::addr_t ReadPC(bool *success);
|
||||
bool WritePC(lldb::addr_t pc);
|
||||
bool IsLoongArch64() { return m_arch_subtype == llvm::Triple::loongarch64; }
|
||||
bool TestExecute(uint32_t inst);
|
||||
|
||||
private:
|
||||
struct Opcode {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
add_lldb_unittest(EmulatorTests
|
||||
ARM64/TestAArch64Emulator.cpp
|
||||
LoongArch/TestLoongArchEmulator.cpp
|
||||
RISCV/TestRISCVEmulator.cpp
|
||||
|
||||
LINK_LIBS
|
||||
@@ -7,8 +8,9 @@ add_lldb_unittest(EmulatorTests
|
||||
lldbSymbol
|
||||
lldbTarget
|
||||
lldbPluginInstructionARM64
|
||||
lldbPluginInstructionLoongArch
|
||||
lldbPluginInstructionRISCV
|
||||
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
)
|
||||
)
|
||||
|
||||
230
lldb/unittests/Instruction/LoongArch/TestLoongArchEmulator.cpp
Normal file
230
lldb/unittests/Instruction/LoongArch/TestLoongArchEmulator.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
//===-- TestLoongArchEmulator.cpp -----------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lldb/Core/Address.h"
|
||||
#include "lldb/Core/Disassembler.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Utility/ArchSpec.h"
|
||||
#include "lldb/Utility/RegisterValue.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h"
|
||||
#include "Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h"
|
||||
#include "Plugins/Process/Utility/lldb-loongarch-register-enums.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
#define GEN_BCOND_TEST(bit, name, rj_val, rd_val_branched, rd_val_continued) \
|
||||
TEST_F(LoongArch##bit##EmulatorTester, test##name##branched) { \
|
||||
testBcondBranch(this, name, true, rj_val, rd_val_branched); \
|
||||
} \
|
||||
TEST_F(LoongArch##bit##EmulatorTester, test##name##continued) { \
|
||||
testBcondBranch(this, name, false, rj_val, rd_val_continued); \
|
||||
}
|
||||
|
||||
#define GEN_BZCOND_TEST(bit, name, rj_val_branched, rj_val_continued) \
|
||||
TEST_F(LoongArch##bit##EmulatorTester, test##name##branched) { \
|
||||
testBZcondBranch(this, name, true, rj_val_branched); \
|
||||
} \
|
||||
TEST_F(LoongArch##bit##EmulatorTester, test##name##continued) { \
|
||||
testBZcondBranch(this, name, false, rj_val_continued); \
|
||||
}
|
||||
|
||||
struct LoongArch64EmulatorTester : public EmulateInstructionLoongArch,
|
||||
testing::Test {
|
||||
RegisterInfoPOSIX_loongarch64::GPR gpr;
|
||||
RegisterInfoPOSIX_loongarch64::FPR fpr;
|
||||
|
||||
LoongArch64EmulatorTester(
|
||||
std::string triple = "loongarch64-unknown-linux-gnu")
|
||||
: EmulateInstructionLoongArch(ArchSpec(triple)) {
|
||||
EmulateInstruction::SetReadRegCallback(ReadRegisterCallback);
|
||||
EmulateInstruction::SetWriteRegCallback(WriteRegisterCallback);
|
||||
}
|
||||
|
||||
static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
|
||||
const RegisterInfo *reg_info,
|
||||
RegisterValue ®_value) {
|
||||
LoongArch64EmulatorTester *tester =
|
||||
(LoongArch64EmulatorTester *)instruction;
|
||||
uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
|
||||
if (reg >= gpr_r0_loongarch && reg <= gpr_r31_loongarch)
|
||||
reg_value.SetUInt(tester->gpr.gpr[reg], reg_info->byte_size);
|
||||
else if (reg == gpr_orig_a0_loongarch)
|
||||
reg_value.SetUInt(tester->gpr.orig_a0, reg_info->byte_size);
|
||||
else if (reg == gpr_pc_loongarch)
|
||||
reg_value.SetUInt(tester->gpr.csr_era, reg_info->byte_size);
|
||||
else if (reg == gpr_badv_loongarch)
|
||||
reg_value.SetUInt(tester->gpr.csr_badv, reg_info->byte_size);
|
||||
else if (reg == fpr_first_loongarch + 32)
|
||||
// fcc0
|
||||
reg_value.SetUInt(tester->fpr.fcc, reg_info->byte_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool WriteRegisterCallback(EmulateInstruction *instruction,
|
||||
void *baton, const Context &context,
|
||||
const RegisterInfo *reg_info,
|
||||
const RegisterValue ®_value) {
|
||||
LoongArch64EmulatorTester *tester =
|
||||
(LoongArch64EmulatorTester *)instruction;
|
||||
uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
|
||||
if (reg >= gpr_r0_loongarch && reg <= gpr_r31_loongarch)
|
||||
tester->gpr.gpr[reg] = reg_value.GetAsUInt64();
|
||||
else if (reg == gpr_orig_a0_loongarch)
|
||||
tester->gpr.orig_a0 = reg_value.GetAsUInt64();
|
||||
else if (reg == gpr_pc_loongarch)
|
||||
tester->gpr.csr_era = reg_value.GetAsUInt64();
|
||||
else if (reg == gpr_badv_loongarch)
|
||||
tester->gpr.csr_badv = reg_value.GetAsUInt64();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// BEQ BNE BLT BGE BLTU BGEU
|
||||
static uint32_t EncodeBcondType(uint32_t opcode, uint32_t rj, uint32_t rd,
|
||||
uint32_t offs16) {
|
||||
offs16 = offs16 & 0x0000ffff;
|
||||
return opcode << 26 | offs16 << 10 | rj << 5 | rd;
|
||||
}
|
||||
|
||||
static uint32_t BEQ(uint32_t rj, uint32_t rd, int32_t offs16) {
|
||||
return EncodeBcondType(0b010110, rj, rd, uint32_t(offs16));
|
||||
}
|
||||
|
||||
static uint32_t BNE(uint32_t rj, uint32_t rd, int32_t offs16) {
|
||||
return EncodeBcondType(0b010111, rj, rd, uint32_t(offs16));
|
||||
}
|
||||
|
||||
static uint32_t BLT(uint32_t rj, uint32_t rd, int32_t offs16) {
|
||||
return EncodeBcondType(0b011000, rj, rd, uint32_t(offs16));
|
||||
}
|
||||
|
||||
static uint32_t BGE(uint32_t rj, uint32_t rd, int32_t offs16) {
|
||||
return EncodeBcondType(0b011001, rj, rd, uint32_t(offs16));
|
||||
}
|
||||
|
||||
static uint32_t BLTU(uint32_t rj, uint32_t rd, int32_t offs16) {
|
||||
return EncodeBcondType(0b011010, rj, rd, uint32_t(offs16));
|
||||
}
|
||||
|
||||
static uint32_t BGEU(uint32_t rj, uint32_t rd, int32_t offs16) {
|
||||
return EncodeBcondType(0b011011, rj, rd, uint32_t(offs16));
|
||||
}
|
||||
|
||||
// BEQZ BNEZ
|
||||
static uint32_t EncodeBZcondType(uint32_t opcode, uint32_t rj,
|
||||
uint32_t offs21) {
|
||||
uint32_t offs20_16 = (offs21 & 0x001f0000) >> 16;
|
||||
uint32_t offs15_0 = offs21 & 0x0000ffff;
|
||||
return opcode << 26 | offs15_0 << 10 | rj << 5 | offs20_16;
|
||||
}
|
||||
|
||||
static uint32_t BEQZ(uint32_t rj, int32_t offs21) {
|
||||
return EncodeBZcondType(0b010000, rj, uint32_t(offs21));
|
||||
}
|
||||
|
||||
static uint32_t BNEZ(uint32_t rj, int32_t offs21) {
|
||||
return EncodeBZcondType(0b010001, rj, uint32_t(offs21));
|
||||
}
|
||||
|
||||
using EncoderBcond = uint32_t (*)(uint32_t rj, uint32_t rd, int32_t offs16);
|
||||
using EncoderBZcond = uint32_t (*)(uint32_t rj, int32_t offs21);
|
||||
|
||||
TEST_F(LoongArch64EmulatorTester, testJIRL) {
|
||||
bool success = false;
|
||||
addr_t old_pc = 0x12000600;
|
||||
WritePC(old_pc);
|
||||
// JIRL r1, r12, 0x10
|
||||
// | 31 26 | 25 15 | 9 5 | 4 0 |
|
||||
// | 0 1 0 0 1 1 | 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 | 0 1 1 0 0 | 0 0 0 0 1 |
|
||||
uint32_t inst = 0b01001100000000000100000110000001;
|
||||
uint32_t offs16 = 0x10;
|
||||
gpr.gpr[12] = 0x12000400;
|
||||
ASSERT_TRUE(TestExecute(inst));
|
||||
auto r1 = gpr.gpr[1];
|
||||
auto pc = ReadPC(&success);
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(r1, old_pc + 4);
|
||||
ASSERT_EQ(pc, gpr.gpr[12] + (offs16 * 4));
|
||||
}
|
||||
|
||||
TEST_F(LoongArch64EmulatorTester, testB) {
|
||||
bool success = false;
|
||||
addr_t old_pc = 0x12000600;
|
||||
WritePC(old_pc);
|
||||
// B 0x10010
|
||||
// | 31 26 | 25 10 | 9 0 |
|
||||
// | 0 1 0 1 0 0 | 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 | 0 0 0 0 0 0 0 0 0 1 |
|
||||
uint32_t inst = 0b01010000000000000100000000000001;
|
||||
uint32_t offs26 = 0x10010;
|
||||
ASSERT_TRUE(TestExecute(inst));
|
||||
auto pc = ReadPC(&success);
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(pc, old_pc + (offs26 * 4));
|
||||
}
|
||||
|
||||
TEST_F(LoongArch64EmulatorTester, testBL) {
|
||||
bool success = false;
|
||||
addr_t old_pc = 0x12000600;
|
||||
WritePC(old_pc);
|
||||
// BL 0x10010
|
||||
// | 31 26 | 25 10 | 9 0 |
|
||||
// | 0 1 0 1 0 1 | 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 | 0 0 0 0 0 0 0 0 0 1 |
|
||||
uint32_t inst = 0b01010100000000000100000000000001;
|
||||
uint32_t offs26 = 0x10010;
|
||||
ASSERT_TRUE(TestExecute(inst));
|
||||
auto r1 = gpr.gpr[1];
|
||||
auto pc = ReadPC(&success);
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(r1, old_pc + 4);
|
||||
ASSERT_EQ(pc, old_pc + (offs26 * 4));
|
||||
}
|
||||
|
||||
static void testBcondBranch(LoongArch64EmulatorTester *tester,
|
||||
EncoderBcond encoder, bool branched,
|
||||
uint64_t rj_val, uint64_t rd_val) {
|
||||
bool success = false;
|
||||
addr_t old_pc = 0x12000600;
|
||||
tester->WritePC(old_pc);
|
||||
tester->gpr.gpr[12] = rj_val;
|
||||
tester->gpr.gpr[13] = rd_val;
|
||||
// b<cmp> r12, r13, (-256)
|
||||
uint32_t inst = encoder(12, 13, -256);
|
||||
ASSERT_TRUE(tester->TestExecute(inst));
|
||||
auto pc = tester->ReadPC(&success);
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(pc, old_pc + (branched ? (-256 * 4) : 4));
|
||||
}
|
||||
|
||||
static void testBZcondBranch(LoongArch64EmulatorTester *tester,
|
||||
EncoderBZcond encoder, bool branched,
|
||||
uint64_t rj_val) {
|
||||
bool success = false;
|
||||
addr_t old_pc = 0x12000600;
|
||||
tester->WritePC(old_pc);
|
||||
tester->gpr.gpr[4] = rj_val;
|
||||
// b<cmp>z r4, (-256)
|
||||
uint32_t inst = encoder(4, -256);
|
||||
ASSERT_TRUE(tester->TestExecute(inst));
|
||||
auto pc = tester->ReadPC(&success);
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(pc, old_pc + (branched ? (-256 * 4) : 4));
|
||||
}
|
||||
|
||||
GEN_BCOND_TEST(64, BEQ, 1, 1, 0)
|
||||
GEN_BCOND_TEST(64, BNE, 1, 0, 1)
|
||||
GEN_BCOND_TEST(64, BLT, -2, 1, -3)
|
||||
GEN_BCOND_TEST(64, BGE, -2, -3, 1)
|
||||
GEN_BCOND_TEST(64, BLTU, -2, -1, 1)
|
||||
GEN_BCOND_TEST(64, BGEU, -2, 1, -1)
|
||||
GEN_BZCOND_TEST(64, BEQZ, 0, 1)
|
||||
GEN_BZCOND_TEST(64, BNEZ, 1, 0)
|
||||
Reference in New Issue
Block a user