| //===-- RenderScriptExpressionOpts.cpp --------------------------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include <string> |
| |
| #include "llvm/ADT/None.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/IR/Instruction.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/LegacyPassManager.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/TargetRegistry.h" |
| #include "llvm/Target/TargetMachine.h" |
| #include "llvm/Target/TargetOptions.h" |
| |
| #include "clang/Basic/TargetOptions.h" |
| |
| #include "lldb/Target/Process.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Utility/Log.h" |
| |
| #include "RenderScriptExpressionOpts.h" |
| #include "RenderScriptRuntime.h" |
| #include "RenderScriptx86ABIFixups.h" |
| |
| using namespace lldb_private; |
| using namespace lldb_renderscript; |
| |
| // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang), |
| // the compiler frontend for RenderScript embeds an ARM specific triple in IR |
| // that is shipped in the app, after generating IR that has some assumptions |
| // that an ARM device is the target. As the IR is then compiled on a device of |
| // unknown (at time the IR was generated at least) architecture, when calling |
| // RenderScript API function as part of debugger expressions, we have to |
| // perform a fixup pass that removes those assumptions right before the module |
| // is sent to be generated by the llvm backend. |
| |
| namespace { |
| bool registerRSDefaultTargetOpts(clang::TargetOptions &proto, |
| const llvm::Triple::ArchType &arch) { |
| switch (arch) { |
| case llvm::Triple::ArchType::x86: |
| proto.Triple = "i686--linux-android"; |
| proto.CPU = "atom"; |
| proto.Features.push_back("+long64"); |
| // Fallthrough for common x86 family features |
| LLVM_FALLTHROUGH; |
| case llvm::Triple::ArchType::x86_64: |
| proto.Features.push_back("+mmx"); |
| proto.Features.push_back("+sse"); |
| proto.Features.push_back("+sse2"); |
| proto.Features.push_back("+sse3"); |
| proto.Features.push_back("+ssse3"); |
| proto.Features.push_back("+sse4.1"); |
| proto.Features.push_back("+sse4.2"); |
| break; |
| case llvm::Triple::ArchType::mipsel: |
| // pretend this is `arm' for the front-end |
| proto.Triple = "armv7-none-linux-android"; |
| proto.CPU = ""; |
| proto.Features.push_back("+long64"); |
| break; |
| case llvm::Triple::ArchType::mips64el: |
| // pretend this is `aarch64' for the front-end |
| proto.Triple = "aarch64-none-linux-android"; |
| proto.CPU = ""; |
| break; |
| default: |
| return false; |
| } |
| return true; |
| } |
| } // end anonymous namespace |
| |
| bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { |
| bool changed_module = false; |
| Log *log( |
| GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); |
| |
| std::string err; |
| llvm::StringRef real_triple = |
| m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple(); |
| const llvm::Target *target_info = |
| llvm::TargetRegistry::lookupTarget(real_triple, err); |
| if (!target_info) { |
| if (log) |
| log->Warning("couldn't determine real target architecture: '%s'", |
| err.c_str()); |
| return false; |
| } |
| |
| llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None; |
| assert(m_process_ptr && "no available lldb process"); |
| switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) { |
| case llvm::Triple::ArchType::x86: |
| changed_module |= fixupX86FunctionCalls(module); |
| // For some reason this triple gets totally missed by the backend, and must |
| // be set manually. There a reference in bcc/Main.cpp about auto feature- |
| // detection being removed from LLVM3.5, but I can't see that discussion |
| // anywhere public. |
| real_triple = "i686--linux-android"; |
| break; |
| case llvm::Triple::ArchType::x86_64: |
| changed_module |= fixupX86_64FunctionCalls(module); |
| break; |
| case llvm::Triple::ArchType::mipsel: |
| case llvm::Triple::ArchType::mips64el: |
| // No actual IR fixup pass is needed on MIPS, but the datalayout and |
| // targetmachine do need to be explicitly set. |
| |
| // bcc explicitly compiles MIPS code to use the static relocation model due |
| // to an issue with relocations in mclinker. see |
| // libbcc/support/CompilerConfig.cpp for details |
| reloc_model = llvm::Reloc::Static; |
| changed_module = true; |
| break; |
| case llvm::Triple::ArchType::arm: |
| case llvm::Triple::ArchType::aarch64: |
| // ARM subtargets need no fixup passes as they are the initial target as |
| // generated by the |
| // slang compiler frontend. |
| break; |
| default: |
| if (log) |
| log->Warning("Ignoring unknown renderscript target"); |
| return false; |
| } |
| |
| if (changed_module) { |
| llvm::TargetOptions options; |
| llvm::TargetMachine *target_machine = target_info->createTargetMachine( |
| real_triple, "", "", options, reloc_model); |
| assert(target_machine && |
| "failed to identify RenderScriptRuntime target machine"); |
| // We've been using a triple and datalayout of some ARM variant all along, |
| // so we need to let the backend know that this is no longer the case. |
| if (log) { |
| log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__, |
| real_triple.str().c_str()); |
| log->Printf( |
| "%s - Changing RS datalayout to '%s'", __FUNCTION__, |
| target_machine->createDataLayout().getStringRepresentation().c_str()); |
| } |
| module.setTargetTriple(real_triple); |
| module.setDataLayout(target_machine->createDataLayout()); |
| } |
| return changed_module; |
| } |
| |
| char RenderScriptRuntimeModulePass::ID = 0; |
| |
| namespace lldb_private { |
| |
| bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) { |
| auto *process = GetProcess(); |
| assert(process); |
| return registerRSDefaultTargetOpts( |
| proto, process->GetTarget().GetArchitecture().GetMachine()); |
| } |
| |
| bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) { |
| if (!m_ir_passes) |
| m_ir_passes = new RSIRPasses(GetProcess()); |
| assert(m_ir_passes); |
| |
| passes.EarlyPasses = m_ir_passes->EarlyPasses; |
| passes.LatePasses = m_ir_passes->LatePasses; |
| |
| return true; |
| } |
| |
| namespace lldb_renderscript { |
| |
| RSIRPasses::RSIRPasses(Process *process) { |
| IRPasses(); |
| assert(process); |
| |
| EarlyPasses = std::make_shared<llvm::legacy::PassManager>(); |
| assert(EarlyPasses); |
| EarlyPasses->add(new RenderScriptRuntimeModulePass(process)); |
| } |
| |
| RSIRPasses::~RSIRPasses() {} |
| |
| } // namespace lldb_renderscript |
| } // namespace lldb_private |