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