[Lldb-commits] [lldb] [llvm] [lldb][RISCV] function calls support in lldb expressions (PR #99336)

via lldb-commits lldb-commits at lists.llvm.org
Tue Sep 10 10:12:14 PDT 2024


https://github.com/dlav-sc updated https://github.com/llvm/llvm-project/pull/99336

>From 71986c7633f6f2d8e8e8ed5dba332c822204d211 Mon Sep 17 00:00:00 2001
From: Daniil Avdeev <daniil.avdeev at syntacore.com>
Date: Thu, 11 Jul 2024 11:21:36 +0000
Subject: [PATCH 1/5] [lldb][RISCV] add jitted function calls to ABI

Function calls support in LLDB expressions for RISCV: 1 of 5

Augments corresponding functionality to RISCV ABI, which allows to jit
lldb expressions and thus make function calls inside them. Only function
calls with integer and void function arguments and return value are
supported.
---
 .../Plugins/ABI/RISCV/ABISysV_riscv.cpp       | 88 +++++++++++++++++--
 lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h |  3 +
 2 files changed, 84 insertions(+), 7 deletions(-)

diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
index de304183f67175..02f9fae57c5fba 100644
--- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
+++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
@@ -10,7 +10,9 @@
 
 #include <array>
 #include <limits>
+#include <sstream>
 
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/IR/DerivedTypes.h"
 
 #include "Utility/RISCV_DWARF_Registers.h"
@@ -20,6 +22,7 @@
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Target/Thread.h"
+#include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/RegisterValue.h"
 
 #define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString()
@@ -164,11 +167,82 @@ TotalArgsSizeInWords(bool is_rv64,
   return total_size;
 }
 
+static bool UpdateRegister(RegisterContext *reg_ctx,
+                           const lldb::RegisterKind reg_kind,
+                           const uint32_t reg_num, const addr_t value) {
+  Log *log = GetLog(LLDBLog::Expressions);
+
+  const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(reg_kind, reg_num);
+
+  LLDB_LOG(log, "Writing {0}: 0x{1:x}", reg_info->name,
+           static_cast<uint64_t>(value));
+  if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, value)) {
+    LLDB_LOG(log, "Writing {0}: failed", reg_info->name);
+    return false;
+  }
+  return true;
+}
+
+static void LogInitInfo(Log *log, const Thread &thread, addr_t sp,
+                        addr_t func_addr, addr_t return_addr,
+                        const llvm::ArrayRef<addr_t> args) {
+  assert(log);
+  std::stringstream ss;
+  ss << "ABISysV_riscv::PrepareTrivialCall"
+     << " (tid = 0x" << std::hex << thread.GetID() << ", sp = 0x" << sp
+     << ", func_addr = 0x" << func_addr << ", return_addr = 0x" << return_addr;
+
+  for (auto &&[idx, arg] : enumerate(args))
+    ss << ", arg" << std::dec << idx << " = 0x" << std::hex << arg;
+  ss << ")";
+  log->PutString(ss.str());
+}
+
 bool ABISysV_riscv::PrepareTrivialCall(Thread &thread, addr_t sp,
                                        addr_t func_addr, addr_t return_addr,
                                        llvm::ArrayRef<addr_t> args) const {
-  // TODO: Implement
-  return false;
+  Log *log = GetLog(LLDBLog::Expressions);
+  if (log)
+    LogInitInfo(log, thread, sp, func_addr, return_addr, args);
+
+  const auto reg_ctx_sp = thread.GetRegisterContext();
+  if (!reg_ctx_sp) {
+    LLDB_LOG(log, "Failed to get RegisterContext");
+    return false;
+  }
+
+  if (args.size() > s_regs_for_args_count) {
+    LLDB_LOG(log, "Function has {0} arguments, but only {1} are allowed!",
+             args.size(), s_regs_for_args_count);
+    return false;
+  }
+
+  // Write arguments to registers
+  for (auto &&[idx, arg] : enumerate(args)) {
+    const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfo(
+        eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + idx);
+    LLDB_LOG(log, "About to write arg{0} (0x{1:x}) into {2}", idx, arg,
+             reg_info->name);
+
+    if (!reg_ctx_sp->WriteRegisterFromUnsigned(reg_info, arg)) {
+      LLDB_LOG(log, "Failed to write arg{0} (0x{1:x}) into {2}", idx, arg,
+               reg_info->name);
+      return false;
+    }
+  }
+
+  if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric,
+                      LLDB_REGNUM_GENERIC_PC, func_addr))
+    return false;
+  if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric,
+                      LLDB_REGNUM_GENERIC_SP, sp))
+    return false;
+  if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric,
+                      LLDB_REGNUM_GENERIC_RA, return_addr))
+    return false;
+
+  LLDB_LOG(log, "ABISysV_riscv::{0}() success", __FUNCTION__);
+  return true;
 }
 
 bool ABISysV_riscv::PrepareTrivialCall(
@@ -222,14 +296,14 @@ bool ABISysV_riscv::PrepareTrivialCall(
   assert(prototype.getFunctionNumParams() == args.size());
 
   const size_t num_args = args.size();
-  const size_t regs_for_args_count = 8U;
   const size_t num_args_in_regs =
-      num_args > regs_for_args_count ?  regs_for_args_count : num_args;
+      num_args > s_regs_for_args_count ? s_regs_for_args_count : num_args;
 
   // Number of arguments passed on stack.
   size_t args_size = TotalArgsSizeInWords(m_is_rv64, args);
-  auto on_stack =
-      args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count;
+  auto on_stack = args_size <= s_regs_for_args_count
+                      ? 0
+                      : args_size - s_regs_for_args_count;
   auto offset = on_stack * word_size;
 
   uint8_t reg_value[8];
@@ -260,7 +334,7 @@ bool ABISysV_riscv::PrepareTrivialCall(
       ++reg_index;
     }
 
-    if (reg_index < regs_for_args_count || size == 0)
+    if (reg_index < s_regs_for_args_count || size == 0)
       continue;
 
     // Remaining arguments are passed on the stack.
diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h
index d8cf008dbb0bf8..04ec018c8a7180 100644
--- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h
+++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h
@@ -124,6 +124,9 @@ class ABISysV_riscv : public lldb_private::RegInfoBasedABI {
   using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance
                                                         // instead.
   bool m_is_rv64; // true if target is riscv64; false if target is riscv32
+  static constexpr size_t s_regs_for_args_count =
+      8U; // number of argument registers (the base integer calling convention
+          // provides 8 argument registers, a0-a7)
 };
 
 #endif // liblldb_ABISysV_riscv_h_

>From c75a5a062f64edd88c5ed0a66f185bf88a779665 Mon Sep 17 00:00:00 2001
From: Daniil Avdeev <daniil.avdeev at syntacore.com>
Date: Thu, 11 Jul 2024 11:23:39 +0000
Subject: [PATCH 2/5] [lldb][RISCV] add JIT relocations resolver

Function calls support in LLDB expressions for RISCV: 2 of 5

Adds required RISCV relocations resolving functionality in lldb
ExecutionEngine.
---
 .../RuntimeDyld/RuntimeDyldELF.cpp            | 155 +++++++++++++++++-
 .../RuntimeDyld/RuntimeDyldELF.h              |   7 +
 2 files changed, 159 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index 736d9a3e056f1e..a43edd41f5e889 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -1011,6 +1011,135 @@ void RuntimeDyldELF::resolveBPFRelocation(const SectionEntry &Section,
   }
 }
 
+static void applyUTypeImmRISCV(uint8_t *InstrAddr, uint32_t Imm) {
+  uint32_t UpperImm = (Imm + 0x800) & 0xfffff000;
+  auto Instr = support::ulittle32_t::ref(InstrAddr);
+  Instr = (Instr & 0xfff) | UpperImm;
+}
+
+static void applyITypeImmRISCV(uint8_t *InstrAddr, uint32_t Imm) {
+  uint32_t LowerImm = Imm & 0xfff;
+  auto Instr = support::ulittle32_t::ref(InstrAddr);
+  Instr = (Instr & 0xfffff) | (LowerImm << 20);
+}
+
+void RuntimeDyldELF::resolveRISCVRelocation(const SectionEntry &Section,
+                                            uint64_t Offset, uint64_t Value,
+                                            uint32_t Type, int64_t Addend,
+                                            SID SectionID) {
+  switch (Type) {
+  default: {
+    std::string Err = "Unimplemented reloc type: " + std::to_string(Type);
+    llvm::report_fatal_error(Err.c_str());
+  }
+    // 32-bit PC-relative function call, macros call, tail (PIC)
+    // Write first 20 bits of 32 bit value to the auipc instruction
+    // Last 12 bits to the jalr instruction
+  case ELF::R_RISCV_CALL:
+  case ELF::R_RISCV_CALL_PLT: {
+    uint64_t P = Section.getLoadAddressWithOffset(Offset);
+    uint64_t PCOffset = Value + Addend - P;
+    applyUTypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset);
+    applyITypeImmRISCV(Section.getAddressWithOffset(Offset + 4), PCOffset);
+    break;
+  }
+    // High 20 bits of 32-bit absolute address, %hi(symbol)
+  case ELF::R_RISCV_HI20: {
+    uint64_t PCOffset = Value + Addend;
+    applyUTypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset);
+    break;
+  }
+    // Low 12 bits of 32-bit absolute address, %lo(symbol)
+  case ELF::R_RISCV_LO12_I: {
+    uint64_t PCOffset = Value + Addend;
+    applyITypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset);
+    break;
+  }
+    // High 20 bits of 32-bit PC-relative reference, %pcrel_hi(symbol)
+  case ELF::R_RISCV_GOT_HI20:
+  case ELF::R_RISCV_PCREL_HI20: {
+    uint64_t P = Section.getLoadAddressWithOffset(Offset);
+    uint64_t PCOffset = Value + Addend - P;
+    applyUTypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset);
+    break;
+  }
+
+    // label:
+    //    auipc      a0, %pcrel_hi(symbol)    // R_RISCV_PCREL_HI20
+    //    addi       a0, a0, %pcrel_lo(label) // R_RISCV_PCREL_LO12_I
+    //
+    // The low 12 bits of relative address between pc and symbol.
+    // The symbol is related to the high part instruction which is marked by
+    // label.
+  case ELF::R_RISCV_PCREL_LO12_I: {
+    for (auto &&PendingReloc : PendingRelocs) {
+      const RelocationValueRef &MatchingValue = PendingReloc.first;
+      RelocationEntry &Reloc = PendingReloc.second;
+      uint64_t HIRelocPC =
+          getSectionLoadAddress(Reloc.SectionID) + Reloc.Offset;
+      if (Value + Addend == HIRelocPC) {
+        uint64_t Symbol = getSectionLoadAddress(MatchingValue.SectionID) +
+                          MatchingValue.Addend;
+        auto PCOffset = Symbol - HIRelocPC;
+        applyITypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset);
+        return;
+      }
+    }
+
+    llvm::report_fatal_error(
+        "R_RISCV_PCREL_LO12_I without matching R_RISCV_PCREL_HI20");
+  }
+  case ELF::R_RISCV_32_PCREL: {
+    uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
+    int64_t RealOffset = Value + Addend - FinalAddress;
+    int32_t TruncOffset = Lo_32(RealOffset);
+    support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) =
+        TruncOffset;
+    break;
+  }
+  case ELF::R_RISCV_32: {
+    auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset));
+    Ref = Value + Addend;
+    break;
+  }
+  case ELF::R_RISCV_64: {
+    auto Ref = support::ulittle64_t::ref(Section.getAddressWithOffset(Offset));
+    Ref = Value + Addend;
+    break;
+  }
+  case ELF::R_RISCV_ADD16: {
+    auto Ref = support::ulittle16_t::ref(Section.getAddressWithOffset(Offset));
+    Ref = Ref + Value + Addend;
+    break;
+  }
+  case ELF::R_RISCV_ADD32: {
+    auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset));
+    Ref = Ref + Value + Addend;
+    break;
+  }
+  case ELF::R_RISCV_ADD64: {
+    auto Ref = support::ulittle64_t::ref(Section.getAddressWithOffset(Offset));
+    Ref = Ref + Value + Addend;
+    break;
+  }
+  case ELF::R_RISCV_SUB16: {
+    auto Ref = support::ulittle16_t::ref(Section.getAddressWithOffset(Offset));
+    Ref = Ref - Value - Addend;
+    break;
+  }
+  case ELF::R_RISCV_SUB32: {
+    auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset));
+    Ref = Ref - Value - Addend;
+    break;
+  }
+  case ELF::R_RISCV_SUB64: {
+    auto Ref = support::ulittle64_t::ref(Section.getAddressWithOffset(Offset));
+    Ref = Ref - Value - Addend;
+    break;
+  }
+  }
+}
+
 // The target location for the relocation is described by RE.SectionID and
 // RE.Offset.  RE.SectionID can be used to find the SectionEntry.  Each
 // SectionEntry has three members describing its location.
