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