Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb][RISCV] function calls support in lldb expressions #99336

Merged
merged 4 commits into from
Oct 2, 2024

Conversation

dlav-sc
Copy link
Contributor

@dlav-sc dlav-sc commented Jul 17, 2024

To make function calls inside lldb expressions ABI support and JIT engine support are required. This patch augments corresponding functionality to RISCV ABI and implements RISCV relocation resolver in MCJIT.

Also it sets large code model for RISC-V 64bit targets, which allows to make assembly jumps at any 64bit address. This is necessary, because jitted code can be placed too far from the code in the binary.

Fixed tests:

TestCallThatRestarts.ExprCommandThatRestartsTestCase
TestMainThreadExit.ThreadExitTestCase
TestSBValuePersist.SBValuePersistTestCase
TestThisClassTypeMixing.TestCase
Test11588.Issue11581TestCase
TestExprsChar.ExprCharTestCase
TestExpressions.TestExpressions
TestCallWithTimeout.ExprCommandWithTimeoutsTestCase
TestInlineNamespace.TestInlineNamespace
TestInlineNamespaceAlias.TestInlineNamespace
TestSetValues.SetValuesTestCase
TestValueAPIAddressOfVoidStar.ValueAPIVoidStarTestCase
TestXValuePrinting.ExprXValuePrintingTestCase
lldbsuite.test.lldbtest.TestRedefinitionsInInlines
lldbsuite.test.lldbtest.TestVirtualOverload
TestSetValues.SetValuesTestCase
TestExprs.BasicExprCommandsTestCase
TestExprHelpExamples.Radar9673644TestCase
TestExprEntryBP.ExprEntryBPTestCase
TestExprInsideLambdas.ExprInsideLambdaTestCase
TestConstStaticIntegralMemberInt128.TestCase
TestDWIMPrint.TestCase
TestCPPStaticMembers.TestCase
TestNestedPersistentTypes.NestedPersistentTypesTestCase
TestSaveJITObjects.SaveJITObjectsTestCase
TestNamespaceLookup.NamespaceLookupTestCase
TestCCallingConventions.TestCase
TestCppTypedef.TestCppTypedef
TestUnwindExpression.UnwindFromExpressionTest
TestCxxChar8_t.CxxChar8_tTestCase
TestCallCPPFunction.CallCPPFunctionTestCase
TestExprDoesntBlock.ExprDoesntDeadlockTestCase
TestEnumTypes.EnumTypesTestCase
TestAnonymous.AnonymousTestCase

@llvmbot
Copy link
Member

llvmbot commented Jul 17, 2024

@llvm/pr-subscribers-lldb

Author: None (dlav-sc)

Changes

To make function calls inside lldb expressions ABI support, JIT engine support are required. This patch augments corresponding functionality to RISCV ABI and implements RISCV relocation resolver in JIT, which allows to make function calls with integer and void function arguments and return value. Also it adds RISCV specific DirectToIndirectFunctionCallsReplacement IR pass, that allows to make assembly jumps at any 64bit address without RISCV large code model, which has not been implemented yet. This pass is needed, because jitted code contains more that +-2GB jumps, which are not available in RISCV without large code model now.

Fixed tests:

TestCallThatRestarts.ExprCommandThatRestartsTestCase
TestMainThreadExit.ThreadExitTestCase
TestSBValuePersist.SBValuePersistTestCase
TestThisClassTypeMixing.TestCase
Test11588.Issue11581TestCase
TestExprsChar.ExprCharTestCase
TestExpressions.TestExpressions
TestCallWithTimeout.ExprCommandWithTimeoutsTestCase
TestInlineNamespace.TestInlineNamespace
TestInlineNamespaceAlias.TestInlineNamespace
TestSetValues.SetValuesTestCase
TestValueAPIAddressOfVoidStar.ValueAPIVoidStarTestCase
TestXValuePrinting.ExprXValuePrintingTestCase
lldbsuite.test.lldbtest.TestRedefinitionsInInlines
lldbsuite.test.lldbtest.TestVirtualOverload
TestSetValues.SetValuesTestCase
TestExprs.BasicExprCommandsTestCase
TestExprHelpExamples.Radar9673644TestCase
TestExprEntryBP.ExprEntryBPTestCase
TestExprInsideLambdas.ExprInsideLambdaTestCase
TestConstStaticIntegralMemberInt128.TestCase
TestDWIMPrint.TestCase
TestCPPStaticMembers.TestCase
TestNestedPersistentTypes.NestedPersistentTypesTestCase
TestSaveJITObjects.SaveJITObjectsTestCase
TestNamespaceLookup.NamespaceLookupTestCase
TestCCallingConventions.TestCase
TestCppTypedef.TestCppTypedef
TestUnwindExpression.UnwindFromExpressionTest
TestCxxChar8_t.CxxChar8_tTestCase
TestCallCPPFunction.CallCPPFunctionTestCase
TestExprDoesntBlock.ExprDoesntDeadlockTestCase
TestEnumTypes.EnumTypesTestCase
TestAnonymous.AnonymousTestCase

Patch is 35.55 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/99336.diff

15 Files Affected:

  • (modified) lldb/include/lldb/Core/Architecture.h (+12)
  • (modified) lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp (+82-7)
  • (modified) lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h (+3)
  • (modified) lldb/source/Plugins/Architecture/CMakeLists.txt (+1)
  • (added) lldb/source/Plugins/Architecture/RISCV/ArchitectureRISCV.cpp (+55)
  • (added) lldb/source/Plugins/Architecture/RISCV/ArchitectureRISCV.h (+34)
  • (added) lldb/source/Plugins/Architecture/RISCV/CMakeLists.txt (+12)
  • (added) lldb/source/Plugins/Architecture/RISCV/DirectToIndirectFCR.cpp (+194)
  • (added) lldb/source/Plugins/Architecture/RISCV/DirectToIndirectFCR.h (+58)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+23)
  • (added) lldb/test/API/riscv/expressions/Makefile (+3)
  • (added) lldb/test/API/riscv/expressions/TestExpressions.py (+88)
  • (added) lldb/test/API/riscv/expressions/main.cpp (+51)
  • (modified) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp (+152-3)
  • (modified) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h (+7)
diff --git a/lldb/include/lldb/Core/Architecture.h b/lldb/include/lldb/Core/Architecture.h
index b6fc1a20e1e69..ca6a9207d8012 100644
--- a/lldb/include/lldb/Core/Architecture.h
+++ b/lldb/include/lldb/Core/Architecture.h
@@ -12,6 +12,7 @@
 #include "lldb/Core/PluginInterface.h"
 #include "lldb/Target/DynamicRegisterInfo.h"
 #include "lldb/Target/MemoryTagManager.h"
