1*696bd635SAlexander Shaposhnikov //===-- RenderScriptExpressionOpts.cpp --------------------------*- C++ -*-===// 219459580SLuke Drummond // 319459580SLuke Drummond // The LLVM Compiler Infrastructure 419459580SLuke Drummond // 519459580SLuke Drummond // This file is distributed under the University of Illinois Open Source 619459580SLuke Drummond // License. See LICENSE.TXT for details. 719459580SLuke Drummond // 819459580SLuke Drummond //===----------------------------------------------------------------------===// 919459580SLuke Drummond 1019459580SLuke Drummond // C Includes 1119459580SLuke Drummond // C++ Includes 1219459580SLuke Drummond #include <string> 1319459580SLuke Drummond 1419459580SLuke Drummond // Other libraries and framework includes 1519459580SLuke Drummond #include "llvm/ADT/None.h" 1619459580SLuke Drummond #include "llvm/ADT/StringRef.h" 1719459580SLuke Drummond #include "llvm/IR/Instruction.h" 1819459580SLuke Drummond #include "llvm/IR/Instructions.h" 1919459580SLuke Drummond #include "llvm/IR/LegacyPassManager.h" 2019459580SLuke Drummond #include "llvm/IR/Module.h" 2119459580SLuke Drummond #include "llvm/Support/TargetRegistry.h" 2219459580SLuke Drummond #include "llvm/Target/TargetMachine.h" 2319459580SLuke Drummond #include "llvm/Target/TargetOptions.h" 2419459580SLuke Drummond 2519459580SLuke Drummond #include "clang/Basic/TargetOptions.h" 2619459580SLuke Drummond 2719459580SLuke Drummond // Project includes 2819459580SLuke Drummond #include "lldb/Core/Log.h" 2919459580SLuke Drummond #include "lldb/Target/Process.h" 3019459580SLuke Drummond #include "lldb/Target/Target.h" 3119459580SLuke Drummond 3219459580SLuke Drummond #include "RenderScriptExpressionOpts.h" 3319459580SLuke Drummond #include "RenderScriptRuntime.h" 3419459580SLuke Drummond #include "RenderScriptx86ABIFixups.h" 3519459580SLuke Drummond 3619459580SLuke Drummond using namespace lldb_private; 3719459580SLuke Drummond using namespace lldb_renderscript; 3819459580SLuke Drummond 3919459580SLuke Drummond // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang), 40b9c1b51eSKate Stone // the compiler frontend for RenderScript embeds an ARM specific triple in IR 41b9c1b51eSKate Stone // that is shipped in the app, after 4219459580SLuke Drummond // generating IR that has some assumptions that an ARM device is the target. 43b9c1b51eSKate Stone // As the IR is then compiled on a device of unknown (at time the IR was 44b9c1b51eSKate Stone // generated at least) architecture, 45b9c1b51eSKate Stone // when calling RenderScript API function as part of debugger expressions, we 46b9c1b51eSKate Stone // have to perform a fixup pass that 47b9c1b51eSKate Stone // removes those assumptions right before the module is sent to be generated by 48b9c1b51eSKate Stone // the llvm backend. 4919459580SLuke Drummond 50b9c1b51eSKate Stone namespace { 51b9c1b51eSKate Stone bool registerRSDefaultTargetOpts(clang::TargetOptions &proto, 52b9c1b51eSKate Stone const llvm::Triple::ArchType &arch) { 53b9c1b51eSKate Stone switch (arch) { 5419459580SLuke Drummond case llvm::Triple::ArchType::x86: 5519459580SLuke Drummond proto.Triple = "i686--linux-android"; 5619459580SLuke Drummond proto.CPU = "atom"; 5719459580SLuke Drummond proto.Features.push_back("+long64"); 5819459580SLuke Drummond // Fallthrough for common x86 family features 5919459580SLuke Drummond case llvm::Triple::ArchType::x86_64: 6019459580SLuke Drummond proto.Features.push_back("+mmx"); 6119459580SLuke Drummond proto.Features.push_back("+sse"); 6219459580SLuke Drummond proto.Features.push_back("+sse2"); 6319459580SLuke Drummond proto.Features.push_back("+sse3"); 6419459580SLuke Drummond proto.Features.push_back("+ssse3"); 6519459580SLuke Drummond proto.Features.push_back("+sse4.1"); 6619459580SLuke Drummond proto.Features.push_back("+sse4.2"); 6719459580SLuke Drummond break; 6819459580SLuke Drummond case llvm::Triple::ArchType::mipsel: 6919459580SLuke Drummond // pretend this is `arm' for the front-end 7019459580SLuke Drummond proto.Triple = "armv7-none-linux-android"; 7119459580SLuke Drummond proto.CPU = ""; 7219459580SLuke Drummond proto.Features.push_back("+long64"); 7319459580SLuke Drummond break; 7419459580SLuke Drummond case llvm::Triple::ArchType::mips64el: 7519459580SLuke Drummond // pretend this is `aarch64' for the front-end 7619459580SLuke Drummond proto.Triple = "aarch64-none-linux-android"; 7719459580SLuke Drummond proto.CPU = ""; 7819459580SLuke Drummond break; 7919459580SLuke Drummond default: 8019459580SLuke Drummond return false; 8119459580SLuke Drummond } 8219459580SLuke Drummond return true; 8319459580SLuke Drummond } 8419459580SLuke Drummond } // end anonymous namespace 8519459580SLuke Drummond 86b9c1b51eSKate Stone bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { 8719459580SLuke Drummond bool changed_module = false; 88b9c1b51eSKate Stone Log *log( 89b9c1b51eSKate Stone GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); 9019459580SLuke Drummond 9119459580SLuke Drummond std::string err; 92b9c1b51eSKate Stone llvm::StringRef real_triple = 93b9c1b51eSKate Stone m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple(); 94b9c1b51eSKate Stone const llvm::Target *target_info = 95b9c1b51eSKate Stone llvm::TargetRegistry::lookupTarget(real_triple, err); 96b9c1b51eSKate Stone if (!target_info) { 9719459580SLuke Drummond if (log) 98b9c1b51eSKate Stone log->Warning("couldn't determine real target architecture: '%s'", 99b9c1b51eSKate Stone err.c_str()); 10019459580SLuke Drummond return false; 10119459580SLuke Drummond } 10219459580SLuke Drummond 10319459580SLuke Drummond llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None; 10419459580SLuke Drummond assert(m_process_ptr && "no available lldb process"); 105b9c1b51eSKate Stone switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) { 10619459580SLuke Drummond case llvm::Triple::ArchType::x86: 10719459580SLuke Drummond changed_module |= fixupX86FunctionCalls(module); 108b9c1b51eSKate Stone // For some reason this triple gets totally missed by the backend, and must 109b9c1b51eSKate Stone // be set manually. 110b9c1b51eSKate Stone // There a reference in bcc/Main.cpp about auto feature-detection being 111b9c1b51eSKate Stone // removed from LLVM3.5, but I can't 11219459580SLuke Drummond // see that discussion anywhere public. 11319459580SLuke Drummond real_triple = "i686--linux-android"; 11419459580SLuke Drummond break; 11519459580SLuke Drummond case llvm::Triple::ArchType::x86_64: 11619459580SLuke Drummond changed_module |= fixupX86_64FunctionCalls(module); 11719459580SLuke Drummond break; 11819459580SLuke Drummond case llvm::Triple::ArchType::mipsel: 11919459580SLuke Drummond case llvm::Triple::ArchType::mips64el: 12019459580SLuke Drummond // No actual IR fixup pass is needed on MIPS, but the datalayout 12119459580SLuke Drummond // and targetmachine do need to be explicitly set. 12219459580SLuke Drummond 12319459580SLuke Drummond // bcc explicitly compiles MIPS code to use the static relocation 12419459580SLuke Drummond // model due to an issue with relocations in mclinker. 12519459580SLuke Drummond // see libbcc/support/CompilerConfig.cpp for details 12619459580SLuke Drummond reloc_model = llvm::Reloc::Static; 12719459580SLuke Drummond changed_module = true; 12819459580SLuke Drummond break; 12919459580SLuke Drummond case llvm::Triple::ArchType::arm: 13019459580SLuke Drummond case llvm::Triple::ArchType::aarch64: 131b9c1b51eSKate Stone // ARM subtargets need no fixup passes as they are the initial target as 132b9c1b51eSKate Stone // generated by the 13319459580SLuke Drummond // slang compiler frontend. 13419459580SLuke Drummond break; 13519459580SLuke Drummond default: 13619459580SLuke Drummond if (log) 13719459580SLuke Drummond log->Warning("Ignoring unknown renderscript target"); 13819459580SLuke Drummond return false; 13919459580SLuke Drummond } 14019459580SLuke Drummond 141b9c1b51eSKate Stone if (changed_module) { 14219459580SLuke Drummond llvm::TargetOptions options; 143b9c1b51eSKate Stone llvm::TargetMachine *target_machine = target_info->createTargetMachine( 144b9c1b51eSKate Stone real_triple, "", "", options, reloc_model); 145b9c1b51eSKate Stone assert(target_machine && 146b9c1b51eSKate Stone "failed to identify RenderScriptRuntime target machine"); 147b9c1b51eSKate Stone // We've been using a triple and datalayout of some ARM variant all along, 148b9c1b51eSKate Stone // so 14919459580SLuke Drummond // we need to let the backend know that this is no longer the case. 150b9c1b51eSKate Stone if (log) { 151b9c1b51eSKate Stone log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__, 152b9c1b51eSKate Stone real_triple.str().c_str()); 153b9c1b51eSKate Stone log->Printf( 154b9c1b51eSKate Stone "%s - Changing RS datalayout to '%s'", __FUNCTION__, 15519459580SLuke Drummond target_machine->createDataLayout().getStringRepresentation().c_str()); 15619459580SLuke Drummond } 15719459580SLuke Drummond module.setTargetTriple(real_triple); 15819459580SLuke Drummond module.setDataLayout(target_machine->createDataLayout()); 15919459580SLuke Drummond } 16019459580SLuke Drummond return changed_module; 16119459580SLuke Drummond } 16219459580SLuke Drummond 16319459580SLuke Drummond char RenderScriptRuntimeModulePass::ID = 0; 16419459580SLuke Drummond 165b9c1b51eSKate Stone namespace lldb_private { 16619459580SLuke Drummond 167b9c1b51eSKate Stone bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) { 16819459580SLuke Drummond auto *process = GetProcess(); 16919459580SLuke Drummond assert(process); 170b9c1b51eSKate Stone return registerRSDefaultTargetOpts( 171b9c1b51eSKate Stone proto, process->GetTarget().GetArchitecture().GetMachine()); 17219459580SLuke Drummond } 17319459580SLuke Drummond 174b9c1b51eSKate Stone bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) { 17519459580SLuke Drummond if (!m_ir_passes) 17619459580SLuke Drummond m_ir_passes = new RSIRPasses(GetProcess()); 17719459580SLuke Drummond assert(m_ir_passes); 17819459580SLuke Drummond 17919459580SLuke Drummond passes.EarlyPasses = m_ir_passes->EarlyPasses; 18019459580SLuke Drummond passes.LatePasses = m_ir_passes->LatePasses; 18119459580SLuke Drummond 18219459580SLuke Drummond return true; 18319459580SLuke Drummond } 18419459580SLuke Drummond 185b9c1b51eSKate Stone namespace lldb_renderscript { 18619459580SLuke Drummond 187b9c1b51eSKate Stone RSIRPasses::RSIRPasses(Process *process) { 18819459580SLuke Drummond IRPasses(); 18919459580SLuke Drummond assert(process); 19019459580SLuke Drummond 19119459580SLuke Drummond EarlyPasses = std::make_shared<llvm::legacy::PassManager>(); 19219459580SLuke Drummond assert(EarlyPasses); 19319459580SLuke Drummond EarlyPasses->add(new RenderScriptRuntimeModulePass(process)); 19419459580SLuke Drummond } 19519459580SLuke Drummond 196b9c1b51eSKate Stone RSIRPasses::~RSIRPasses() {} 19719459580SLuke Drummond 19819459580SLuke Drummond } // namespace lldb_renderscript 19919459580SLuke Drummond } // namespace lldb_private 200