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