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