1696bd635SAlexander Shaposhnikov //===-- RenderScriptExpressionOpts.cpp --------------------------*- C++ -*-===// 219459580SLuke Drummond // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 619459580SLuke Drummond // 719459580SLuke Drummond //===----------------------------------------------------------------------===// 819459580SLuke Drummond 919459580SLuke Drummond #include <string> 1019459580SLuke Drummond 1119459580SLuke Drummond #include "llvm/ADT/None.h" 1219459580SLuke Drummond #include "llvm/ADT/StringRef.h" 1319459580SLuke Drummond #include "llvm/IR/Instruction.h" 1419459580SLuke Drummond #include "llvm/IR/Instructions.h" 1519459580SLuke Drummond #include "llvm/IR/LegacyPassManager.h" 1619459580SLuke Drummond #include "llvm/IR/Module.h" 1719459580SLuke Drummond #include "llvm/Support/TargetRegistry.h" 1819459580SLuke Drummond #include "llvm/Target/TargetMachine.h" 1919459580SLuke Drummond #include "llvm/Target/TargetOptions.h" 2019459580SLuke Drummond 2119459580SLuke Drummond #include "clang/Basic/TargetOptions.h" 2219459580SLuke Drummond 2319459580SLuke Drummond #include "lldb/Target/Process.h" 2419459580SLuke Drummond #include "lldb/Target/Target.h" 256f9e6901SZachary Turner #include "lldb/Utility/Log.h" 2619459580SLuke Drummond 2719459580SLuke Drummond #include "RenderScriptExpressionOpts.h" 2819459580SLuke Drummond #include "RenderScriptRuntime.h" 2919459580SLuke Drummond #include "RenderScriptx86ABIFixups.h" 3019459580SLuke Drummond 3119459580SLuke Drummond using namespace lldb_private; 3219459580SLuke Drummond using namespace lldb_renderscript; 3319459580SLuke Drummond 3419459580SLuke Drummond // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang), 35b9c1b51eSKate Stone // the compiler frontend for RenderScript embeds an ARM specific triple in IR 3605097246SAdrian Prantl // that is shipped in the app, after generating IR that has some assumptions 3705097246SAdrian Prantl // that an ARM device is the target. As the IR is then compiled on a device of 3805097246SAdrian Prantl // unknown (at time the IR was generated at least) architecture, when calling 3905097246SAdrian Prantl // RenderScript API function as part of debugger expressions, we have to 4005097246SAdrian Prantl // perform a fixup pass that removes those assumptions right before the module 4105097246SAdrian Prantl // is sent to be generated by the llvm backend. 4219459580SLuke Drummond 43b9c1b51eSKate Stone namespace { 44b9c1b51eSKate Stone bool registerRSDefaultTargetOpts(clang::TargetOptions &proto, 45b9c1b51eSKate Stone const llvm::Triple::ArchType &arch) { 46b9c1b51eSKate Stone switch (arch) { 4719459580SLuke Drummond case llvm::Triple::ArchType::x86: 4819459580SLuke Drummond proto.Triple = "i686--linux-android"; 4919459580SLuke Drummond proto.CPU = "atom"; 5019459580SLuke Drummond proto.Features.push_back("+long64"); 5119459580SLuke Drummond // Fallthrough for common x86 family features 52962364c6SGreg Clayton LLVM_FALLTHROUGH; 5319459580SLuke Drummond case llvm::Triple::ArchType::x86_64: 5419459580SLuke Drummond proto.Features.push_back("+mmx"); 5519459580SLuke Drummond proto.Features.push_back("+sse"); 5619459580SLuke Drummond proto.Features.push_back("+sse2"); 5719459580SLuke Drummond proto.Features.push_back("+sse3"); 5819459580SLuke Drummond proto.Features.push_back("+ssse3"); 5919459580SLuke Drummond proto.Features.push_back("+sse4.1"); 6019459580SLuke Drummond proto.Features.push_back("+sse4.2"); 6119459580SLuke Drummond break; 6219459580SLuke Drummond case llvm::Triple::ArchType::mipsel: 6319459580SLuke Drummond // pretend this is `arm' for the front-end 6419459580SLuke Drummond proto.Triple = "armv7-none-linux-android"; 6519459580SLuke Drummond proto.CPU = ""; 6619459580SLuke Drummond proto.Features.push_back("+long64"); 6719459580SLuke Drummond break; 6819459580SLuke Drummond case llvm::Triple::ArchType::mips64el: 6919459580SLuke Drummond // pretend this is `aarch64' for the front-end 7019459580SLuke Drummond proto.Triple = "aarch64-none-linux-android"; 7119459580SLuke Drummond proto.CPU = ""; 7219459580SLuke Drummond break; 7319459580SLuke Drummond default: 7419459580SLuke Drummond return false; 7519459580SLuke Drummond } 7619459580SLuke Drummond return true; 7719459580SLuke Drummond } 7819459580SLuke Drummond } // end anonymous namespace 7919459580SLuke Drummond 80b9c1b51eSKate Stone bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { 8119459580SLuke Drummond bool changed_module = false; 82b9c1b51eSKate Stone Log *log( 83b9c1b51eSKate Stone GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); 8419459580SLuke Drummond 8519459580SLuke Drummond std::string err; 86b9c1b51eSKate Stone llvm::StringRef real_triple = 87b9c1b51eSKate Stone m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple(); 88b9c1b51eSKate Stone const llvm::Target *target_info = 89b9c1b51eSKate Stone llvm::TargetRegistry::lookupTarget(real_triple, err); 90b9c1b51eSKate Stone if (!target_info) { 9119459580SLuke Drummond if (log) 92b9c1b51eSKate Stone log->Warning("couldn't determine real target architecture: '%s'", 93b9c1b51eSKate Stone err.c_str()); 9419459580SLuke Drummond return false; 9519459580SLuke Drummond } 9619459580SLuke Drummond 9719459580SLuke Drummond llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None; 9819459580SLuke Drummond assert(m_process_ptr && "no available lldb process"); 99b9c1b51eSKate Stone switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) { 10019459580SLuke Drummond case llvm::Triple::ArchType::x86: 10119459580SLuke Drummond changed_module |= fixupX86FunctionCalls(module); 102b9c1b51eSKate Stone // For some reason this triple gets totally missed by the backend, and must 10305097246SAdrian Prantl // be set manually. There a reference in bcc/Main.cpp about auto feature- 10405097246SAdrian Prantl // detection being removed from LLVM3.5, but I can't see that discussion 10505097246SAdrian Prantl // anywhere public. 10619459580SLuke Drummond real_triple = "i686--linux-android"; 10719459580SLuke Drummond break; 10819459580SLuke Drummond case llvm::Triple::ArchType::x86_64: 10919459580SLuke Drummond changed_module |= fixupX86_64FunctionCalls(module); 11019459580SLuke Drummond break; 11119459580SLuke Drummond case llvm::Triple::ArchType::mipsel: 11219459580SLuke Drummond case llvm::Triple::ArchType::mips64el: 11305097246SAdrian Prantl // No actual IR fixup pass is needed on MIPS, but the datalayout and 11405097246SAdrian Prantl // targetmachine do need to be explicitly set. 11519459580SLuke Drummond 11605097246SAdrian Prantl // bcc explicitly compiles MIPS code to use the static relocation model due 11705097246SAdrian Prantl // to an issue with relocations in mclinker. see 11805097246SAdrian Prantl // libbcc/support/CompilerConfig.cpp for details 11919459580SLuke Drummond reloc_model = llvm::Reloc::Static; 12019459580SLuke Drummond changed_module = true; 12119459580SLuke Drummond break; 12219459580SLuke Drummond case llvm::Triple::ArchType::arm: 12319459580SLuke Drummond case llvm::Triple::ArchType::aarch64: 124b9c1b51eSKate Stone // ARM subtargets need no fixup passes as they are the initial target as 125b9c1b51eSKate Stone // generated by the 12619459580SLuke Drummond // slang compiler frontend. 12719459580SLuke Drummond break; 12819459580SLuke Drummond default: 12919459580SLuke Drummond if (log) 13019459580SLuke Drummond log->Warning("Ignoring unknown renderscript target"); 13119459580SLuke Drummond return false; 13219459580SLuke Drummond } 13319459580SLuke Drummond 134b9c1b51eSKate Stone if (changed_module) { 13519459580SLuke Drummond llvm::TargetOptions options; 136b9c1b51eSKate Stone llvm::TargetMachine *target_machine = target_info->createTargetMachine( 137b9c1b51eSKate Stone real_triple, "", "", options, reloc_model); 138b9c1b51eSKate Stone assert(target_machine && 139b9c1b51eSKate Stone "failed to identify RenderScriptRuntime target machine"); 140b9c1b51eSKate Stone // We've been using a triple and datalayout of some ARM variant all along, 14105097246SAdrian Prantl // so we need to let the backend know that this is no longer the case. 142b9c1b51eSKate Stone if (log) { 143b9c1b51eSKate Stone log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__, 144b9c1b51eSKate Stone real_triple.str().c_str()); 145b9c1b51eSKate Stone log->Printf( 146b9c1b51eSKate Stone "%s - Changing RS datalayout to '%s'", __FUNCTION__, 14719459580SLuke Drummond target_machine->createDataLayout().getStringRepresentation().c_str()); 14819459580SLuke Drummond } 14919459580SLuke Drummond module.setTargetTriple(real_triple); 15019459580SLuke Drummond module.setDataLayout(target_machine->createDataLayout()); 15119459580SLuke Drummond } 15219459580SLuke Drummond return changed_module; 15319459580SLuke Drummond } 15419459580SLuke Drummond 15519459580SLuke Drummond char RenderScriptRuntimeModulePass::ID = 0; 15619459580SLuke Drummond 157b9c1b51eSKate Stone namespace lldb_private { 15819459580SLuke Drummond 159b9c1b51eSKate Stone bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) { 16019459580SLuke Drummond auto *process = GetProcess(); 16119459580SLuke Drummond assert(process); 162b9c1b51eSKate Stone return registerRSDefaultTargetOpts( 163b9c1b51eSKate Stone proto, process->GetTarget().GetArchitecture().GetMachine()); 16419459580SLuke Drummond } 16519459580SLuke Drummond 166b9c1b51eSKate Stone bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) { 16719459580SLuke Drummond if (!m_ir_passes) 16819459580SLuke Drummond m_ir_passes = new RSIRPasses(GetProcess()); 16919459580SLuke Drummond assert(m_ir_passes); 17019459580SLuke Drummond 17119459580SLuke Drummond passes.EarlyPasses = m_ir_passes->EarlyPasses; 17219459580SLuke Drummond passes.LatePasses = m_ir_passes->LatePasses; 17319459580SLuke Drummond 17419459580SLuke Drummond return true; 17519459580SLuke Drummond } 17619459580SLuke Drummond 177b9c1b51eSKate Stone namespace lldb_renderscript { 17819459580SLuke Drummond 179b9c1b51eSKate Stone RSIRPasses::RSIRPasses(Process *process) { 18019459580SLuke Drummond IRPasses(); 18119459580SLuke Drummond assert(process); 18219459580SLuke Drummond 18319459580SLuke Drummond EarlyPasses = std::make_shared<llvm::legacy::PassManager>(); 18419459580SLuke Drummond assert(EarlyPasses); 18519459580SLuke Drummond EarlyPasses->add(new RenderScriptRuntimeModulePass(process)); 18619459580SLuke Drummond } 18719459580SLuke Drummond 188b9c1b51eSKate Stone RSIRPasses::~RSIRPasses() {} 18919459580SLuke Drummond 19019459580SLuke Drummond } // namespace lldb_renderscript 19119459580SLuke Drummond } // namespace lldb_private 192