1696bd635SAlexander 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 59*962364c6SGreg Clayton LLVM_FALLTHROUGH; 6019459580SLuke Drummond case llvm::Triple::ArchType::x86_64: 6119459580SLuke Drummond proto.Features.push_back("+mmx"); 6219459580SLuke Drummond proto.Features.push_back("+sse"); 6319459580SLuke Drummond proto.Features.push_back("+sse2"); 6419459580SLuke Drummond proto.Features.push_back("+sse3"); 6519459580SLuke Drummond proto.Features.push_back("+ssse3"); 6619459580SLuke Drummond proto.Features.push_back("+sse4.1"); 6719459580SLuke Drummond proto.Features.push_back("+sse4.2"); 6819459580SLuke Drummond break; 6919459580SLuke Drummond case llvm::Triple::ArchType::mipsel: 7019459580SLuke Drummond // pretend this is `arm' for the front-end 7119459580SLuke Drummond proto.Triple = "armv7-none-linux-android"; 7219459580SLuke Drummond proto.CPU = ""; 7319459580SLuke Drummond proto.Features.push_back("+long64"); 7419459580SLuke Drummond break; 7519459580SLuke Drummond case llvm::Triple::ArchType::mips64el: 7619459580SLuke Drummond // pretend this is `aarch64' for the front-end 7719459580SLuke Drummond proto.Triple = "aarch64-none-linux-android"; 7819459580SLuke Drummond proto.CPU = ""; 7919459580SLuke Drummond break; 8019459580SLuke Drummond default: 8119459580SLuke Drummond return false; 8219459580SLuke Drummond } 8319459580SLuke Drummond return true; 8419459580SLuke Drummond } 8519459580SLuke Drummond } // end anonymous namespace 8619459580SLuke Drummond 87b9c1b51eSKate Stone bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { 8819459580SLuke Drummond bool changed_module = false; 89b9c1b51eSKate Stone Log *log( 90b9c1b51eSKate Stone GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); 9119459580SLuke Drummond 9219459580SLuke Drummond std::string err; 93b9c1b51eSKate Stone llvm::StringRef real_triple = 94b9c1b51eSKate Stone m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple(); 95b9c1b51eSKate Stone const llvm::Target *target_info = 96b9c1b51eSKate Stone llvm::TargetRegistry::lookupTarget(real_triple, err); 97b9c1b51eSKate Stone if (!target_info) { 9819459580SLuke Drummond if (log) 99b9c1b51eSKate Stone log->Warning("couldn't determine real target architecture: '%s'", 100b9c1b51eSKate Stone err.c_str()); 10119459580SLuke Drummond return false; 10219459580SLuke Drummond } 10319459580SLuke Drummond 10419459580SLuke Drummond llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None; 10519459580SLuke Drummond assert(m_process_ptr && "no available lldb process"); 106b9c1b51eSKate Stone switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) { 10719459580SLuke Drummond case llvm::Triple::ArchType::x86: 10819459580SLuke Drummond changed_module |= fixupX86FunctionCalls(module); 109b9c1b51eSKate Stone // For some reason this triple gets totally missed by the backend, and must 110b9c1b51eSKate Stone // be set manually. 111b9c1b51eSKate Stone // There a reference in bcc/Main.cpp about auto feature-detection being 112b9c1b51eSKate Stone // removed from LLVM3.5, but I can't 11319459580SLuke Drummond // see that discussion anywhere public. 11419459580SLuke Drummond real_triple = "i686--linux-android"; 11519459580SLuke Drummond break; 11619459580SLuke Drummond case llvm::Triple::ArchType::x86_64: 11719459580SLuke Drummond changed_module |= fixupX86_64FunctionCalls(module); 11819459580SLuke Drummond break; 11919459580SLuke Drummond case llvm::Triple::ArchType::mipsel: 12019459580SLuke Drummond case llvm::Triple::ArchType::mips64el: 12119459580SLuke Drummond // No actual IR fixup pass is needed on MIPS, but the datalayout 12219459580SLuke Drummond // and targetmachine do need to be explicitly set. 12319459580SLuke Drummond 12419459580SLuke Drummond // bcc explicitly compiles MIPS code to use the static relocation 12519459580SLuke Drummond // model due to an issue with relocations in mclinker. 12619459580SLuke Drummond // see libbcc/support/CompilerConfig.cpp for details 12719459580SLuke Drummond reloc_model = llvm::Reloc::Static; 12819459580SLuke Drummond changed_module = true; 12919459580SLuke Drummond break; 13019459580SLuke Drummond case llvm::Triple::ArchType::arm: 13119459580SLuke Drummond case llvm::Triple::ArchType::aarch64: 132b9c1b51eSKate Stone // ARM subtargets need no fixup passes as they are the initial target as 133b9c1b51eSKate Stone // generated by the 13419459580SLuke Drummond // slang compiler frontend. 13519459580SLuke Drummond break; 13619459580SLuke Drummond default: 13719459580SLuke Drummond if (log) 13819459580SLuke Drummond log->Warning("Ignoring unknown renderscript target"); 13919459580SLuke Drummond return false; 14019459580SLuke Drummond } 14119459580SLuke Drummond 142b9c1b51eSKate Stone if (changed_module) { 14319459580SLuke Drummond llvm::TargetOptions options; 144b9c1b51eSKate Stone llvm::TargetMachine *target_machine = target_info->createTargetMachine( 145b9c1b51eSKate Stone real_triple, "", "", options, reloc_model); 146b9c1b51eSKate Stone assert(target_machine && 147b9c1b51eSKate Stone "failed to identify RenderScriptRuntime target machine"); 148b9c1b51eSKate Stone // We've been using a triple and datalayout of some ARM variant all along, 149b9c1b51eSKate Stone // so 15019459580SLuke Drummond // we need to let the backend know that this is no longer the case. 151b9c1b51eSKate Stone if (log) { 152b9c1b51eSKate Stone log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__, 153b9c1b51eSKate Stone real_triple.str().c_str()); 154b9c1b51eSKate Stone log->Printf( 155b9c1b51eSKate Stone "%s - Changing RS datalayout to '%s'", __FUNCTION__, 15619459580SLuke Drummond target_machine->createDataLayout().getStringRepresentation().c_str()); 15719459580SLuke Drummond } 15819459580SLuke Drummond module.setTargetTriple(real_triple); 15919459580SLuke Drummond module.setDataLayout(target_machine->createDataLayout()); 16019459580SLuke Drummond } 16119459580SLuke Drummond return changed_module; 16219459580SLuke Drummond } 16319459580SLuke Drummond 16419459580SLuke Drummond char RenderScriptRuntimeModulePass::ID = 0; 16519459580SLuke Drummond 166b9c1b51eSKate Stone namespace lldb_private { 16719459580SLuke Drummond 168b9c1b51eSKate Stone bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) { 16919459580SLuke Drummond auto *process = GetProcess(); 17019459580SLuke Drummond assert(process); 171b9c1b51eSKate Stone return registerRSDefaultTargetOpts( 172b9c1b51eSKate Stone proto, process->GetTarget().GetArchitecture().GetMachine()); 17319459580SLuke Drummond } 17419459580SLuke Drummond 175b9c1b51eSKate Stone bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) { 17619459580SLuke Drummond if (!m_ir_passes) 17719459580SLuke Drummond m_ir_passes = new RSIRPasses(GetProcess()); 17819459580SLuke Drummond assert(m_ir_passes); 17919459580SLuke Drummond 18019459580SLuke Drummond passes.EarlyPasses = m_ir_passes->EarlyPasses; 18119459580SLuke Drummond passes.LatePasses = m_ir_passes->LatePasses; 18219459580SLuke Drummond 18319459580SLuke Drummond return true; 18419459580SLuke Drummond } 18519459580SLuke Drummond 186b9c1b51eSKate Stone namespace lldb_renderscript { 18719459580SLuke Drummond 188b9c1b51eSKate Stone RSIRPasses::RSIRPasses(Process *process) { 18919459580SLuke Drummond IRPasses(); 19019459580SLuke Drummond assert(process); 19119459580SLuke Drummond 19219459580SLuke Drummond EarlyPasses = std::make_shared<llvm::legacy::PassManager>(); 19319459580SLuke Drummond assert(EarlyPasses); 19419459580SLuke Drummond EarlyPasses->add(new RenderScriptRuntimeModulePass(process)); 19519459580SLuke Drummond } 19619459580SLuke Drummond 197b9c1b51eSKate Stone RSIRPasses::~RSIRPasses() {} 19819459580SLuke Drummond 19919459580SLuke Drummond } // namespace lldb_renderscript 20019459580SLuke Drummond } // namespace lldb_private 201