[Lldb-commits] [lldb] 1eaadae - [LLDB][LoongArch] Add unittests for EmulateInstructionLoongArch

Weining Lu via lldb-commits lldb-commits at lists.llvm.org
Thu Jan 12 18:18:54 PST 2023


Author: Hui Li
Date: 2023-01-13T10:17:55+08:00
New Revision: 1eaadaea5090f88d4e26331a5046a1a07f15a6ea

URL: https://github.com/llvm/llvm-project/commit/1eaadaea5090f88d4e26331a5046a1a07f15a6ea
DIFF: https://github.com/llvm/llvm-project/commit/1eaadaea5090f88d4e26331a5046a1a07f15a6ea.diff

LOG: [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

Added: 
    lldb/unittests/Instruction/LoongArch/TestLoongArchEmulator.cpp

Modified: 
    lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
    lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
    lldb/unittests/Instruction/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp b/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
index fb0317acc91af..c17da8b25aa31 100644
--- a/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
+++ b/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
@@ -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();

diff  --git a/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h b/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
index e5193dfad7db0..15da499261b05 100644
--- a/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
+++ b/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.h
@@ -60,6 +60,7 @@ class EmulateInstructionLoongArch : public EmulateInstruction {
   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 {

diff  --git a/lldb/unittests/Instruction/CMakeLists.txt b/lldb/unittests/Instruction/CMakeLists.txt
index 1d011d5f7c5b8..7b1f8afce6b29 100644
--- a/lldb/unittests/Instruction/CMakeLists.txt
+++ b/lldb/unittests/Instruction/CMakeLists.txt
@@ -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
-  )
\ No newline at end of file
+  )

diff  --git a/lldb/unittests/Instruction/LoongArch/TestLoongArchEmulator.cpp b/lldb/unittests/Instruction/LoongArch/TestLoongArchEmulator.cpp
new file mode 100644
index 0000000000000..af16559161507
--- /dev/null
+++ b/lldb/unittests/Instruction/LoongArch/TestLoongArchEmulator.cpp
@@ -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 &reg_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 &reg_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)


        


More information about the lldb-commits mailing list