@@ -1076,12 +1205,17 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
   case Triple::bpfeb:
     resolveBPFRelocation(Section, Offset, Value, Type, Addend);
     break;
+  case Triple::riscv32: // Fall through.
+  case Triple::riscv64:
+    resolveRISCVRelocation(Section, Offset, Value, Type, Addend, SectionID);
+    break;
   default:
     llvm_unreachable("Unsupported CPU type!");
   }
 }
 
-void *RuntimeDyldELF::computePlaceholderAddress(unsigned SectionID, uint64_t Offset) const {
+void *RuntimeDyldELF::computePlaceholderAddress(unsigned SectionID,
+                                                uint64_t Offset) const {
   return (void *)(Sections[SectionID].getObjAddress() + Offset);
 }
 
@@ -1870,7 +2004,8 @@ RuntimeDyldELF::processRelocationRef(
       Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset));
       processSimpleRelocation(SectionID, Offset, RelType, Value);
     } else if (RelType == ELF::R_X86_64_PC64) {
-      Value.Addend += support::ulittle64_t::ref(computePlaceholderAddress(SectionID, Offset));
+      Value.Addend += support::ulittle64_t::ref(
+          computePlaceholderAddress(SectionID, Offset));
       processSimpleRelocation(SectionID, Offset, RelType, Value);
     } else if (RelType == ELF::R_X86_64_GOTTPOFF) {
       processX86_64GOTTPOFFRelocation(SectionID, Offset, Value, Addend);
@@ -1884,9 +2019,23 @@ RuntimeDyldELF::processRelocationRef(
     } else {
       processSimpleRelocation(SectionID, Offset, RelType, Value);
     }
+  } else if (Arch == Triple::riscv32 || Arch == Triple::riscv64) {
+    // *_LO12 relocation receive information about a symbol from the
+    // corresponding *_HI20 relocation, so we have to collect this information
+    // before resolving
+    if (RelType == ELF::R_RISCV_GOT_HI20 ||
+        RelType == ELF::R_RISCV_PCREL_HI20 ||
+        RelType == ELF::R_RISCV_TPREL_HI20 ||
+        RelType == ELF::R_RISCV_TLS_GD_HI20 ||
+        RelType == ELF::R_RISCV_TLS_GOT_HI20) {
+      RelocationEntry RE(SectionID, Offset, RelType, Addend);
+      PendingRelocs.push_back({Value, RE});
+    }
+    processSimpleRelocation(SectionID, Offset, RelType, Value);
   } else {
     if (Arch == Triple::x86) {
-      Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset));
+      Value.Addend += support::ulittle32_t::ref(
+          computePlaceholderAddress(SectionID, Offset));
     }
     processSimpleRelocation(SectionID, Offset, RelType, Value);
   }
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
index 1b90013dfe2df9..97517884654bc5 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
@@ -58,6 +58,10 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
   void resolveBPFRelocation(const SectionEntry &Section, uint64_t Offset,
                             uint64_t Value, uint32_t Type, int64_t Addend);
 
