ldrumm created this revision.
ldrumm added reviewers: clayborg, spyffe.
ldrumm added a subscriber: lldb-commits.
ldrumm set the repository for this revision to rL LLVM.

Runtimes should be able to pass custom compilation options to the JIT for their 
stack frame. This patch adds a custom expression options member class to 
LanguageOptions, and modifies the clang Expression evaluator to check the 
current runtime for those options. If those options are available on the 
runtime, they are passed to the clang compiler.

Repository:
  rL LLVM

http://reviews.llvm.org/D15527

Files:
  include/lldb/Target/LanguageRuntime.h
  source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp

Index: source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -76,11 +76,27 @@
 #include "lldb/Target/ObjCLanguageRuntime.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
+#include "lldb/Target/Language.h"
 
 using namespace clang;
 using namespace llvm;
 using namespace lldb_private;
 
+namespace {
+    void debugStringVector(Log *log, const std::vector<std::string>& vec, const char *name)
+    {
+        if(!log)
+            return;
+
+        log->Debug("Begin %s:", name);
+        for (const auto& s : vec)
+            log->Debug("%s", s.c_str());
+
+        log->Debug("End %s.", name);
+    }
+}
+
+
 //===----------------------------------------------------------------------===//
 // Utility Methods for Clang
 //===----------------------------------------------------------------------===//
@@ -166,54 +182,121 @@
     m_code_generator (),
     m_pp_callbacks(nullptr)
 {
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
     // 1. Create a new compiler instance.
     m_compiler.reset(new CompilerInstance());
-
-    // 2. Install the target.
-
+    lldb::LanguageType frame_lang = lldb::eLanguageTypeUnknown;
+    lldb_private::LanguageRuntime::OverrideExprOptions *target_opts_override = nullptr;
+    lldb_private::LanguageRuntime *lang_rt = nullptr;
     lldb::TargetSP target_sp;
     if (exe_scope)
         target_sp = exe_scope->CalculateTarget();
 
-    // TODO: figure out what to really do when we don't have a valid target.
-    // Sometimes this will be ok to just use the host target triple (when we
-    // evaluate say "2+3", but other expressions like breakpoint conditions
-    // and other things that _are_ target specific really shouldn't just be
-    // using the host triple. This needs to be fixed in a better way.
-    if (target_sp && target_sp->GetArchitecture().IsValid())
+    // If the expression is being evaluated in the context of an existing
+    // stack frame, we introspect to see if the language runtime is available.
+    auto frame = exe_scope->CalculateStackFrame();
+    if (frame)
+        frame_lang = frame->GetLanguage();
+
+    if (frame_lang != lldb::eLanguageTypeUnknown)
     {
-        std::string triple = target_sp->GetArchitecture().GetTriple().str();
-        m_compiler->getTargetOpts().Triple = triple;
+        lang_rt = exe_scope->CalculateProcess()->GetLanguageRuntime(frame_lang);
+        if (log)
+            log->Printf("Frame has language of type %s", Language::GetNameForLanguageType(frame_lang));
     }
-    else
+
+    // 2. Configure the target, overriding with any custom options we can get.
+    if (lang_rt)
     {
-        m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
+        // The expression is being evaluated in a known LanguageRuntime and StackFrame.
+        // We check if there are any overridden options for the evaluation, and configure
+        // the compiler appropriately.
+        target_opts_override = lang_rt->GetOverrideExprOptions();
     }
 
-    if (target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86 ||
-        target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
+    if (target_opts_override)
     {
-        m_compiler->getTargetOpts().Features.push_back("+sse");
-        m_compiler->getTargetOpts().Features.push_back("+sse2");
+        if (log)
+            log->Debug("Using overridden target options for the expression evaluation");
+
+        // If we get here this means the given language runtime has a custom set of code
+        // generation requirements, and they are configured from the language runtime.
+        m_compiler->getTargetOpts().Features = target_opts_override->Features;
+        m_compiler->getTargetOpts().CPU = target_opts_override->CPU;
+        m_compiler->getTargetOpts().Triple = target_opts_override->Triple;
+        m_compiler->getTargetOpts().FeaturesAsWritten = target_opts_override->FeaturesAsWritten;
+        m_compiler->getTargetOpts().Reciprocals = target_opts_override->Reciprocals;
+    }
+    else
+    {
+        // In this case, a specialized language runtime is not available and
+        // we have to fallback to making some basic assumptions on the target architecture.
+        // For 99% of use cases, this will be fine and is assumed to be the default.
+        if (target_sp && target_sp->GetArchitecture().IsValid())
+        {
+            std::string triple = target_sp->GetArchitecture().GetTriple().str();
+            m_compiler->getTargetOpts().Triple = triple;
+            if (log)
+                log->Printf("Using %s as the target triple", m_compiler->getTargetOpts().Triple.c_str());
+        }
+        else
+        {
+            // If we get here we don't have a valid target and just have to guess.
+            // Sometimes this will be ok to just use the host target triple (when we
+            // evaluate say "2+3", but other expressions like breakpoint conditions
+            // and other things that _are_ target specific really shouldn't just be
+            // using the host triple. In such a case the language runtime should
+            // expose an overridden options set rather than letting this default path execute.
+            m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
+            if (log)
+                log->Printf("Using default target triple of %s", m_compiler->getTargetOpts().Triple.c_str());
+        }
+        // Now add some special fixes for known architectures:
+        // Any arm32 iOS environment, but not on arm64
+        if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos &&
+            m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos &&
+            m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos)
+        {
+            m_compiler->getTargetOpts().ABI = "apcs-gnu";
+        }
+        // Supported subsets of x86
+        if (target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86 ||
+            target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
+        {
+            m_compiler->getTargetOpts().Features.push_back("+sse");
+            m_compiler->getTargetOpts().Features.push_back("+sse2");
+        }
     }
 
-    // Any arm32 iOS environment, but not on arm64
-    if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos &&
-        m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos &&
-        m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos)
+    if (log)
     {
-        m_compiler->getTargetOpts().ABI = "apcs-gnu";
+        auto opts = m_compiler->getTargetOpts();
+        log->Debug("Triple: '%s'", opts.Triple.c_str());
+        log->Debug("CPU: '%s'", opts.CPU.c_str());
+        log->Debug("FPMath: '%s'", opts.FPMath.c_str());
+        log->Debug("ABI: '%s'", opts.ABI.c_str());
+        log->Debug("LinkerVersion: '%s'", opts.LinkerVersion.c_str());
+        debugStringVector(log, opts.FeaturesAsWritten, "FeaturesAsWritten");
+        debugStringVector(log, opts.Features, "Features");
+        debugStringVector(log, opts.Reciprocals, "Reciprocals");
     }
 
+    // 3. Create and install the target on the compiler.
     m_compiler->createDiagnostics();
-
-    // Create the target instance.
-    m_compiler->setTarget(TargetInfo::CreateTargetInfo(
-        m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts));
+    auto target_info = TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts);
+    if (log)
+    {
+        log->Printf("Using SIMD alignment: %d", target_info->getSimdDefaultAlign());
+        log->Printf("Target datalayout string: '%s'", target_info->getDataLayoutString());
+        log->Printf("Target ABI: '%s'", target_info->getABI().str().c_str());
+        log->Printf("Target vector alignment: %d", target_info->getMaxVectorAlign());
+    }
+    m_compiler->setTarget(target_info);
 
     assert (m_compiler->hasTarget());
 
