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