+  void resolveRISCVRelocation(const SectionEntry &Section, uint64_t Offset,
+                              uint64_t Value, uint32_t Type, int64_t Addend,
+                              SID SectionID);
+
   unsigned getMaxStubSize() const override {
     if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be)
       return 20; // movz; movk; movk; movk; br
@@ -146,6 +150,9 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
 
   // *HI16 relocations will be added for resolving when we find matching
   // *LO16 part. (Mips specific)
+  //
+  // *HI20 relocations will be added for resolving when we find matching
+  // *LO12 part. (RISC-V specific)
   SmallVector<std::pair<RelocationValueRef, RelocationEntry>, 8> PendingRelocs;
 
   // When a module is loaded we save the SectionID of the EH frame section

>From 1638039f648901bc3e0a7227e46831101dbe98b4 Mon Sep 17 00:00:00 2001
From: Daniil Avdeev <daniil.avdeev at syntacore.com>
Date: Tue, 10 Sep 2024 19:34:43 +0300
Subject: [PATCH 3/5] [lldb][RISCV] RISC-V large code model in lldb expressions

Function calls support in LLDB expressions for RISCV: 3 of 5

This patch sets large code model in MCJIT settings for RISC-V 64-bit targets
that allows to make assembly jumps at any 64bit address. This is needed,
because resulted jitted code may contain more that +-2GB jumps, which are
not available in RISC-V with medium code model.
---
 lldb/source/Expression/IRExecutionUnit.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index d2f2ee26fd4307..04f48556ce384a 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -279,6 +279,9 @@ void IRExecutionUnit::GetRunnableInfo(Status &error, lldb::addr_t &func_addr,
       .setMCJITMemoryManager(std::make_unique<MemoryManager>(*this))
       .setOptLevel(llvm::CodeGenOptLevel::Less);
 
+  if (triple.isRISCV64())
+    builder.setCodeModel(llvm::CodeModel::Large);
+
   llvm::StringRef mArch;
   llvm::StringRef mCPU;
   llvm::SmallVector<std::string, 0> mAttrs;

>From 4226b51ce24d075869632478f213d35b38dc70ec Mon Sep 17 00:00:00 2001
From: Daniil Avdeev <daniil.avdeev at syntacore.com>
Date: Tue, 10 Sep 2024 19:30:11 +0300
Subject: [PATCH 4/5] [lldb][RISCV] doubles support in lldb expressions

Function calls support in LLDB expressions for RISCV: 4 of 5

This patch adds desired feature flags in MCJIT compiler to enable
hard-float instructions if target supports them and allows to use floats
and doubles in lldb expressions.
---
 .../Clang/ClangExpressionParser.cpp           | 69 +++++++++++++++----
 1 file changed, 54 insertions(+), 15 deletions(-)

diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 90f26de939a478..5fb0ad67ad23e3 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -43,6 +43,7 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/TargetSelect.h"
+#include "llvm/TargetParser/Triple.h"
 
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
@@ -407,24 +408,50 @@ static void SetupDefaultClangDiagnostics(CompilerInstance &compiler) {
 /// \return
 ///     A string representing target ABI for the current architecture.
 static std::string GetClangTargetABI(const ArchSpec &target_arch) {
-  std::string abi;
-
   if (target_arch.IsMIPS()) {
     switch (target_arch.GetFlags() & ArchSpec::eMIPSABI_mask) {
     case ArchSpec::eMIPSABI_N64:
-      abi = "n64";
-      break;
+      return "n64";
     case ArchSpec::eMIPSABI_N32:
-      abi = "n32";
-      break;
+      return "n32";
     case ArchSpec::eMIPSABI_O32:
-      abi = "o32";
-      break;
+      return "o32";
     default:
-      break;
+      return {};
     }
   }
-  return abi;
+
+  if (target_arch.GetTriple().isRISCV64()) {
+    switch (target_arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask) {
+    case ArchSpec::eRISCV_float_abi_soft:
+      return "lp64";
+    case ArchSpec::eRISCV_float_abi_single:
+      return "lp64f";
+    case ArchSpec::eRISCV_float_abi_double:
+      return "lp64d";
+    case ArchSpec::eRISCV_float_abi_quad:
+      return "lp64q";
+    default:
+      return {};
+    }
+  }
+
+  if (target_arch.GetTriple().isRISCV32()) {
+    switch (target_arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask) {
+    case ArchSpec::eRISCV_float_abi_soft:
+      return "ilp32";
+    case ArchSpec::eRISCV_float_abi_single:
+      return "ilp32f";
+    case ArchSpec::eRISCV_float_abi_double:
+      return "ilp32d";
+    case ArchSpec::eRISCV_float_abi_soft | ArchSpec::eRISCV_rve:
+      return "ilp32e";
+    default:
+      return {};
+    }
+  }
+
+  return {};
 }
 
 static void SetupTargetOpts(CompilerInstance &compiler,
@@ -471,6 +498,18 @@ static void SetupTargetOpts(CompilerInstance &compiler,
   // Set the target ABI
   if (std::string abi = GetClangTargetABI(target_arch); !abi.empty())
     compiler.getTargetOpts().ABI = std::move(abi);
+
+  if ((target_machine == llvm::Triple::riscv64 &&
+       compiler.getTargetOpts().ABI == "lp64f") ||
+      (target_machine == llvm::Triple::riscv32 &&
+       compiler.getTargetOpts().ABI == "ilp32f"))
+    compiler->getTargetOpts().FeaturesAsWritten.emplace_back("+f");
+
+  if ((target_machine == llvm::Triple::riscv64 &&
+       compiler.getTargetOpts().ABI == "lp64d") ||
+      (target_machine == llvm::Triple::riscv32 &&
+       compiler.getTargetOpts().ABI == "ilp32d"))
+    compiler->getTargetOpts().FeaturesAsWritten.emplace_back("+d");
 }
 
 static void SetupLangOpts(CompilerInstance &compiler,
@@ -722,7 +761,7 @@ ClangExpressionParser::ClangExpressionParser(
   m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
   m_compiler->getCodeGenOpts().InstrumentFunctions = false;
   m_compiler->getCodeGenOpts().setFramePointer(
-                                    CodeGenOptions::FramePointerKind::All);
+      CodeGenOptions::FramePointerKind::All);
   if (generate_debug_info)
     m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
   else
@@ -736,7 +775,7 @@ ClangExpressionParser::ClangExpressionParser(
   // FIXME: We shouldn't need to do this, the target should be immutable once
   // created. This complexity should be lifted elsewhere.
   m_compiler->getTarget().adjust(m_compiler->getDiagnostics(),
-		                 m_compiler->getLangOpts());
+                                 m_compiler->getLangOpts());
 
   // 5. Set up the diagnostic buffer for reporting errors
 
@@ -1157,8 +1196,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
           if (auto fileEntry = m_compiler->getFileManager().getOptionalFileRef(
                   result_path)) {
             source_mgr.setMainFileID(source_mgr.createFileID(
-                *fileEntry,
-                SourceLocation(), SrcMgr::C_User));
+                *fileEntry, SourceLocation(), SrcMgr::C_User));
             created_main_file = true;
           }
         }
@@ -1506,7 +1544,8 @@ lldb_private::Status ClangExpressionParser::DoPrepareForExecution(
 
           DiagnosticManager install_diags;
           if (Error Err = dynamic_checkers->Install(install_diags, exe_ctx)) {
-            std::string ErrMsg = "couldn't install checkers: " + toString(std::move(Err));
+            std::string ErrMsg =
+                "couldn't install checkers: " + toString(std::move(Err));
             if (install_diags.Diagnostics().size())
               ErrMsg = ErrMsg + "\n" + install_diags.GetString().c_str();
             err = Status(ErrMsg);

>From 49108fedaf1599c5dd29773c4698f3b5b3277ba3 Mon Sep 17 00:00:00 2001
From: Daniil Avdeev <daniil.avdeev at syntacore.com>
Date: Tue, 10 Sep 2024 19:31:12 +0300
Subject: [PATCH 5/5] [lldb][RISCV] add function calls tests

Function calls support in LLDB expressions for RISCV: 5 of 5

Adds tests on function calls inside lldb expressions
---
 lldb/test/API/riscv/expressions/Makefile      |   3 +
 .../API/riscv/expressions/TestExpressions.py  | 101 ++++++++++++++++++
 lldb/test/API/riscv/expressions/main.cpp      |  63 +++++++++++
 3 files changed, 167 insertions(+)
 create mode 100644 lldb/test/API/riscv/expressions/Makefile
 create mode 100644 lldb/test/API/riscv/expressions/TestExpressions.py
 create mode 100644 lldb/test/API/riscv/expressions/main.cpp

diff --git a/lldb/test/API/riscv/expressions/Makefile b/lldb/test/API/riscv/expressions/Makefile
new file mode 100644
index 00000000000000..99998b20bcb050
--- /dev/null
+++ b/lldb/test/API/riscv/expressions/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/riscv/expressions/TestExpressions.py b/lldb/test/API/riscv/expressions/TestExpressions.py
new file mode 100644
index 00000000000000..506df563c46050
--- /dev/null
+++ b/lldb/test/API/riscv/expressions/TestExpressions.py
@@ -0,0 +1,101 @@
+"""
+Test RISC-V expressions evaluation.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestExpressions(TestBase):
+    def common_setup(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_int_arg(self):
+        self.common_setup()
+        self.expect_expr("foo(foo(5), foo())", result_type="int", result_value="8")
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_double_arg(self):
+        self.common_setup()
+        self.expect_expr(
+            "func_with_double_arg(1, 6.5)", result_type="int", result_value="1"
+        )
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_ptr_arg(self):
+        self.common_setup()
+        self.expect_expr(
+            'func_with_ptr_arg("message")', result_type="int", result_value="2"
+        )
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_ptr_ret_val(self):
+        self.common_setup()
+        self.expect("expr func_with_ptr_return()", substrs=["global"])
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_ptr(self):
+        self.common_setup()
+        self.expect(
+            'expr func_with_ptr("message")',
+            substrs=["message"],
+        )
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_global_ptr(self):
+        self.common_setup()
+        self.expect(
+            "expr func_with_ptr(g_str)",
+            substrs=["global"],
+        )
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_struct_arg(self):
+        self.common_setup()
+        self.expect_expr(
+            "func_with_struct_arg(s)", result_type="int", result_value="110"
+        )
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_unsupported_struct_arg(self):
+        self.common_setup()
+        self.expect_expr(
+            "func_with_double_struct_arg(u)", result_type="int", result_value="400"
+        )
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_double_ret_val(self):
+        self.common_setup()
+        self.expect_expr(
+            "func_with_double_return()", result_type="double", result_value="42"
+        )
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_struct_return(self):
+        self.common_setup()
+        self.expect_expr("func_with_struct_return()", result_type="S")
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_struct_double_ret_val(self):
+        self.common_setup()
+        self.expect_expr("func_with_double_struct_return()", result_type="U")
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_float_arg(self):
+        self.common_setup()
+        self.expect_expr(
+            "func_with_float_arg(9.99, 8.88)", result_type="int", result_value="7"
+        )
+
+    @skipIf(archs=no_match(["rv64gc"]))
+    def test_float_ret_val(self):
+        self.common_setup()
+        self.expect_expr(
+            "func_with_float_ret_val()", result_type="float", result_value="8"
+        )
diff --git a/lldb/test/API/riscv/expressions/main.cpp b/lldb/test/API/riscv/expressions/main.cpp
new file mode 100644
index 00000000000000..600f9b841f7a35
--- /dev/null
+++ b/lldb/test/API/riscv/expressions/main.cpp
@@ -0,0 +1,63 @@
+struct S {
+  int a;
+  int b;
+};
+
+struct U {
+  int a;
+  double d;
+};
+
+int g;
+
+char *g_str = "global";
+
+int func_with_double_arg(int a, double b) { return 1; }
+
+int func_with_float_arg(float a, float b) { return 7; }
+float func_with_float_ret_val() { return 8.0f; }
+
+int func_with_ptr_arg(char *msg) { return 2; }
+char *func_with_ptr_return() { return g_str; }
+char *func_with_ptr(char *msg) { return msg; }
+
+int func_with_struct_arg(S s) { return s.a + s.b; }
+
+int func_with_double_struct_arg(U u) { return u.a * 3 + 31; }
+
+double func_with_double_return() { return 42.0; }
+
+S func_with_struct_return() {
+  S s = {123, 4};
+  return s;
+}
+
+U func_with_double_struct_return() {
+  U u = {123, 42.0};
+  return u;
+}
+
+int foo() { return 3; }
+
+int foo(int a) { return a; }
+
+int foo(int a, int b) { return a + b; }
+
+int main() {
+  S s{11, 99};
+  U u{123, 7.7};
+
+  double d = func_with_double_arg(1, 1.0) + func_with_struct_arg(S{1, 2}) +
+             func_with_ptr_arg("msg") + func_with_double_return() +
+             func_with_double_struct_arg(U{1, 1.0}) + foo() + foo(1) +
+             foo(1, 2) + func_with_float_arg(5.42, 7.86) +
+             func_with_float_ret_val();
+
+  char *msg = func_with_ptr("msg");
+  char *ptr = func_with_ptr_return();
+
+  S s_s = func_with_struct_return();
+  U s_u = func_with_double_struct_return(); // break here
+
+  return 0;
+}



More information about the lldb-commits mailing list