-    // 3. Set options.
+    // 4. Set language options.
 
     lldb::LanguageType language = expr.Language();
 
@@ -321,11 +404,11 @@
     // created. This complexity should be lifted elsewhere.
     m_compiler->getTarget().adjust(m_compiler->getLangOpts());
 
-    // 4. Set up the diagnostic buffer for reporting errors
+    // 5. Set up the diagnostic buffer for reporting errors
 
     m_compiler->getDiagnostics().setClient(new clang::TextDiagnosticBuffer);
 
-    // 5. Set up the source management objects inside the compiler
+    // 6. Set up the source management objects inside the compiler
 
     clang::FileSystemOptions file_system_options;
     m_file_manager.reset(new clang::FileManager(file_system_options));
@@ -344,7 +427,7 @@
         m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks));
     }
         
-    // 6. Most of this we get from the CompilerInstance, but we
+    // 7. Most of this we get from the CompilerInstance, but we
     // also want to give the context an ExternalASTSource.
     m_selector_table.reset(new SelectorTable());
     m_builtin_context.reset(new Builtin::Context());
Index: include/lldb/Target/LanguageRuntime.h
===================================================================
--- include/lldb/Target/LanguageRuntime.h
+++ include/lldb/Target/LanguageRuntime.h
@@ -22,6 +22,7 @@
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Core/Value.h"
 #include "lldb/Target/ExecutionContextScope.h"
+#include "clang/Basic/TargetOptions.h"
 
 namespace lldb_private {
 
@@ -30,6 +31,7 @@
 {
 public:
 
+    class OverrideExprOptions : public clang::TargetOptions {};
     ~LanguageRuntime() override;
     
     static LanguageRuntime* 
@@ -150,6 +152,18 @@
     {
     }
 
+    virtual OverrideExprOptions *
+    GetOverrideExprOptions()
+    {
+        return nullptr;
+    }
+
+    virtual bool
+    SetOverrideExprOptions(OverrideExprOptions *opts)
+    {
+        return false;
+    }
+
 protected:
     //------------------------------------------------------------------
     // Classes that inherit from LanguageRuntime can see and modify these
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to