1 //===-- RenderScriptExpressionOpts.cpp --------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include <string> 11 12 #include "llvm/ADT/None.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/IR/Instruction.h" 15 #include "llvm/IR/Instructions.h" 16 #include "llvm/IR/LegacyPassManager.h" 17 #include "llvm/IR/Module.h" 18 #include "llvm/Support/TargetRegistry.h" 19 #include "llvm/Target/TargetMachine.h" 20 #include "llvm/Target/TargetOptions.h" 21 22 #include "clang/Basic/TargetOptions.h" 23 24 #include "lldb/Target/Process.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Utility/Log.h" 27 28 #include "RenderScriptExpressionOpts.h" 29 #include "RenderScriptRuntime.h" 30 #include "RenderScriptx86ABIFixups.h" 31 32 using namespace lldb_private; 33 using namespace lldb_renderscript; 34 35 // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang), 36 // the compiler frontend for RenderScript embeds an ARM specific triple in IR 37 // that is shipped in the app, after generating IR that has some assumptions 38 // that an ARM device is the target. As the IR is then compiled on a device of 39 // unknown (at time the IR was generated at least) architecture, when calling 40 // RenderScript API function as part of debugger expressions, we have to 41 // perform a fixup pass that removes those assumptions right before the module 42 // is sent to be generated by the llvm backend. 43 44 namespace { 45 bool registerRSDefaultTargetOpts(clang::TargetOptions &proto, 46 const llvm::Triple::ArchType &arch) { 47 switch (arch) { 48 case llvm::Triple::ArchType::x86: 49 proto.Triple = "i686--linux-android"; 50 proto.CPU = "atom"; 51 proto.Features.push_back("+long64"); 52 // Fallthrough for common x86 family features 53 LLVM_FALLTHROUGH; 54 case llvm::Triple::ArchType::x86_64: 55 proto.Features.push_back("+mmx"); 56 proto.Features.push_back("+sse"); 57 proto.Features.push_back("+sse2"); 58 proto.Features.push_back("+sse3"); 59 proto.Features.push_back("+ssse3"); 60 proto.Features.push_back("+sse4.1"); 61 proto.Features.push_back("+sse4.2"); 62 break; 63 case llvm::Triple::ArchType::mipsel: 64 // pretend this is `arm' for the front-end 65 proto.Triple = "armv7-none-linux-android"; 66 proto.CPU = ""; 67 proto.Features.push_back("+long64"); 68 break; 69 case llvm::Triple::ArchType::mips64el: 70 // pretend this is `aarch64' for the front-end 71 proto.Triple = "aarch64-none-linux-android"; 72 proto.CPU = ""; 73 break; 74 default: 75 return false; 76 } 77 return true; 78 } 79 } // end anonymous namespace 80 81 bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { 82 bool changed_module = false; 83 Log *log( 84 GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); 85 86 std::string err; 87 llvm::StringRef real_triple = 88 m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple(); 89 const llvm::Target *target_info = 90 llvm::TargetRegistry::lookupTarget(real_triple, err); 91 if (!target_info) { 92 if (log) 93 log->Warning("couldn't determine real target architecture: '%s'", 94 err.c_str()); 95 return false; 96 } 97 98 llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None; 99 assert(m_process_ptr && "no available lldb process"); 100 switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) { 101 case llvm::Triple::ArchType::x86: 102 changed_module |= fixupX86FunctionCalls(module); 103 // For some reason this triple gets totally missed by the backend, and must 104 // be set manually. There a reference in bcc/Main.cpp about auto feature- 105 // detection being removed from LLVM3.5, but I can't see that discussion 106 // anywhere public. 107 real_triple = "i686--linux-android"; 108 break; 109 case llvm::Triple::ArchType::x86_64: 110 changed_module |= fixupX86_64FunctionCalls(module); 111 break; 112 case llvm::Triple::ArchType::mipsel: 113 case llvm::Triple::ArchType::mips64el: 114 // No actual IR fixup pass is needed on MIPS, but the datalayout and 115 // targetmachine do need to be explicitly set. 116 117 // bcc explicitly compiles MIPS code to use the static relocation model due 118 // to an issue with relocations in mclinker. see 119 // libbcc/support/CompilerConfig.cpp for details 120 reloc_model = llvm::Reloc::Static; 121 changed_module = true; 122 break; 123 case llvm::Triple::ArchType::arm: 124 case llvm::Triple::ArchType::aarch64: 125 // ARM subtargets need no fixup passes as they are the initial target as 126 // generated by the 127 // slang compiler frontend. 128 break; 129 default: 130 if (log) 131 log->Warning("Ignoring unknown renderscript target"); 132 return false; 133 } 134 135 if (changed_module) { 136 llvm::TargetOptions options; 137 llvm::TargetMachine *target_machine = target_info->createTargetMachine( 138 real_triple, "", "", options, reloc_model); 139 assert(target_machine && 140 "failed to identify RenderScriptRuntime target machine"); 141 // We've been using a triple and datalayout of some ARM variant all along, 142 // so we need to let the backend know that this is no longer the case. 143 if (log) { 144 log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__, 145 real_triple.str().c_str()); 146 log->Printf( 147 "%s - Changing RS datalayout to '%s'", __FUNCTION__, 148 target_machine->createDataLayout().getStringRepresentation().c_str()); 149 } 150 module.setTargetTriple(real_triple); 151 module.setDataLayout(target_machine->createDataLayout()); 152 } 153 return changed_module; 154 } 155 156 char RenderScriptRuntimeModulePass::ID = 0; 157 158 namespace lldb_private { 159 160 bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) { 161 auto *process = GetProcess(); 162 assert(process); 163 return registerRSDefaultTargetOpts( 164 proto, process->GetTarget().GetArchitecture().GetMachine()); 165 } 166 167 bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) { 168 if (!m_ir_passes) 169 m_ir_passes = new RSIRPasses(GetProcess()); 170 assert(m_ir_passes); 171 172 passes.EarlyPasses = m_ir_passes->EarlyPasses; 173 passes.LatePasses = m_ir_passes->LatePasses; 174 175 return true; 176 } 177 178 namespace lldb_renderscript { 179 180 RSIRPasses::RSIRPasses(Process *process) { 181 IRPasses(); 182 assert(process); 183 184 EarlyPasses = std::make_shared<llvm::legacy::PassManager>(); 185 assert(EarlyPasses); 186 EarlyPasses->add(new RenderScriptRuntimeModulePass(process)); 187 } 188 189 RSIRPasses::~RSIRPasses() {} 190 191 } // namespace lldb_renderscript 192 } // namespace lldb_private 193