1435933ddSDimitry Andric //===-- RenderScriptExpressionOpts.cpp --------------------------*- C++ -*-===//
2435933ddSDimitry Andric //
3435933ddSDimitry Andric // The LLVM Compiler Infrastructure
4435933ddSDimitry Andric //
5435933ddSDimitry Andric // This file is distributed under the University of Illinois Open Source
6435933ddSDimitry Andric // License. See LICENSE.TXT for details.
7435933ddSDimitry Andric //
8435933ddSDimitry Andric //===----------------------------------------------------------------------===//
9435933ddSDimitry Andric
10435933ddSDimitry Andric #include <string>
11435933ddSDimitry Andric
12435933ddSDimitry Andric #include "llvm/ADT/None.h"
13435933ddSDimitry Andric #include "llvm/ADT/StringRef.h"
14435933ddSDimitry Andric #include "llvm/IR/Instruction.h"
15435933ddSDimitry Andric #include "llvm/IR/Instructions.h"
16435933ddSDimitry Andric #include "llvm/IR/LegacyPassManager.h"
17435933ddSDimitry Andric #include "llvm/IR/Module.h"
18435933ddSDimitry Andric #include "llvm/Support/TargetRegistry.h"
19435933ddSDimitry Andric #include "llvm/Target/TargetMachine.h"
20435933ddSDimitry Andric #include "llvm/Target/TargetOptions.h"
21435933ddSDimitry Andric
22435933ddSDimitry Andric #include "clang/Basic/TargetOptions.h"
23435933ddSDimitry Andric
24435933ddSDimitry Andric #include "lldb/Target/Process.h"
25435933ddSDimitry Andric #include "lldb/Target/Target.h"
26f678e45dSDimitry Andric #include "lldb/Utility/Log.h"
27435933ddSDimitry Andric
28435933ddSDimitry Andric #include "RenderScriptExpressionOpts.h"
29435933ddSDimitry Andric #include "RenderScriptRuntime.h"
30435933ddSDimitry Andric #include "RenderScriptx86ABIFixups.h"
31435933ddSDimitry Andric
32435933ddSDimitry Andric using namespace lldb_private;
33435933ddSDimitry Andric using namespace lldb_renderscript;
34435933ddSDimitry Andric
35435933ddSDimitry Andric // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang),
36435933ddSDimitry Andric // the compiler frontend for RenderScript embeds an ARM specific triple in IR
37*4ba319b5SDimitry Andric // that is shipped in the app, after generating IR that has some assumptions
38*4ba319b5SDimitry Andric // that an ARM device is the target. As the IR is then compiled on a device of
39*4ba319b5SDimitry Andric // unknown (at time the IR was generated at least) architecture, when calling
40*4ba319b5SDimitry Andric // RenderScript API function as part of debugger expressions, we have to
41*4ba319b5SDimitry Andric // perform a fixup pass that removes those assumptions right before the module
42*4ba319b5SDimitry Andric // is sent to be generated by the llvm backend.
43435933ddSDimitry Andric
44435933ddSDimitry Andric namespace {
registerRSDefaultTargetOpts(clang::TargetOptions & proto,const llvm::Triple::ArchType & arch)45435933ddSDimitry Andric bool registerRSDefaultTargetOpts(clang::TargetOptions &proto,
46435933ddSDimitry Andric const llvm::Triple::ArchType &arch) {
47435933ddSDimitry Andric switch (arch) {
48435933ddSDimitry Andric case llvm::Triple::ArchType::x86:
49435933ddSDimitry Andric proto.Triple = "i686--linux-android";
50435933ddSDimitry Andric proto.CPU = "atom";
51435933ddSDimitry Andric proto.Features.push_back("+long64");
52435933ddSDimitry Andric // Fallthrough for common x86 family features
53435933ddSDimitry Andric LLVM_FALLTHROUGH;
54435933ddSDimitry Andric case llvm::Triple::ArchType::x86_64:
55435933ddSDimitry Andric proto.Features.push_back("+mmx");
56435933ddSDimitry Andric proto.Features.push_back("+sse");
57435933ddSDimitry Andric proto.Features.push_back("+sse2");
58435933ddSDimitry Andric proto.Features.push_back("+sse3");
59435933ddSDimitry Andric proto.Features.push_back("+ssse3");
60435933ddSDimitry Andric proto.Features.push_back("+sse4.1");
61435933ddSDimitry Andric proto.Features.push_back("+sse4.2");
62435933ddSDimitry Andric break;
63435933ddSDimitry Andric case llvm::Triple::ArchType::mipsel:
64435933ddSDimitry Andric // pretend this is `arm' for the front-end
65435933ddSDimitry Andric proto.Triple = "armv7-none-linux-android";
66435933ddSDimitry Andric proto.CPU = "";
67435933ddSDimitry Andric proto.Features.push_back("+long64");
68435933ddSDimitry Andric break;
69435933ddSDimitry Andric case llvm::Triple::ArchType::mips64el:
70435933ddSDimitry Andric // pretend this is `aarch64' for the front-end
71435933ddSDimitry Andric proto.Triple = "aarch64-none-linux-android";
72435933ddSDimitry Andric proto.CPU = "";
73435933ddSDimitry Andric break;
74435933ddSDimitry Andric default:
75435933ddSDimitry Andric return false;
76435933ddSDimitry Andric }
77435933ddSDimitry Andric return true;
78435933ddSDimitry Andric }
79435933ddSDimitry Andric } // end anonymous namespace
80435933ddSDimitry Andric
runOnModule(llvm::Module & module)81435933ddSDimitry Andric bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) {
82435933ddSDimitry Andric bool changed_module = false;
83435933ddSDimitry Andric Log *log(
84435933ddSDimitry Andric GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS));
85435933ddSDimitry Andric
86435933ddSDimitry Andric std::string err;
87435933ddSDimitry Andric llvm::StringRef real_triple =
88435933ddSDimitry Andric m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple();
89435933ddSDimitry Andric const llvm::Target *target_info =
90435933ddSDimitry Andric llvm::TargetRegistry::lookupTarget(real_triple, err);
91435933ddSDimitry Andric if (!target_info) {
92435933ddSDimitry Andric if (log)
93435933ddSDimitry Andric log->Warning("couldn't determine real target architecture: '%s'",
94435933ddSDimitry Andric err.c_str());
95435933ddSDimitry Andric return false;
96435933ddSDimitry Andric }
97435933ddSDimitry Andric
98435933ddSDimitry Andric llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None;
99435933ddSDimitry Andric assert(m_process_ptr && "no available lldb process");
100435933ddSDimitry Andric switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) {
101435933ddSDimitry Andric case llvm::Triple::ArchType::x86:
102435933ddSDimitry Andric changed_module |= fixupX86FunctionCalls(module);
103435933ddSDimitry Andric // For some reason this triple gets totally missed by the backend, and must
104*4ba319b5SDimitry Andric // be set manually. There a reference in bcc/Main.cpp about auto feature-
105*4ba319b5SDimitry Andric // detection being removed from LLVM3.5, but I can't see that discussion
106*4ba319b5SDimitry Andric // anywhere public.
107435933ddSDimitry Andric real_triple = "i686--linux-android";
108435933ddSDimitry Andric break;
109435933ddSDimitry Andric case llvm::Triple::ArchType::x86_64:
110435933ddSDimitry Andric changed_module |= fixupX86_64FunctionCalls(module);
111435933ddSDimitry Andric break;
112435933ddSDimitry Andric case llvm::Triple::ArchType::mipsel:
113435933ddSDimitry Andric case llvm::Triple::ArchType::mips64el:
114*4ba319b5SDimitry Andric // No actual IR fixup pass is needed on MIPS, but the datalayout and
115*4ba319b5SDimitry Andric // targetmachine do need to be explicitly set.
116435933ddSDimitry Andric
117*4ba319b5SDimitry Andric // bcc explicitly compiles MIPS code to use the static relocation model due
118*4ba319b5SDimitry Andric // to an issue with relocations in mclinker. see
119*4ba319b5SDimitry Andric // libbcc/support/CompilerConfig.cpp for details
120435933ddSDimitry Andric reloc_model = llvm::Reloc::Static;
121435933ddSDimitry Andric changed_module = true;
122435933ddSDimitry Andric break;
123435933ddSDimitry Andric case llvm::Triple::ArchType::arm:
124435933ddSDimitry Andric case llvm::Triple::ArchType::aarch64:
125435933ddSDimitry Andric // ARM subtargets need no fixup passes as they are the initial target as
126435933ddSDimitry Andric // generated by the
127435933ddSDimitry Andric // slang compiler frontend.
128435933ddSDimitry Andric break;
129435933ddSDimitry Andric default:
130435933ddSDimitry Andric if (log)
131435933ddSDimitry Andric log->Warning("Ignoring unknown renderscript target");
132435933ddSDimitry Andric return false;
133435933ddSDimitry Andric }
134435933ddSDimitry Andric
135435933ddSDimitry Andric if (changed_module) {
136435933ddSDimitry Andric llvm::TargetOptions options;
137435933ddSDimitry Andric llvm::TargetMachine *target_machine = target_info->createTargetMachine(
138435933ddSDimitry Andric real_triple, "", "", options, reloc_model);
139435933ddSDimitry Andric assert(target_machine &&
140435933ddSDimitry Andric "failed to identify RenderScriptRuntime target machine");
141435933ddSDimitry Andric // We've been using a triple and datalayout of some ARM variant all along,
142*4ba319b5SDimitry Andric // so we need to let the backend know that this is no longer the case.
143435933ddSDimitry Andric if (log) {
144435933ddSDimitry Andric log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__,
145435933ddSDimitry Andric real_triple.str().c_str());
146435933ddSDimitry Andric log->Printf(
147435933ddSDimitry Andric "%s - Changing RS datalayout to '%s'", __FUNCTION__,
148435933ddSDimitry Andric target_machine->createDataLayout().getStringRepresentation().c_str());
149435933ddSDimitry Andric }
150435933ddSDimitry Andric module.setTargetTriple(real_triple);
151435933ddSDimitry Andric module.setDataLayout(target_machine->createDataLayout());
152435933ddSDimitry Andric }
153435933ddSDimitry Andric return changed_module;
154435933ddSDimitry Andric }
155435933ddSDimitry Andric
156435933ddSDimitry Andric char RenderScriptRuntimeModulePass::ID = 0;
157435933ddSDimitry Andric
158435933ddSDimitry Andric namespace lldb_private {
159435933ddSDimitry Andric
GetOverrideExprOptions(clang::TargetOptions & proto)160435933ddSDimitry Andric bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) {
161435933ddSDimitry Andric auto *process = GetProcess();
162435933ddSDimitry Andric assert(process);
163435933ddSDimitry Andric return registerRSDefaultTargetOpts(
164435933ddSDimitry Andric proto, process->GetTarget().GetArchitecture().GetMachine());
165435933ddSDimitry Andric }
166435933ddSDimitry Andric
GetIRPasses(LLVMUserExpression::IRPasses & passes)167435933ddSDimitry Andric bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) {
168435933ddSDimitry Andric if (!m_ir_passes)
169435933ddSDimitry Andric m_ir_passes = new RSIRPasses(GetProcess());
170435933ddSDimitry Andric assert(m_ir_passes);
171435933ddSDimitry Andric
172435933ddSDimitry Andric passes.EarlyPasses = m_ir_passes->EarlyPasses;
173435933ddSDimitry Andric passes.LatePasses = m_ir_passes->LatePasses;
174435933ddSDimitry Andric
175435933ddSDimitry Andric return true;
176435933ddSDimitry Andric }
177435933ddSDimitry Andric
178435933ddSDimitry Andric namespace lldb_renderscript {
179435933ddSDimitry Andric
RSIRPasses(Process * process)180435933ddSDimitry Andric RSIRPasses::RSIRPasses(Process *process) {
181435933ddSDimitry Andric IRPasses();
182435933ddSDimitry Andric assert(process);
183435933ddSDimitry Andric
184435933ddSDimitry Andric EarlyPasses = std::make_shared<llvm::legacy::PassManager>();
185435933ddSDimitry Andric assert(EarlyPasses);
186435933ddSDimitry Andric EarlyPasses->add(new RenderScriptRuntimeModulePass(process));
187435933ddSDimitry Andric }
188435933ddSDimitry Andric
~RSIRPasses()189435933ddSDimitry Andric RSIRPasses::~RSIRPasses() {}
190435933ddSDimitry Andric
191435933ddSDimitry Andric } // namespace lldb_renderscript
192435933ddSDimitry Andric } // namespace lldb_private
193