15ffd83dbSDimitry Andric //===-- RenderScriptExpressionOpts.cpp ------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include <string>
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "llvm/ADT/None.h"
120b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
130b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
140b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
150b57cec5SDimitry Andric #include "llvm/IR/LegacyPassManager.h"
160b57cec5SDimitry Andric #include "llvm/IR/Module.h"
170b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h"
180b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
190b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #include "clang/Basic/TargetOptions.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #include "lldb/Target/Process.h"
240b57cec5SDimitry Andric #include "lldb/Target/Target.h"
250b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #include "RenderScriptExpressionOpts.h"
280b57cec5SDimitry Andric #include "RenderScriptRuntime.h"
290b57cec5SDimitry Andric #include "RenderScriptx86ABIFixups.h"
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace lldb_private;
320b57cec5SDimitry Andric using namespace lldb_renderscript;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang),
350b57cec5SDimitry Andric // the compiler frontend for RenderScript embeds an ARM specific triple in IR
360b57cec5SDimitry Andric // that is shipped in the app, after generating IR that has some assumptions
370b57cec5SDimitry Andric // that an ARM device is the target. As the IR is then compiled on a device of
380b57cec5SDimitry Andric // unknown (at time the IR was generated at least) architecture, when calling
390b57cec5SDimitry Andric // RenderScript API function as part of debugger expressions, we have to
400b57cec5SDimitry Andric // perform a fixup pass that removes those assumptions right before the module
410b57cec5SDimitry Andric // is sent to be generated by the llvm backend.
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric namespace {
registerRSDefaultTargetOpts(clang::TargetOptions & proto,const llvm::Triple::ArchType & arch)440b57cec5SDimitry Andric bool registerRSDefaultTargetOpts(clang::TargetOptions &proto,
450b57cec5SDimitry Andric                                  const llvm::Triple::ArchType &arch) {
460b57cec5SDimitry Andric   switch (arch) {
470b57cec5SDimitry Andric   case llvm::Triple::ArchType::x86:
480b57cec5SDimitry Andric     proto.Triple = "i686--linux-android";
490b57cec5SDimitry Andric     proto.CPU = "atom";
500b57cec5SDimitry Andric     proto.Features.push_back("+long64");
510b57cec5SDimitry Andric     // Fallthrough for common x86 family features
520b57cec5SDimitry Andric     LLVM_FALLTHROUGH;
530b57cec5SDimitry Andric   case llvm::Triple::ArchType::x86_64:
540b57cec5SDimitry Andric     proto.Features.push_back("+mmx");
550b57cec5SDimitry Andric     proto.Features.push_back("+sse");
560b57cec5SDimitry Andric     proto.Features.push_back("+sse2");
570b57cec5SDimitry Andric     proto.Features.push_back("+sse3");
580b57cec5SDimitry Andric     proto.Features.push_back("+ssse3");
590b57cec5SDimitry Andric     proto.Features.push_back("+sse4.1");
600b57cec5SDimitry Andric     proto.Features.push_back("+sse4.2");
610b57cec5SDimitry Andric     break;
620b57cec5SDimitry Andric   case llvm::Triple::ArchType::mipsel:
630b57cec5SDimitry Andric     // pretend this is `arm' for the front-end
640b57cec5SDimitry Andric     proto.Triple = "armv7-none-linux-android";
650b57cec5SDimitry Andric     proto.CPU = "";
660b57cec5SDimitry Andric     proto.Features.push_back("+long64");
670b57cec5SDimitry Andric     break;
680b57cec5SDimitry Andric   case llvm::Triple::ArchType::mips64el:
690b57cec5SDimitry Andric     // pretend this is `aarch64' for the front-end
700b57cec5SDimitry Andric     proto.Triple = "aarch64-none-linux-android";
710b57cec5SDimitry Andric     proto.CPU = "";
720b57cec5SDimitry Andric     break;
730b57cec5SDimitry Andric   default:
740b57cec5SDimitry Andric     return false;
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric   return true;
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric } // end anonymous namespace
790b57cec5SDimitry Andric 
runOnModule(llvm::Module & module)800b57cec5SDimitry Andric bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) {
810b57cec5SDimitry Andric   bool changed_module = false;
820b57cec5SDimitry Andric   Log *log(
830b57cec5SDimitry Andric       GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS));
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   std::string err;
860b57cec5SDimitry Andric   llvm::StringRef real_triple =
870b57cec5SDimitry Andric       m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple();
880b57cec5SDimitry Andric   const llvm::Target *target_info =
895ffd83dbSDimitry Andric       llvm::TargetRegistry::lookupTarget(std::string(real_triple), err);
900b57cec5SDimitry Andric   if (!target_info) {
910b57cec5SDimitry Andric     if (log)
920b57cec5SDimitry Andric       log->Warning("couldn't determine real target architecture: '%s'",
930b57cec5SDimitry Andric                    err.c_str());
940b57cec5SDimitry Andric     return false;
950b57cec5SDimitry Andric   }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None;
980b57cec5SDimitry Andric   assert(m_process_ptr && "no available lldb process");
990b57cec5SDimitry Andric   switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) {
1000b57cec5SDimitry Andric   case llvm::Triple::ArchType::x86:
1010b57cec5SDimitry Andric     changed_module |= fixupX86FunctionCalls(module);
1020b57cec5SDimitry Andric     // For some reason this triple gets totally missed by the backend, and must
1030b57cec5SDimitry Andric     // be set manually. There a reference in bcc/Main.cpp about auto feature-
1040b57cec5SDimitry Andric     // detection being removed from LLVM3.5, but I can't see that discussion
1050b57cec5SDimitry Andric     // anywhere public.
1060b57cec5SDimitry Andric     real_triple = "i686--linux-android";
1070b57cec5SDimitry Andric     break;
1080b57cec5SDimitry Andric   case llvm::Triple::ArchType::x86_64:
1090b57cec5SDimitry Andric     changed_module |= fixupX86_64FunctionCalls(module);
1100b57cec5SDimitry Andric     break;
1110b57cec5SDimitry Andric   case llvm::Triple::ArchType::mipsel:
1120b57cec5SDimitry Andric   case llvm::Triple::ArchType::mips64el:
1130b57cec5SDimitry Andric     // No actual IR fixup pass is needed on MIPS, but the datalayout and
1140b57cec5SDimitry Andric     // targetmachine do need to be explicitly set.
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric     // bcc explicitly compiles MIPS code to use the static relocation model due
1170b57cec5SDimitry Andric     // to an issue with relocations in mclinker. see
1180b57cec5SDimitry Andric     // libbcc/support/CompilerConfig.cpp for details
1190b57cec5SDimitry Andric     reloc_model = llvm::Reloc::Static;
1200b57cec5SDimitry Andric     changed_module = true;
1210b57cec5SDimitry Andric     break;
1220b57cec5SDimitry Andric   case llvm::Triple::ArchType::arm:
1230b57cec5SDimitry Andric   case llvm::Triple::ArchType::aarch64:
1240b57cec5SDimitry Andric     // ARM subtargets need no fixup passes as they are the initial target as
1250b57cec5SDimitry Andric     // generated by the
1260b57cec5SDimitry Andric     // slang compiler frontend.
1270b57cec5SDimitry Andric     break;
1280b57cec5SDimitry Andric   default:
1290b57cec5SDimitry Andric     if (log)
1300b57cec5SDimitry Andric       log->Warning("Ignoring unknown renderscript target");
1310b57cec5SDimitry Andric     return false;
1320b57cec5SDimitry Andric   }
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   if (changed_module) {
1350b57cec5SDimitry Andric     llvm::TargetOptions options;
1360b57cec5SDimitry Andric     llvm::TargetMachine *target_machine = target_info->createTargetMachine(
1370b57cec5SDimitry Andric         real_triple, "", "", options, reloc_model);
1380b57cec5SDimitry Andric     assert(target_machine &&
1390b57cec5SDimitry Andric            "failed to identify RenderScriptRuntime target machine");
1400b57cec5SDimitry Andric     // We've been using a triple and datalayout of some ARM variant all along,
1410b57cec5SDimitry Andric     // so we need to let the backend know that this is no longer the case.
1420b57cec5SDimitry Andric     if (log) {
1439dba64beSDimitry Andric       LLDB_LOGF(log, "%s - Changing RS target triple to '%s'", __FUNCTION__,
1440b57cec5SDimitry Andric                 real_triple.str().c_str());
1459dba64beSDimitry Andric       LLDB_LOGF(
1469dba64beSDimitry Andric           log, "%s - Changing RS datalayout to '%s'", __FUNCTION__,
1470b57cec5SDimitry Andric           target_machine->createDataLayout().getStringRepresentation().c_str());
1480b57cec5SDimitry Andric     }
1490b57cec5SDimitry Andric     module.setTargetTriple(real_triple);
1500b57cec5SDimitry Andric     module.setDataLayout(target_machine->createDataLayout());
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric   return changed_module;
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric char RenderScriptRuntimeModulePass::ID = 0;
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric namespace lldb_private {
1580b57cec5SDimitry Andric 
GetOverrideExprOptions(clang::TargetOptions & proto)1590b57cec5SDimitry Andric bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) {
1600b57cec5SDimitry Andric   auto *process = GetProcess();
1610b57cec5SDimitry Andric   assert(process);
1620b57cec5SDimitry Andric   return registerRSDefaultTargetOpts(
1630b57cec5SDimitry Andric       proto, process->GetTarget().GetArchitecture().GetMachine());
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
GetIRPasses(LLVMUserExpression::IRPasses & passes)1660b57cec5SDimitry Andric bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) {
1670b57cec5SDimitry Andric   if (!m_ir_passes)
1680b57cec5SDimitry Andric     m_ir_passes = new RSIRPasses(GetProcess());
1690b57cec5SDimitry Andric   assert(m_ir_passes);
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   passes.EarlyPasses = m_ir_passes->EarlyPasses;
1720b57cec5SDimitry Andric   passes.LatePasses = m_ir_passes->LatePasses;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   return true;
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric namespace lldb_renderscript {
1780b57cec5SDimitry Andric 
RSIRPasses(Process * process)1790b57cec5SDimitry Andric RSIRPasses::RSIRPasses(Process *process) {
1800b57cec5SDimitry Andric   IRPasses();
1810b57cec5SDimitry Andric   assert(process);
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   EarlyPasses = std::make_shared<llvm::legacy::PassManager>();
1840b57cec5SDimitry Andric   assert(EarlyPasses);
1850b57cec5SDimitry Andric   EarlyPasses->add(new RenderScriptRuntimeModulePass(process));
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
188*5f7ddb14SDimitry Andric RSIRPasses::~RSIRPasses() = default;
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric } // namespace lldb_renderscript
1910b57cec5SDimitry Andric } // namespace lldb_private
192