+#include "llvm/IR/LegacyPassManager.h"
 
 namespace lldb_private {
 
@@ -129,6 +130,17 @@ class Architecture : public PluginInterface {
                                        RegisterContext &reg_context) const {
     return false;
   }
+
+  // Takes a Pass Manager and adds passes for this Architecture that should be
+  // run before IRForTarget
+  virtual std::unique_ptr<llvm::legacy::PassManager>
+  GetArchitectureCustomPasses(const ExecutionContext &exe_ctx,
+                              const llvm::StringRef expr) const {
+    return nullptr;
+  }
+
+  static constexpr llvm::StringLiteral s_target_incompatibility_marker =
+      "target_incompatibility_detected";
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
index 6395f5bb5bd9b..f3edee1dd6dc1 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 "lldb/Core/PluginManager.h"
@@ -19,6 +21,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()
@@ -163,11 +166,83 @@ 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 %s: 0x%" PRIx64, reg_info->name,
+           static_cast<uint64_t>(value));
+  if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, value)) {
+    LLDB_LOG(log, "Writing %s: 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 %lu arguments, but only %lu 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%lu (0x%" PRIx64 ") into %s", idx, arg,
+             reg_info->name);
+
+    if (!reg_ctx_sp->WriteRegisterFromUnsigned(reg_info, arg)) {
+      LLDB_LOG(log, "Failed to write arg%lu (0x%" PRIx64 ") into %s", 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::%s: success", __func__);
+  return true;
 }
 
 bool ABISysV_riscv::PrepareTrivialCall(
@@ -221,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];
@@ -259,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 d8cf008dbb0bf..04ec018c8a718 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_
diff --git a/lldb/source/Plugins/Architecture/CMakeLists.txt b/lldb/source/Plugins/Architecture/CMakeLists.txt
index 9ed8edf70af3f..78cdaa0bdf2d4 100644
--- a/lldb/source/Plugins/Architecture/CMakeLists.txt
+++ b/lldb/source/Plugins/Architecture/CMakeLists.txt
@@ -2,3 +2,4 @@ add_subdirectory(Arm)
 add_subdirectory(Mips)
 add_subdirectory(PPC64)
 add_subdirectory(AArch64)
+add_subdirectory(RISCV)
diff --git a/lldb/source/Plugins/Architecture/RISCV/ArchitectureRISCV.cpp b/lldb/source/Plugins/Architecture/RISCV/ArchitectureRISCV.cpp
new file mode 100644
index 0000000000000..e4608b41bd787
--- /dev/null
+++ b/lldb/source/Plugins/Architecture/RISCV/ArchitectureRISCV.cpp
@@ -0,0 +1,55 @@
+//===-- ArchitectureRISCV.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 "Plugins/Architecture/RISCV/ArchitectureRISCV.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ArchSpec.h"
+
+#include "llvm/IR/LegacyPassManager.h"
+
+#include "DirectToIndirectFCR.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+LLDB_PLUGIN_DEFINE(ArchitectureRISCV)
+
+void ArchitectureRISCV::Initialize() {
+  PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                "RISCV-specific algorithms",
+                                &ArchitectureRISCV::Create);
+}
+
+void ArchitectureRISCV::Terminate() {
+  PluginManager::UnregisterPlugin(&ArchitectureRISCV::Create);
+}
+
+std::unique_ptr<Architecture> ArchitectureRISCV::Create(const ArchSpec &arch) {
+  if (!arch.GetTriple().isRISCV())
+    return nullptr;
+  return std::unique_ptr<Architecture>(new ArchitectureRISCV());
+}
+
+void ArchitectureRISCV::OverrideStopInfo(Thread &thread) const {}
+
+std::unique_ptr<llvm::legacy::PassManager>
+ArchitectureRISCV::GetArchitectureCustomPasses(
+    const ExecutionContext &exe_ctx, const llvm::StringRef expr) const {
+  // LLDB generates additional support functions like
+  // '_$__lldb_valid_pointer_check', that do not require custom passes
+  if (expr != "$__lldb_expr")
+    return nullptr;
+
+  std::unique_ptr<llvm::legacy::PassManager> custom_passes =
+      std::make_unique<llvm::legacy::PassManager>();
+  auto *P = createDirectToIndirectFCR(exe_ctx);
+  custom_passes->add(P);
+  return custom_passes;
+}
diff --git a/lldb/source/Plugins/Architecture/RISCV/ArchitectureRISCV.h b/lldb/source/Plugins/Architecture/RISCV/ArchitectureRISCV.h
new file mode 100644
index 0000000000000..6ef6c62de5f27
--- /dev/null
+++ b/lldb/source/Plugins/Architecture/RISCV/ArchitectureRISCV.h
@@ -0,0 +1,34 @@
+//===-- ArchitectureRISCV.h -------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include "lldb/Core/Architecture.h"
+
+namespace lldb_private {
+
+class ArchitectureRISCV : public Architecture {
+public:
+  static llvm::StringRef GetPluginNameStatic() { return "riscv"; }
+  static void Initialize();
+  static void Terminate();
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+  void OverrideStopInfo(Thread &thread) const override;
+
+  std::unique_ptr<llvm::legacy::PassManager>
+  GetArchitectureCustomPasses(const ExecutionContext &exe_ctx,
+                              const llvm::StringRef expr) const override;
+
+private:
+  static std::unique_ptr<Architecture> Create(const ArchSpec &arch);
+  ArchitectureRISCV() = default;
+};
+
+} // namespace lldb_private
diff --git a/lldb/source/Plugins/Architecture/RISCV/CMakeLists.txt b/lldb/source/Plugins/Architecture/RISCV/CMakeLists.txt
new file mode 100644
index 0000000000000..f2545eb35b000
--- /dev/null
+++ b/lldb/source/Plugins/Architecture/RISCV/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_lldb_library(lldbPluginArchitectureRISCV PLUGIN
+  ArchitectureRISCV.cpp
+  DirectToIndirectFCR.cpp
+
+  LINK_LIBS
+    lldbPluginProcessUtility
+    lldbCore
+    lldbTarget
+    lldbUtility
+  LINK_COMPONENTS
+    Support
+  )
diff --git a/lldb/source/Plugins/Architecture/RISCV/DirectToIndirectFCR.cpp b/lldb/source/Plugins/Architecture/RISCV/DirectToIndirectFCR.cpp
new file mode 100644
index 0000000000000..71d3001fc06e8
--- /dev/null
+++ b/lldb/source/Plugins/Architecture/RISCV/DirectToIndirectFCR.cpp
@@ -0,0 +1,194 @@
+//===--- DirectToIndirectFCR.cpp - RISC-V specific pass -------------------===//
+//
+// 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 "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Value.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+#include "Plugins/Architecture/RISCV/DirectToIndirectFCR.h"
+
+#include "lldb/Core/Architecture.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include <optional>
+
+using namespace llvm;
+using namespace lldb_private;
+
+namespace {
+std::string GetValueTypeStr(const llvm::Type *value_ty) {
+  assert(value_ty);
+  std::string str_type;
+  llvm::raw_string_ostream rso(str_type);
+  value_ty->print(rso);
+  return rso.str();
+}
+
+template <typename... Args> void LogMessage(const char *msg, Args &&...args) {
+  Log *log = GetLog(LLDBLog::Expressions);
+  LLDB_LOG(log, msg, std::forward<Args>(args)...);
+}
+} // namespace
+
+bool DirectToIndirectFCR::canBeReplaced(const llvm::CallInst *ci) {
+  assert(ci);
+  auto *return_value_ty = ci->getType();
+  if (!(return_value_ty->isIntegerTy() || return_value_ty->isVoidTy())) {
+    LogMessage("DirectToIndirectFCR: function {0} has unsupported "
+               "return type ({1})\n",
+               ci->getCalledFunction()->getName(),
+               GetValueTypeStr(return_value_ty));
+    return false;
+  }
+
+  const auto *arg = llvm::find_if_not(ci->args(), [](const auto &arg) {
+    const auto *type = arg->getType();
+    return type->isIntegerTy();
+  });
+
+  if (arg != ci->arg_end()) {
+    LogMessage("DirectToIndirectFCR: argument {0} of {1} function "
+               "has unsupported type ({2})\n",
+               (*arg)->getName(), ci->getCalledFunction()->getName(),
+               GetValueTypeStr((*arg)->getType()));
+    return false;
+  }
+  return true;
+}
+
+std::vector<llvm::Value *>
+DirectToIndirectFCR::getFunctionArgsAsValues(const llvm::CallInst *ci) {
+  assert(ci);
+  std::vector<llvm::Value *> args{};
+  llvm::transform(ci->args(), std::back_inserter(args),
+                  [](const auto &arg) { return arg.get(); });
+  return args;
+}
+
+std::optional<lldb::addr_t>
+DirectToIndirectFCR::getFunctionAddress(const llvm::CallInst *ci) const {
+  auto *target = m_exe_ctx.GetTargetPtr();
+  const auto &lldb_module_sp = target->GetExecutableModule();
+  const auto &symtab = lldb_module_sp->GetSymtab();
+  const llvm::StringRef name = ci->getCalledFunction()->getName();
+
+  // eSymbolTypeCode: we try to find function
+  // eDebugNo: not a debug symbol
+  // eVisibilityExtern: function from extern module
+  const auto *symbol = symtab->FindFirstSymbolWithNameAndType(
+      ConstString(name), lldb::SymbolType::eSymbolTypeCode,
+      Symtab::Debug::eDebugNo, Symtab::Visibility::eVisibilityExtern);
+  if (!symbol) {
+    LogMessage("DirectToIndirectFCR: can't find {0} in symtab\n", name);
+    return std::nullopt;
+  }
+
+  lldb::addr_t addr = symbol->GetLoadAddress(target);
+  LogMessage("DirectToIndirectFCR: found address ({0}) of symbol {1}\n", addr,
+             name);
+  return addr;
+}
+
+llvm::CallInst *DirectToIndirectFCR::getInstReplace(llvm::CallInst *ci) const {
+  assert(ci);
+
+  std::optional<lldb::addr_t> addr_or_null = getFunctionAddress(ci);
+  if (!addr_or_null.has_value())
+    return nullptr;
+
+  lldb::addr_t addr = addr_or_null.value();
+
+  llvm::IRBuilder<> builder(ci);
+
+  std::vector<llvm::Value *> args = getFunctionArgsAsValues(ci);
+  llvm::Constant *func_addr = builder.getInt64(addr);
+  llvm::PointerType *ptr_func_ty = builder.getPtrTy();
+  auto *cast = builder.CreateIntToPtr(func_addr, ptr_func_ty);
+  auto *new_inst =
+      builder.CreateCall(ci->getFunctionType(), cast, ArrayRef(args));
+  return new_inst;
+}
+
+DirectToIndirectFCR::DirectToIndirectFCR(const ExecutionContext &exe_ctx)
+    : FunctionPass(ID), m_exe_ctx{exe_ctx} {}
+
+DirectToIndirectFCR::~DirectToIndirectFCR() = default;
+
+bool DirectToIndirectFCR::runOnFunction(llvm::Function &func) {
+  bool has_irreplaceable =
+      llvm::any_of(instructions(func), [this](llvm::Instruction &inst) {
+        llvm::CallInst *ci = dyn_cast<llvm::CallInst>(&inst);
+        if (!ci || ci->getCalledFunction()->isIntrinsic() ||
+            (DirectToIndirectFCR::canBeReplaced(ci) &&
+             getFunctionAddress(ci).has_value()))
+          return false;
+        return true;
+      });
+
+  if (has_irreplaceable) {
+    func.getParent()->getOrInsertNamedMetadata(
+        Architecture::s_target_incompatibility_marker);
+    return false;
+  }
+
+  std::vector<std::reference_wrapper<llvm::Instruction>>
+      replaceable_function_calls{};
+  llvm::copy_if(instructions(func),
+                std::back_inserter(replaceable_function_calls),
+                [](llvm::Instruction &inst) {
+                  llvm::CallInst *ci = dyn_cast<llvm::CallInst>(&inst);
+                  if (ci && !ci->getCalledFunction()->isIntrinsic())
+                    return true;
+                  return false;
+                });
+
+  if (replaceable_function_calls.empty())
+    return false;
+
+  std::vector<std::pair<llvm::CallInst *, llvm::CallInst *>> replaces;
+  llvm::transform(replaceable_function_calls, std::back_inserter(replaces),
+                  [this](std::reference_wrapper<llvm::Instruction> inst)
+                      -> std::pair<llvm::CallInst *, llvm::CallInst *> {
+                    llvm::CallInst *ci = cast<llvm::CallInst>(&(inst.get()));
+                    llvm::CallInst *new_inst = getInstReplace(ci);
+                    return {ci, new_inst};
+                  });
+
+  for (auto &&[from, to] : replaces) {
+    from->replaceAllUsesWith(to);
+    from->eraseFromParent();
+  }
+
+  return true;
+}
+
+llvm::StringRef DirectToIndirectFCR::getPassName() const {
+  return "Transform function calls to calls by address";
+}
+
+char DirectToIndirectFCR::ID = 0;
+
+llvm::FunctionPass *
+lldb_private::createDirectToIndirectFCR(const ExecutionContext &exe_ctx) {
+  return new DirectToIndirectFCR(exe_ctx);
+}
diff --git a/lldb/source/Plugins/Architecture/RISCV/DirectToIndirectFCR.h b/lldb/source/Plugins/Architecture/RISCV/DirectToIndirectFCR.h
new file mode 100644
index 0000000000000..5ac5820bd95a0
--- /dev/null
+++ b/lldb/source/Plugins/Architecture/RISCV/DirectToIndirectFCR.h
@@ -0,0 +1,58 @@
+//===--- DirectToIndirectFCR.h - RISC-V specific pass ---------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include "lldb/lldb-types.h"
+
+#include "llvm/IR/Instructions.h"
+#include "llvm/Pass.h"
+
+namespace lldb_private {
+
+class ExecutionContext;
+
+// During the lldb expression execution lldb wraps a user expression, jittes
+// fabricated code and then puts it into the stack memory. Thus, if user tried
+// to make a function call there will be a jump from a stack address to a code
+// sections's address. RISC-V Architecture doesn't have a large code model yet
+// and can make only a +-2GiB jumps, but in 64-bit architecture a distance
+// between stack addresses and code sections's addresses is longer. Therefore,
+// relocations resolver obtains an invalid address. To avoid such problem, this
+// pass should be used. It replaces function calls with appropriate function's
+// addresses explicitly. By doing so it removes relocations related to function
+// calls. This pass should be cosidered as temprorary solution until a large
+// code model will be approved.
+class DirectToIndirectFCR : public llvm::FunctionPass {
+
+  static bool canBeReplaced(const llvm::CallInst *ci);
+
+  static std::vector<llvm::Value *>
+  getFunctionArgsAsValues(const llvm::CallInst *ci);
+
+  std::optional<lldb::addr_t>
+  getFunctionAddress(const llvm::CallInst *ci) const;
+
+  llvm::CallInst *getInstReplace(llvm::CallInst *ci) const;
+
+public:
+  static char ID;
+
+  DirectToIndirectFCR(const ExecutionContext &exe_ctx);
+  ~DirectT...
[truncated]

Copy link

github-actions bot commented Jul 17, 2024

✅ With the latest revision this PR passed the Python code formatter.

@Michael137
Copy link
Member

Michael137 commented Jul 18, 2024

Thanks for the patches (if we end up going down this route you'll probably want to split out the LLVM JIT changes into a separate PR).

Not very familiar with RISCV. Could you elaborate on the exact failures you were seeing and why we need the extra IR pass?

Also it adds RISCV specific DirectToIndirectFunctionCallsReplacement IR pass, that allows to make assembly jumps at any 64bit address without RISCV large code model, which has not been implemented yet.

I guess this summarizes it, but would be good to see actual example failures

@DavidSpickett
Copy link
Collaborator

Thanks for the patches (if we end up going down this route you'll probably want to split out the LLVM JIT changes into a separate PR).

I know little about the JIT side but this is my first reaction too. I wonder if that has its own tests that need adding, and it'll get more expert eyes on it.

without RISCV large code model, which has not been implemented yet

I presume the work to do this is much greater than the work shown here?

class ExecutionContext;

// During the lldb expression execution lldb wraps a user expression, jittes
// fabricated code and then puts it into the stack memory. Thus, if user tried
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is quite true. lldb asks the remote stub to allocate memory with read+write permissions for storing the arguments, and read+execute permissions for the jitted code, e.g.

(lldb) p (int)isdigit('1')
 <  13> send packet: $_M1000,rx#83
 <  13> read packet: $100008000#00
 <  13> send packet: $_M1000,rw#82
 <  13> read packet: $10000c000#00

It would be surprising (to me) if the stub returned memory regions on the stack, because lldb is allowed to reuse these regions throughout the debug session, and we can't have the inferior process overwriting them.

You are correct that the allocated regions may be too far from the function(s) they'll need to call, and the same problem you describe below could exist. I don't mean to focus on the "stack memory" part of this, but I think it will confuse people when they read it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your expression is simple enough to be interpreted by IRInterpreter, instead of be sent to JIT compiler, so in this case there are no stack allocations.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The arguments to the jitted code probably go to the stack (just like they would if you called the code "normally"), but I'd be very surprised if the code itself ended up on the stack (present-day architectures generally don't use executable stacks)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, lldb generates its own code that wraps expression, something like:

#line 1 "<lldb wrapper prefix>"                                                                                                                                                                                                                                                    
#ifndef offsetof                                                                                                                                                                                                                                                                   
#define offsetof(t, d) __builtin_offsetof(t, d)                                                                                                                                                                                                                                    
#endif                                                                                                                                                                                                                                                                             
#ifndef NULL                                                                                                                                                                                                                                                                       
#define NULL (__null)                                                                                                                                                                                                                                                              
#endif                                                                                                                                                                                                                                                                             
#ifndef Nil                                                                                                                                                                                                                                                                        
#define Nil (__null)                                                                                                                                                                                                                                                               
#endif                                                                                                                                                                                                                                                                             
#ifndef nil                                                                                                                                                                                                                                                                        
#define nil (__null)                                                                                                                                                                                                                                                               
#endif                                                                                                                                                                                                                                                                             
#ifndef YES                                                                                                                                                                                                                                                                        
#define YES ((BOOL)1)                                                                                                                                                                                                                                                              
#endif                                                                                                                                                                                                                                                                             
#ifndef NO                                                                                                                                                                                                                                                                         
#define NO ((BOOL)0)                                                                                                                                                                                                                                                               
#endif                                                                                                                                                                                                                                                                             
typedef __INT8_TYPE__ int8_t;                                                                                                                                                                                                                                                      
typedef __UINT8_TYPE__ uint8_t;                                                                                                                                                                                                                                                    
typedef __INT16_TYPE__ int16_t;                                                                                                                                                                                                                                                    
typedef __UINT16_TYPE__ uint16_t;                                                                                                                                                                                                                                                  
typedef __INT32_TYPE__ int32_t;                                                                                                                                                                                                                                                    
typedef __UINT32_TYPE__ uint32_t;                                                                                                                                                                                                                                                  
typedef __INT64_TYPE__ int64_t;                                                                                                                                                                                                                                                    
typedef __UINT64_TYPE__ uint64_t;                                                                                                                                                                                                                                                  
typedef __INTPTR_TYPE__ intptr_t;                                                                                                                                                                                                                                                  
typedef __UINTPTR_TYPE__ uintptr_t;                                                                                                                                                                                                                                                
typedef __SIZE_TYPE__ size_t;                                                                                                                                                                                                                                                      
typedef __PTRDIFF_TYPE__ ptrdiff_t;                                                                                                                                                                                                                                                
typedef unsigned short unichar;                                                                                                                                                                                                                                                    
extern "C"                                                                                                                                                                                                                                                                         
{                                                                                                                                                                                                                                                                                  
    int printf(const char * __restrict, ...);                                                                                                                                                                                                                                      
}                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                   
typedef signed char BOOL;                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                   
void                                                                                                                                                                                                                                                                               
$__lldb_expr(void *$__lldb_arg)                                                                                                                                                                                                                                                    
{                                                                                                                                                                                                                                                                                  
    ;                                                                                                                                                                                                                                                                              
#line 1 "<user expression 0>"                                                                                                                                                                                                                                                      
foo()                                                                                                                                                                                                                                                                              
;                                                                                                                                                                                                                                                                                  
#line 1 "<lldb wrapper suffix>"                                                                                                                                                                                                                                                    
}

So lldb have to puts this code somewhere, resolves relocations and executes. I have no idea where lldb can place the code except of the stack.

I've checked that on x86 lldb does the same:

lldb             IRMemoryMap::Malloc (79, 0x10, 0x6, eAllocationPolicyProcessOnly) -> 0x7ffff7fc7040                                                                                                                                                                               
lldb             IRMemoryMap::Malloc (1, 0x1, 0x2, eAllocationPolicyProcessOnly) -> 0x7ffff7fc8450                                                                                                                                                                                 
lldb             IRMemoryMap::Malloc (102, 0x1, 0x2, eAllocationPolicyProcessOnly) -> 0x7ffff7fc8460                                                                                                                                                                               
lldb             IRMemoryMap::Malloc (7, 0x4, 0x6, eAllocationPolicyProcessOnly) -> 0x7ffff7fc7090                                                                                                                                                                                 
lldb             IRMemoryMap::Malloc (31, 0x8, 0x2, eAllocationPolicyProcessOnly) -> 0x7ffff7fc84d0                                                                                                                                                                                
lldb             IRMemoryMap::Malloc (111, 0x1, 0x2, eAllocationPolicyProcessOnly) -> 0x7ffff7fc84f0                                                                                                                                                                               
lldb             IRMemoryMap::Malloc (1, 0x1, 0x2, eAllocationPolicyProcessOnly) -> 0x7ffff7fc8560                                                                                                                                                                                 
lldb             IRMemoryMap::Malloc (103, 0x8, 0x2, eAllocationPolicyProcessOnly) -> 0x7ffff7fc8570                                                                                                                                                                               
lldb             Function disassembly:
0x7ffff7fc7040: 55                             other       pushq  %rbp
0x7ffff7fc7041: 48 89 e5                       other       movq   %rsp, %rbp
0x7ffff7fc7044: 53                             other       pushq  %rbx
0x7ffff7fc7045: 50                             other       pushq  %rax
0x7ffff7fc7046: 48 89 fb                       other       movq   %rdi, %rbx
0x7ffff7fc7049: 48 8d 7d f0                    other       leaq   -0x10(%rbp), %rdi
0x7ffff7fc704d: 48 b9 00 70 fc f7 ff 7f 00 00  other       movabsq $0x7ffff7fc7000, %rcx ; imm = 0x7FFFF7FC7000 
0x7ffff7fc7057: b0 00                          other       movb   $0x0, %al
0x7ffff7fc7059: ff d1                          call        callq  *%rcx
0x7ffff7fc705b: 48 89 5d f0                    other       movq   %rbx, -0x10(%rbp)
0x7ffff7fc705f: 48 b8 29 51 55 55 55 55 00 00  other       movabsq $0x555555555129, %rax ; imm = 0x555555555129 
0x7ffff7fc7069: ff d0                          call        callq  *%rax
0x7ffff7fc706b: 48 83 c4 08                    other       addq   $0x8, %rsp
0x7ffff7fc706f: 5b                             other       popq   %rbx
0x7ffff7fc7070: 5d                             other       popq   %rbp
0x7ffff7fc7071: c3                             return      retq   

Copy link
Collaborator

@labath labath Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LLDB allocates memory inside the target process, either by calling mmap (that's what the PrepareTrivialCall function you're updating in this patch does), or through a server-specific mechanism (the _M packet).

Copy link

@tedwoodward tedwoodward Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've been doing some internal work to enable JIT on Hexagon, and we found that there are certain simple expressions that the IR interpreter doesn't handle, so they fall back to JIT. Ternary operators, for example. An expression like "(a == 2) : 10 ? 20" will run in JIT, not the IR interpreter.

As for memory, lldb will use the _M packet first, and if that fails (usually because the remote stub doesn't handle it), it will call mmap(). Some of the memory that lldb requests will be used for a stack, and some for the JITted code.

// addresses explicitly. By doing so it removes relocations related to function
// calls. This pass should be cosidered as temprorary solution until a large
// code model will be approved.
class DirectToIndirectFCR : public llvm::FunctionPass {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a minor detail, and I never work on the llvm side of the codebase so this is probably just my own ignorance, but: I have no idea what DirectToIndirectFCR means, beyond the explanation above. I'm sure to people more familiar with llvm/clang this is clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just Direct To Indirect Function Calls Replacement. Maybe it's not the best name, but I have a poor fantasy, so if you have any sugestions, feel free to leave them here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DirectCallReplacementPass ? Unless FCR is an established abbreviation in some areas of llvm, I think the name is too cryptic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed. Changed to DirectCallReplacementPass.

// relocations resolver obtains an invalid address. To avoid such problem, this
// pass should be used. It replaces function calls with appropriate function's
// addresses explicitly. By doing so it removes relocations related to function
// calls. This pass should be cosidered as temprorary solution until a large
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny nit: "cosidered", "temprorary". I do this all the time myself, just happened to see them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed. Tricky ones

@jasonmolenda
Copy link
Collaborator

jasonmolenda commented Jul 19, 2024

A quick look at the RISCV ISA and it says that the JAL instruction is pc relative and can jump +/- 1MB. JALR gets the upper 20 bits from a general purpose register and it includes 12 low bits in its instruction encoding. I know almost nothing about rv32, but is this what you mean by a Large Memory Model, the use of the JALR instruction? I didn't find the part that talks about how JALR works in rv64, but it seems likely it can specify an arbitrary 64-bit address?

@jasonmolenda
Copy link
Collaborator

As for getting to the jitted code, of course lldb sets the pc directly so that initial switch from user code to jitted code region is fine. But getting from the jitted wrapper function to the user functions we need to call would require JALR instructions?

Comment on lines 176 to 180
LLDB_LOG(log, "Writing %s: 0x%" PRIx64, reg_info->name,
static_cast<uint64_t>(value));
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, value)) {
LLDB_LOG(log, "Writing %s: failed", reg_info->name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll want to use LLDB_LOGF for printf-style formatters. LLDB_LOG (sans F) uses llvm's formatv formatters.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed. I've changed log messages.

Comment on lines 47 to 50
template <typename... Args> void LogMessage(const char *msg, Args &&...args) {
Log *log = GetLog(LLDBLog::Expressions);
LLDB_LOG(log, msg, std::forward<Args>(args)...);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this helper makes a lot of sense:

  • The goal is to get the log once (which is "expensive") and then have the macro just do a pointer check.
  • This also breaks the line attribution which is why that's a macro in the first place.

Please use the LOG macros directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed

Comment on lines 95 to 102
// eSymbolTypeCode: we try to find function
// eDebugNo: not a debug symbol
// eVisibilityExtern: function from extern module
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either make these named constant variables or use inline comment in the function call (e.g, /*argument_name=*/value)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed. Changed this place

@dlav-sc
Copy link
Contributor Author

dlav-sc commented Jul 22, 2024

Thanks for the patches (if we end up going down this route you'll probably want to split out the LLVM JIT changes into a separate PR).

I know little about the JIT side but this is my first reaction too. I wonder if that has its own tests that need adding, and it'll get more expert eyes on it.

without RISCV large code model, which has not been implemented yet

I presume the work to do this is much greater than the work shown here?

I presume the work to do this is much greater than the work shown here?

To be fair I'm not sure. We have this MR: riscv-non-isa/riscv-elf-psabi-doc#388 (comment) . This review is taking quite a while
already. So I presume there are some issue there. On the hand we can always disable the suggested path if needed.

I wonder if that has its own tests that need adding, and it'll get more expert eyes on it.

Well, for now I assume that existing tests are enough. Meaning we have a list of tests that start passing
after these patches are applied.

@dlav-sc
Copy link
Contributor Author

dlav-sc commented Jul 22, 2024

A quick look at the RISCV ISA and it says that the JAL instruction is pc relative and can jump +/- 1MB. JALR gets the upper 20 bits from a general purpose register and it includes 12 low bits in its instruction encoding. I know almost nothing about rv32, but is this what you mean by a Large Memory Model, the use of the JALR instruction? I didn't find the part that talks about how JALR works in rv64, but it seems likely it can specify an arbitrary 64-bit address?

I know almost nothing about rv32, but is this what you mean by a Large Memory Model, the use of the JALR instruction?

yep.

@dlav-sc
Copy link
Contributor Author

dlav-sc commented Jul 22, 2024

Thanks for the patches (if we end up going down this route you'll probably want to split out the LLVM JIT changes into a separate PR).

Not very familiar with RISCV. Could you elaborate on the exact failures you were seeing and why we need the extra IR pass?

Also it adds RISCV specific DirectToIndirectFunctionCallsReplacement IR pass, that allows to make assembly jumps at any 64bit address without RISCV large code model, which has not been implemented yet.

I guess this summarizes it, but would be good to see actual example failures

I guess this summarizes it, but would be good to see actual example failures

Consider a simple function call:

main.cpp:

void foo() {                                                                                                                                                                                                                                                                   
 int a = 42;
}                                                                                                                                                                                                                                                                  

int main() {                                                                                                                                                                                                                                                                                                                     
 foo();                                                                                                                                                                                                                                                                       
 return 0;                                                                                                                                                                                                                                                                    
} 
(lldb) file main.x
(lldb) b main
(lldb) run
(lldb) expr foo()

Before patch:

Lldb generates a wrapper, obtains its IR and tries to interpret it with IRInterpreter, but fails on a function call:

IR:

lldb             Module as passed in to IRForTarget: 
"; ModuleID = '$__lldb_module'
source_filename = "$__lldb_module"
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

; Function Attrs: convergent mustprogress noinline nounwind optnone
define dso_local void @"_Z12$__lldb_exprPv"(ptr %"$__lldb_arg") #0 {
entry:
  %"$__lldb_arg.addr" = alloca ptr, align 8, !clang.decl.ptr !8
  store ptr %"$__lldb_arg", ptr %"$__lldb_arg.addr", align 8
  call void @_Z3foov() #2
  ret void
}

; Function Attrs: convergent
declare void @_Z3foov() #1

attributes #0 = { convergent mustprogress noinline nounwind optnone "frame-pointer"="all" "no-builtins" "no-trapping-math"="true" "stack-protector-buffer-size"="0" "target-features"="+64bit" }
attributes #1 = { convergent "frame-pointer"="all" "no-builtins" "no-trapping-math"="true" "stack-protector-buffer-size"="0" "target-features"="+64bit" }
attributes #2 = { convergent "no-builtins" }

!llvm.module.flags = !{!0, !1, !2, !3, !4}
!clang.global.decl.ptrs = !{!5, !6}
!llvm.ident = !{!7}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 1, !"target-abi", !"lp64"}
!2 = !{i32 7, !"direct-access-external-data", i32 0}
!3 = !{i32 7, !"frame-pointer", i32 2}
!4 = !{i32 8, !"SmallDataLimit", i32 0}
!5 = !{ptr @"_Z12$__lldb_exprPv", i64 94163729942528}
!6 = !{ptr @_Z3foov, i64 94163729942816}
!7 = !{!"Syntacore clang version 18.1.4-sc (SC git:/tools/llvm/llvm-project/ fefe1910746c1b7e0e23cd64767b3f08ba788cf1)"}
!8 = !{i64 94163729942296}
"

Output:

lldb             Couldn't find result variable
lldb             MaybeHandleCallArguments(  call void @_Z3foov() #2)
lldb             Element arrangement:
lldb             Arg: "ptr %"$__lldb_arg""
lldb             Total structure [align 8, size 0]
lldb             Saw function with body: _Z12$__lldb_exprPv
lldb             Unsupported instruction: call void @_Z3foov() #2
lldb                 [ClangASTImporter] Forgetting destination (ASTContext*)0x000055A433716B10
lldb                 [ClangASTImporter] Forgetting source->dest (ASTContext*)0x000055A433716B10->(ASTContext*)0x000055A433A119D0
error: Can't evaluate the expression without a running target due to: Interpreter doesn't handle one of the expression's opcodes

After patch:

Lldb also generates a wrapper, obtains its IR but sends it to a JIT compiler instead of IRInterpreter. MCJIT generates an assembly, puts it into a process stack memory, resolves relocations and finally executes:

IR the same.

Assembly:

lldb             Function disassembly:                                                                                                                                                                                                                                             
0x3ff7fdd040: 13 01 01 fe  unknown     addi   sp, sp, -0x20                                                                                                                                                                                                                        
0x3ff7fdd044: 23 3c 11 00  unknown     sd     ra, 0x18(sp)                                                                                                                                                                                                                         
0x3ff7fdd048: 23 38 81 00  unknown     sd     s0, 0x10(sp)                                                                                                                                                                                                                         
0x3ff7fdd04c: 23 34 91 00  unknown     sd     s1, 0x8(sp)                                                                                                                                                                                                                          
0x3ff7fdd050: 13 04 01 02  unknown     addi   s0, sp, 0x20                                                                                                                                                                                                                         
0x3ff7fdd054: 93 04 05 00  unknown     mv     s1, a0                                                                                                                                                                                                                               
0x3ff7fdd058: 37 85 ff 03  unknown     lui    a0, 0x3ff8                                                                                                                                                                                                                           
0x3ff7fdd05c: 1b 05 d5 fd  unknown     addiw  a0, a0, -0x23                                                                                                                                                                                                                        
0x3ff7fdd060: 93 15 c5 00  unknown     slli   a1, a0, 0xc                                                                                                                                                                                                                          
0x3ff7fdd064: 13 05 04 fe  unknown     addi   a0, s0, -0x20                                                                                                                                                                                                                        
0x3ff7fdd068: e7 80 05 00  unknown     jalr   a1                                                                                                                                                                                                                                   
0x3ff7fdd06c: 23 30 94 fe  unknown     sd     s1, -0x20(s0)                                                                                                                                                                                                                        
0x3ff7fdd070: 37 55 55 01  unknown     lui    a0, 0x1555                                                                                                                                                                                                                           
0x3ff7fdd074: 1b 05 55 55  unknown     addiw  a0, a0, 0x555                                                                                                                                                                                                                        
0x3ff7fdd078: 13 15 d5 00  unknown     slli   a0, a0, 0xd                                                                                                                                                                                                                          
0x3ff7fdd07c: 13 05 85 62  unknown     addi   a0, a0, 0x628                                                                                                                                                                                                                        
0x3ff7fdd080: e7 00 05 00  unknown     jalr   a0                                                                                                                                                                                                                                   
0x3ff7fdd084: 83 30 81 01  unknown     ld     ra, 0x18(sp)                                                                                                                                                                                                                         
0x3ff7fdd088: 03 34 01 01  unknown     ld     s0, 0x10(sp)                                                                                                                                                                                                                         
0x3ff7fdd08c: 83 34 81 00  unknown     ld     s1, 0x8(sp)                                                                                                                                                                                                                          
0x3ff7fdd090: 13 01 01 02  unknown     addi   sp, sp, 0x20                                                                                                                                                                                                                         
0x3ff7fdd094: 67 80 00 00  unknown     ret

Puts assembly into a stack memory:

lldb             IRMemoryMap::Malloc (91, 0x4, 0x6, eAllocationPolicyProcessOnly) -> 0x3ff7fdd040                                                                                                                                                                                  
lldb             IRMemoryMap::Malloc (111, 0x1, 0x2, eAllocationPolicyProcessOnly) -> 0x3ff7fdc760                                                                                                                                                                                 
lldb             IRMemoryMap::Malloc (28, 0x1, 0x2, eAllocationPolicyProcessOnly) -> 0x3ff7fdc7d0                                                                                                                                                                                  
lldb             IRMemoryMap::Malloc (1, 0x1, 0x2, eAllocationPolicyProcessOnly) -> 0x3ff7fdc7f0                                                                                                                                                                                   
lldb             IRMemoryMap::Malloc (115, 0x1, 0x2, eAllocationPolicyProcessOnly) -> 0x3ff7fdc800                                                                                                                                                                                 
lldb             IRMemoryMap::Malloc (1, 0x1, 0x2, eAllocationPolicyProcessOnly) -> 0x3ff7fdc880                                                                                                                                                                                   
lldb             IRMemoryMap::Malloc (151, 0x8, 0x2, eAllocationPolicyProcessOnly) -> 0x3ff7fdc890                                                                                                                                                                                 
lldb             IRMemoryMap::WriteMemory (0x3ff7fdd040, 0x7f5352f50000, 0x88) went to [0x3ff7fdd040..0x3ff7fdd09b)                                                                                                                                                                
lldb             IRMemoryMap::WriteMemory (0x3ff7fdc760, 0x7f5352eea000, 0x111) went to [0x3ff7fdc760..0x3ff7fdc7cf)                                                                                                                                                               
lldb             IRMemoryMap::WriteMemory (0x3ff7fdc7d0, 0x7f5352eea06f, 0x28) went to [0x3ff7fdc7d0..0x3ff7fdc7ec)                                                                                                                                                                
lldb             IRMemoryMap::WriteMemory (0x3ff7fdc7f0, 0x7f5352eea08b, 0x1) went to [0x3ff7fdc7f0..0x3ff7fdc7f1)                                                                                                                                                                 
lldb             IRMemoryMap::WriteMemory (0x3ff7fdc800, 0x7f5352eea08c, 0x115) went to [0x3ff7fdc800..0x3ff7fdc873)                                                                                                                                                               
lldb             IRMemoryMap::WriteMemory (0x3ff7fdc880, 0x7f5352eea0ff, 0x1) went to [0x3ff7fdc880..0x3ff7fdc881)                                                                                                                                                                 
lldb             IRMemoryMap::WriteMemory (0x3ff7fdc890, 0x7f5352eea100, 0x144) went to [0x3ff7fdc890..0x3ff7fdc927)

Result:

lldb             -- [UserExpression::Execute] Execution of expression begins --
lldb             -- [UserExpression::Execute] Execution of expression completed --
lldb             -- [UserExpression::FinalizeJITExecution] Dematerializing after execution --
lldb             Materializer::Dematerialize (frame_sp = 0x55bcbe861a80, process_address = 0x3ff7fdb000) about to dematerialize:
lldb             == [UserExpression::Evaluate] Execution completed normally with no result ==

class ExecutionContext;

// During the lldb expression execution lldb wraps a user expression, jittes
// fabricated code and then puts it into the stack memory. Thus, if user tried
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The arguments to the jitted code probably go to the stack (just like they would if you called the code "normally"), but I'd be very surprised if the code itself ended up on the stack (present-day architectures generally don't use executable stacks)

// addresses explicitly. By doing so it removes relocations related to function
// calls. This pass should be cosidered as temprorary solution until a large
// code model will be approved.
class DirectToIndirectFCR : public llvm::FunctionPass {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DirectCallReplacementPass ? Unless FCR is an established abbreviation in some areas of llvm, I think the name is too cryptic.


std::optional<lldb::addr_t>
DirectToIndirectFCR::getFunctionAddress(const llvm::CallInst *ci) const {
auto *target = m_exe_ctx.GetTargetPtr();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you looked into the possibility of reusing the code which does symbol resolution/linking for "normal" expression evaluation (I'm not sure where that happens, but it must happen somewhere). Looking at this function, I see at least two problems:

  • it only looks for symbols in the main executable
  • it doesn't look for non-exported symbols (you probably want to be able to call static functions)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Large code model has been merged, so DirectToIndirectFCR pass is deprecated.

//
//===----------------------------------------------------------------------===//

#pragma once
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't do this in lldb. Please use a regular header guard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed

bool DirectToIndirectFCR::canBeReplaced(const llvm::CallInst *ci) {
assert(ci);
auto *return_value_ty = ci->getType();
if (!(return_value_ty->isIntegerTy() || return_value_ty->isVoidTy())) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly for my curiosity, what is the issue with other return types? Naively, I would have expected that, at the IR level, you could perform this kind of transformation for any return type.

Copy link
Contributor Author

@dlav-sc dlav-sc Jul 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have expected that, at the IR level, you could perform this kind of transformation for any return type.

As you've expected I really can apply this pass on functions with any arguments' and return value's types. I just filter unsupported for some reasons function calls.

As for doubles, I think that the problem is in the ABI or MCJIT, because the IR is correct, while the resulting assembly from JIT compiler doesn't contain even float instructions, needed to pass function arguments and get a return value. My RISCV machine supports a float extension, so the assembly should contain float instructions. Currently the result of such expressions is a trash, like:

(double) $1 = 3.3033229080945744E-319

so I've decided to remove function calls that takes double arguments or have double return value.

As for pointers, as such no problems with them.
But if in function that takes char* argument pass a row c string, there will be a SIGSEGV. Most interesting that if pass a variable the function successfully finished:

#include <stdio.h>                                                                                                                                                                                                                                                             

void foo(const char *msg) {                                                                                                                                                                                                                                                    
 printf("%s\n", msg);                                                                                                                                                                                                                                                         
}                                                                                                                                                                                                                                                                              

int main() {                                                                                                                                                                                                                                                                   
 const char *msg = "msg";                                                                                                                                                                                                                                                     
 foo(msg);                                                                                                                                                                                                                                                                    
} 
Process 302 stopped
* thread #1, name = 'pointer.x', stop reason = step over
    frame #0: 0x00000000000105cc pointer.x`main at pointer.cpp:9:6
   6   
   7    int main() {
   8      const char *msg = "msg";
-> 9      foo(msg);
   10   }
(lldb) expr foo("msg")
error: Execution was interrupted, reason: signal SIGSEGV: address not mapped to object (fault address: 0xfffffffff7b6d760).
The process has been returned to the state before expression evaluation.
(lldb) expr foo(msg)
msg
(lldb)

I think that the problem is in relocations.

Copy link
Collaborator

@labath labath Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that sounds like a relocation problem. And I think that's probably the same with floating point arguments. If the generated code looks anything like this, then you're going to need a relocation to access the float argument in another section.

While I don't think you need to submit a fully functional implementation straight away (in fact, maybe the opposite is better), since this patch also introduces the "architecture incompatibility" feature, I think it'd be preferable to either fix it or just let it crash, as both of those things will probably reduce the scope of the PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have fixed expressions with pointer arguments / return value: ee88a87
PIC option is needed for RISC-V 64, because otherwise wrong relocations will be placed.

@dlav-sc
Copy link
Contributor Author

dlav-sc commented Jul 25, 2024

A quick look at the RISCV ISA and it says that the JAL instruction is pc relative and can jump +/- 1MB. JALR gets the upper 20 bits from a general purpose register and it includes 12 low bits in its instruction encoding. I know almost nothing about rv32, but is this what you mean by a Large Memory Model, the use of the JALR instruction? I didn't find the part that talks about how JALR works in rv64, but it seems likely it can specify an arbitrary 64-bit address?

I didn't find the part that talks about how JALR works in rv64, but it seems likely it can specify an arbitrary 64-bit address?

Nope, you can't specify an arbitrary 64-bit address in RISCV now. Here riscv-non-isa/riscv-elf-psabi-doc#388 (comment) they write that if Large Code Model is approved then at least 6 instructions well be need to do it:

lui   t0, <highest20>
addi  t0, t0, <higher12>
slli  t0, 32
auipc t1, <hi20>
addi  t1, t1, t0
ld    t1, <lo12>(t1)

@labath
Copy link
Collaborator

labath commented Jul 26, 2024

A quick look at the RISCV ISA and it says that the JAL instruction is pc relative and can jump +/- 1MB. JALR gets the upper 20 bits from a general purpose register and it includes 12 low bits in its instruction encoding. I know almost nothing about rv32, but is this what you mean by a Large Memory Model, the use of the JALR instruction? I didn't find the part that talks about how JALR works in rv64, but it seems likely it can specify an arbitrary 64-bit address?

I didn't find the part that talks about how JALR works in rv64, but it seems likely it can specify an arbitrary 64-bit address?

Nope, you can't specify an arbitrary 64-bit address in RISCV now. Here riscv-non-isa/riscv-elf-psabi-doc#388 (comment) they write that if Large Code Model is approved then at least 6 instructions well be need to do it:

lui   t0, <highest20>
addi  t0, t0, <higher12>
slli  t0, 32
auipc t1, <hi20>
addi  t1, t1, t0
ld    t1, <lo12>(t1)

I don't suppose there's any chance of implementing some kind of provisional/experimental support for it in the compiler (since what you're basically doing here is implementing a large code model, but within a debugger)?

@tedwoodward
Copy link

Well, for now I assume that existing tests are enough. Meaning we have a list of tests that start passing
after these patches are applied.

How are you running the tests? We're working on getting the tests running in a sane fashion, using user space qemu.

@tedwoodward
Copy link

BTW, if you call SetCanInterpretFunctionCalls(true); somewhere, you can use the IR interpreter to call functions. PrepareTrivialCall below the implementation you do here, for JIT, handles that.

@dlav-sc dlav-sc force-pushed the dlav-sc/lldb-expr-func-calls branch 3 times, most recently from 8d1b7a4 to da97b8d Compare September 2, 2024 08:49
@dlav-sc
Copy link
Contributor Author

dlav-sc commented Sep 4, 2024

Well, for now I assume that existing tests are enough. Meaning we have a list of tests that start passing
after these patches are applied.

How are you running the tests? We're working on getting the tests running in a sane fashion, using user space qemu.

For now I just run Python API tests. They support remote debugging, so dotest.py has options like --platform-name, --platform-url and --platform-working-dir that I use to connect to qemu-system-riscv64 with lldb-server running on it.

@dlav-sc
Copy link
Contributor Author

dlav-sc commented Sep 18, 2024

That code doesn't look right.

Yeah, it looks really suspicious.

Shouldn't it be using eRISCV_float_abi_mask.

I think you are right.

@jasonmolenda
Copy link
Collaborator

As for lldb, maybe it can be useful to obtain features flags from ArchSpec, but I think this should be done in a separate PR, if you don't mind.

Yes, agree with doing this separately so we can get this PR landed.

Copy link
Collaborator

@jasonmolenda jasonmolenda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel like I am an authoritative owner of the parts being modified by this PR, but I am fine with this fwiw.

@DavidSpickett
Copy link
Collaborator

Reminder to update the PR description now that the large code model has been implemented over in llvm.

@dlav-sc dlav-sc force-pushed the dlav-sc/lldb-expr-func-calls branch 2 times, most recently from b9275b3 to bb86d31 Compare September 19, 2024 14:49
Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM too

But please wait a bit for @lhames to chime in about the RuntimeDyld changes in case he has any comments/ideas for testing those

@dlav-sc
Copy link
Contributor Author

dlav-sc commented Sep 25, 2024

@lhames could you take a look, please?

@lhames
Copy link
Contributor

lhames commented Sep 30, 2024

@lhames could you take a look, please?

Hi @dlav-sc. The RuntimeDyld changes look ok to me. We are hoping to switch LLDB to ORC / JITLink soon (https://discourse.llvm.org/t/rfc-removing-mcjit-and-runtimedyld/80464), but JITLink's RISCV support is pretty solid already -- I don't think we'll have any trouble moving over when we're ready.

If you want to test the RuntimeDyld changes you could add llvm-rtdyld tests (see llvm/test/ExecutionEngine/RuntimeDyld), but given that this is a stop-gap I'm ok with the changes going in as-is.

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

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.
Function calls support in LLDB expressions for RISCV: 2 of 4

Adds required RISCV relocations resolving functionality in lldb
ExecutionEngine.
Function calls support in LLDB expressions for RISCV: 3 of 4

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, that are
not available in RISC-V with medium code model.
Function calls support in LLDB expressions for RISCV: 4 of 4

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.
@dlav-sc
Copy link
Contributor Author

dlav-sc commented Oct 2, 2024

Thank you for the review.

@dlav-sc dlav-sc merged commit 8712140 into llvm:main Oct 2, 2024
8 checks passed
VitaNuo pushed a commit to VitaNuo/llvm-project that referenced this pull request Oct 2, 2024
[lldb][RISCV] add jitted function calls to ABI
Function calls support in LLDB expressions for RISCV: 1 of 4

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.

[lldb][RISCV] add JIT relocations resolver
Function calls support in LLDB expressions for RISCV: 2 of 4

Adds required RISCV relocations resolving functionality in lldb
ExecutionEngine.

[lldb][RISCV] RISC-V large code model in lldb expressions
Function calls support in LLDB expressions for RISCV: 3 of 4

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, that are
not available in RISC-V with medium code model.

[lldb][RISCV] doubles support in lldb expressions
Function calls support in LLDB expressions for RISCV: 4 of 4

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.
VitaNuo pushed a commit to VitaNuo/llvm-project that referenced this pull request Oct 2, 2024
[lldb][RISCV] add jitted function calls to ABI
Function calls support in LLDB expressions for RISCV: 1 of 4

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.

[lldb][RISCV] add JIT relocations resolver
Function calls support in LLDB expressions for RISCV: 2 of 4

Adds required RISCV relocations resolving functionality in lldb
ExecutionEngine.

[lldb][RISCV] RISC-V large code model in lldb expressions
Function calls support in LLDB expressions for RISCV: 3 of 4

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, that are
not available in RISC-V with medium code model.

[lldb][RISCV] doubles support in lldb expressions
Function calls support in LLDB expressions for RISCV: 4 of 4

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.
Sterling-Augustine pushed a commit to Sterling-Augustine/llvm-project that referenced this pull request Oct 3, 2024
[lldb][RISCV] add jitted function calls to ABI
Function calls support in LLDB expressions for RISCV: 1 of 4

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.

[lldb][RISCV] add JIT relocations resolver
Function calls support in LLDB expressions for RISCV: 2 of 4

Adds required RISCV relocations resolving functionality in lldb
ExecutionEngine.

[lldb][RISCV] RISC-V large code model in lldb expressions
Function calls support in LLDB expressions for RISCV: 3 of 4

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, that are
not available in RISC-V with medium code model.

[lldb][RISCV] doubles support in lldb expressions
Function calls support in LLDB expressions for RISCV: 4 of 4

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.
xgupta pushed a commit to xgupta/llvm-project that referenced this pull request Oct 4, 2024
[lldb][RISCV] add jitted function calls to ABI
Function calls support in LLDB expressions for RISCV: 1 of 4

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.

[lldb][RISCV] add JIT relocations resolver
Function calls support in LLDB expressions for RISCV: 2 of 4

Adds required RISCV relocations resolving functionality in lldb
ExecutionEngine.

[lldb][RISCV] RISC-V large code model in lldb expressions
Function calls support in LLDB expressions for RISCV: 3 of 4

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, that are
not available in RISC-V with medium code model.

[lldb][RISCV] doubles support in lldb expressions
Function calls support in LLDB expressions for RISCV: 4 of 4

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.
wangleiat added a commit that referenced this pull request Nov 8, 2024
This is necessary for supporting function calls in LLDB expressions for
LoongArch.
This patch is inspired by #99336 and simply extracts the parts related
to RuntimeDyld.

Reviewed By: lhames

Pull Request: #114741
wangleiat added a commit that referenced this pull request Nov 8, 2024
This patch adds desired feature flags in JIT compiler to enable
hard-float instructions if target supports them and allows to use floats
and doubles in lldb expressions.

Fited tests:
lldb-shell :: Expr/TestAnonNamespaceParamFunc.cpp
lldb-shell :: Expr/TestIRMemoryMap.test
lldb-shell :: Expr/TestStringLiteralExpr.test
lldb-shell :: SymbolFile/DWARF/debug-types-expressions.test

Similar as #99336
Depens on: #114741

Reviewed By: SixWeining

Pull Request: #114742
Groverkss pushed a commit to iree-org/llvm-project that referenced this pull request Nov 15, 2024
This is necessary for supporting function calls in LLDB expressions for
LoongArch.
This patch is inspired by llvm#99336 and simply extracts the parts related
to RuntimeDyld.

Reviewed By: lhames

Pull Request: llvm#114741
Groverkss pushed a commit to iree-org/llvm-project that referenced this pull request Nov 15, 2024
This patch adds desired feature flags in JIT compiler to enable
hard-float instructions if target supports them and allows to use floats
and doubles in lldb expressions.

Fited tests:
lldb-shell :: Expr/TestAnonNamespaceParamFunc.cpp
lldb-shell :: Expr/TestIRMemoryMap.test
lldb-shell :: Expr/TestStringLiteralExpr.test
lldb-shell :: SymbolFile/DWARF/debug-types-expressions.test

Similar as llvm#99336
Depens on: llvm#114741

Reviewed By: SixWeining

Pull Request: llvm#114742
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants