Add ability to override JIT expr compiler options.
authorAidan Dodds <aidan@codeplay.com>
Wed, 3 Feb 2016 12:33:05 +0000 (12:33 +0000)
committerAidan Dodds <aidan@codeplay.com>
Wed, 3 Feb 2016 12:33:05 +0000 (12:33 +0000)
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.

Committed for Luke Drummond.
Differential Revision: http://reviews.llvm.org/D15527

llvm-svn: 259644

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

index 686ec5e..20473e3 100644 (file)
@@ -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 {
 
@@ -147,6 +148,15 @@ public:
     {
     }
 
+    // Called by the Clang expression evaluation engine to allow runtimes to alter the set of target options provided to
+    // the compiler.
+    // If the options prototype is modified, runtimes must return true, false otherwise.
+    virtual bool
+    GetOverrideExprOptions(clang::TargetOptions &prototype)
+    {
+        return false;
+    }
+
 protected:
     //------------------------------------------------------------------
     // Classes that inherit from LanguageRuntime can see and modify these
index ff7d11f..01a155a 100644 (file)
@@ -64,6 +64,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Stream.h"
 #include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StringList.h"
 #include "lldb/Core/StreamString.h"
 #include "lldb/Expression/IRExecutionUnit.h"
 #include "lldb/Expression/IRDynamicChecks.h"
@@ -76,6 +77,7 @@
 #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;
@@ -166,37 +168,54 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
     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 = expr.Language(); // defaults to lldb::eLanguageTypeUnknown
+    bool overridden_target_opts = false;
+    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 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();
+
+    // Make sure the user hasn't provided a preferred execution language
+    // with `expression --language X -- ...`
+    if (frame && frame_lang == lldb::eLanguageTypeUnknown)
+        frame_lang = frame->GetLanguage();
+
+    if (frame_lang != lldb::eLanguageTypeUnknown)
+    {
+        lang_rt = exe_scope->CalculateProcess()->GetLanguageRuntime(frame_lang);
+        if (log)
+            log->Printf("Frame has language of type %s", Language::GetNameForLanguageType(frame_lang));
+    }
+
+    // 2. Configure the compiler with a set of default options that are appropriate
+    // for most situations.
     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 (3),
+        // below.
         m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
+        if (log)
+            log->Printf("Using default target triple of %s", m_compiler->getTargetOpts().Triple.c_str());
     }
-
-    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");
-    }
-
+    // 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 &&
@@ -204,17 +223,51 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
     {
         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");
+    }
 
-    m_compiler->createDiagnostics();
+    // 3. Now allow the runtime to provide custom configuration options for the target.
+    // In this case, a specialized language runtime is available and we can query it for extra options.
+    // For 99% of use cases, this will not be needed and should be provided when basic platform detection is not enough.
+    if (lang_rt)
+        overridden_target_opts = lang_rt->GetOverrideExprOptions(m_compiler->getTargetOpts());
 
-    // Create the target instance.
-    m_compiler->setTarget(TargetInfo::CreateTargetInfo(
-        m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts));
+    if (overridden_target_opts)
+        if (log)
+        {
+            log->Debug("Using overridden target options for the expression evaluation");
+
+            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());
+            StringList::LogDump(log, opts.FeaturesAsWritten, "FeaturesAsWritten");
+            StringList::LogDump(log, opts.Features, "Features");
+            StringList::LogDump(log, opts.Reciprocals, "Reciprocals");
+        }
 
-    assert (m_compiler->hasTarget());
+    // 4. Create and install the target on the compiler.
+    m_compiler->createDiagnostics();
+    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);
 
-    // 3. Set options.
+    assert (m_compiler->hasTarget());
 
+    // 5. Set language options.
     lldb::LanguageType language = expr.Language();
 
     switch (language)
@@ -321,11 +374,11 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
     // created. This complexity should be lifted elsewhere.
     m_compiler->getTarget().adjust(m_compiler->getLangOpts());
 
-    // 4. Set up the diagnostic buffer for reporting errors
+    // 6. 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
+    // 7. 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 +397,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
         m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks));
     }
         
-    // 6. Most of this we get from the CompilerInstance, but we
+    // 8. 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());