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