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