1dda28197Spatrick //===-- RenderScriptExpressionOpts.cpp ------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include <string>
10061da546Spatrick
11061da546Spatrick #include "llvm/ADT/StringRef.h"
12061da546Spatrick #include "llvm/IR/Instruction.h"
13061da546Spatrick #include "llvm/IR/Instructions.h"
14061da546Spatrick #include "llvm/IR/LegacyPassManager.h"
15061da546Spatrick #include "llvm/IR/Module.h"
16*f6aab3d8Srobert #include "llvm/MC/TargetRegistry.h"
17061da546Spatrick #include "llvm/Target/TargetMachine.h"
18061da546Spatrick #include "llvm/Target/TargetOptions.h"
19061da546Spatrick
20061da546Spatrick #include "clang/Basic/TargetOptions.h"
21061da546Spatrick
22061da546Spatrick #include "lldb/Target/Process.h"
23061da546Spatrick #include "lldb/Target/Target.h"
24*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
25061da546Spatrick #include "lldb/Utility/Log.h"
26061da546Spatrick
27061da546Spatrick #include "RenderScriptExpressionOpts.h"
28061da546Spatrick #include "RenderScriptRuntime.h"
29061da546Spatrick #include "RenderScriptx86ABIFixups.h"
30061da546Spatrick
31061da546Spatrick using namespace lldb_private;
32061da546Spatrick using namespace lldb_renderscript;
33061da546Spatrick
34061da546Spatrick // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang),
35061da546Spatrick // the compiler frontend for RenderScript embeds an ARM specific triple in IR
36061da546Spatrick // that is shipped in the app, after generating IR that has some assumptions
37061da546Spatrick // that an ARM device is the target. As the IR is then compiled on a device of
38061da546Spatrick // unknown (at time the IR was generated at least) architecture, when calling
39061da546Spatrick // RenderScript API function as part of debugger expressions, we have to
40061da546Spatrick // perform a fixup pass that removes those assumptions right before the module
41061da546Spatrick // is sent to be generated by the llvm backend.
42061da546Spatrick
registerRSDefaultTargetOpts(clang::TargetOptions & proto,const llvm::Triple::ArchType & arch)43*f6aab3d8Srobert static bool registerRSDefaultTargetOpts(clang::TargetOptions &proto,
44061da546Spatrick const llvm::Triple::ArchType &arch) {
45061da546Spatrick switch (arch) {
46061da546Spatrick case llvm::Triple::ArchType::x86:
47061da546Spatrick proto.Triple = "i686--linux-android";
48061da546Spatrick proto.CPU = "atom";
49061da546Spatrick proto.Features.push_back("+long64");
50061da546Spatrick // Fallthrough for common x86 family features
51*f6aab3d8Srobert [[fallthrough]];
52061da546Spatrick case llvm::Triple::ArchType::x86_64:
53061da546Spatrick proto.Features.push_back("+mmx");
54061da546Spatrick proto.Features.push_back("+sse");
55061da546Spatrick proto.Features.push_back("+sse2");
56061da546Spatrick proto.Features.push_back("+sse3");
57061da546Spatrick proto.Features.push_back("+ssse3");
58061da546Spatrick proto.Features.push_back("+sse4.1");
59061da546Spatrick proto.Features.push_back("+sse4.2");
60061da546Spatrick break;
61061da546Spatrick case llvm::Triple::ArchType::mipsel:
62061da546Spatrick // pretend this is `arm' for the front-end
63061da546Spatrick proto.Triple = "armv7-none-linux-android";
64061da546Spatrick proto.CPU = "";
65061da546Spatrick proto.Features.push_back("+long64");
66061da546Spatrick break;
67061da546Spatrick case llvm::Triple::ArchType::mips64el:
68061da546Spatrick // pretend this is `aarch64' for the front-end
69061da546Spatrick proto.Triple = "aarch64-none-linux-android";
70061da546Spatrick proto.CPU = "";
71061da546Spatrick break;
72061da546Spatrick default:
73061da546Spatrick return false;
74061da546Spatrick }
75061da546Spatrick return true;
76061da546Spatrick }
77061da546Spatrick
runOnModule(llvm::Module & module)78061da546Spatrick bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) {
79061da546Spatrick bool changed_module = false;
80*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Language | LLDBLog::Expressions);
81061da546Spatrick
82061da546Spatrick std::string err;
83061da546Spatrick llvm::StringRef real_triple =
84061da546Spatrick m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple();
85061da546Spatrick const llvm::Target *target_info =
86dda28197Spatrick llvm::TargetRegistry::lookupTarget(std::string(real_triple), err);
87061da546Spatrick if (!target_info) {
88061da546Spatrick if (log)
89061da546Spatrick log->Warning("couldn't determine real target architecture: '%s'",
90061da546Spatrick err.c_str());
91061da546Spatrick return false;
92061da546Spatrick }
93061da546Spatrick
94*f6aab3d8Srobert std::optional<llvm::Reloc::Model> reloc_model;
95061da546Spatrick assert(m_process_ptr && "no available lldb process");
96061da546Spatrick switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) {
97061da546Spatrick case llvm::Triple::ArchType::x86:
98061da546Spatrick changed_module |= fixupX86FunctionCalls(module);
99061da546Spatrick // For some reason this triple gets totally missed by the backend, and must
100061da546Spatrick // be set manually. There a reference in bcc/Main.cpp about auto feature-
101061da546Spatrick // detection being removed from LLVM3.5, but I can't see that discussion
102061da546Spatrick // anywhere public.
103061da546Spatrick real_triple = "i686--linux-android";
104061da546Spatrick break;
105061da546Spatrick case llvm::Triple::ArchType::x86_64:
106061da546Spatrick changed_module |= fixupX86_64FunctionCalls(module);
107061da546Spatrick break;
108061da546Spatrick case llvm::Triple::ArchType::mipsel:
109061da546Spatrick case llvm::Triple::ArchType::mips64el:
110061da546Spatrick // No actual IR fixup pass is needed on MIPS, but the datalayout and
111061da546Spatrick // targetmachine do need to be explicitly set.
112061da546Spatrick
113061da546Spatrick // bcc explicitly compiles MIPS code to use the static relocation model due
114061da546Spatrick // to an issue with relocations in mclinker. see
115061da546Spatrick // libbcc/support/CompilerConfig.cpp for details
116061da546Spatrick reloc_model = llvm::Reloc::Static;
117061da546Spatrick changed_module = true;
118061da546Spatrick break;
119061da546Spatrick case llvm::Triple::ArchType::arm:
120061da546Spatrick case llvm::Triple::ArchType::aarch64:
121061da546Spatrick // ARM subtargets need no fixup passes as they are the initial target as
122061da546Spatrick // generated by the
123061da546Spatrick // slang compiler frontend.
124061da546Spatrick break;
125061da546Spatrick default:
126061da546Spatrick if (log)
127061da546Spatrick log->Warning("Ignoring unknown renderscript target");
128061da546Spatrick return false;
129061da546Spatrick }
130061da546Spatrick
131061da546Spatrick if (changed_module) {
132061da546Spatrick llvm::TargetOptions options;
133061da546Spatrick llvm::TargetMachine *target_machine = target_info->createTargetMachine(
134061da546Spatrick real_triple, "", "", options, reloc_model);
135061da546Spatrick assert(target_machine &&
136061da546Spatrick "failed to identify RenderScriptRuntime target machine");
137061da546Spatrick // We've been using a triple and datalayout of some ARM variant all along,
138061da546Spatrick // so we need to let the backend know that this is no longer the case.
139061da546Spatrick if (log) {
140061da546Spatrick LLDB_LOGF(log, "%s - Changing RS target triple to '%s'", __FUNCTION__,
141061da546Spatrick real_triple.str().c_str());
142061da546Spatrick LLDB_LOGF(
143061da546Spatrick log, "%s - Changing RS datalayout to '%s'", __FUNCTION__,
144061da546Spatrick target_machine->createDataLayout().getStringRepresentation().c_str());
145061da546Spatrick }
146061da546Spatrick module.setTargetTriple(real_triple);
147061da546Spatrick module.setDataLayout(target_machine->createDataLayout());
148061da546Spatrick }
149061da546Spatrick return changed_module;
150061da546Spatrick }
151061da546Spatrick
152061da546Spatrick char RenderScriptRuntimeModulePass::ID = 0;
153061da546Spatrick
154061da546Spatrick namespace lldb_private {
155061da546Spatrick
GetOverrideExprOptions(clang::TargetOptions & proto)156061da546Spatrick bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) {
157061da546Spatrick auto *process = GetProcess();
158061da546Spatrick assert(process);
159061da546Spatrick return registerRSDefaultTargetOpts(
160061da546Spatrick proto, process->GetTarget().GetArchitecture().GetMachine());
161061da546Spatrick }
162061da546Spatrick
GetIRPasses(LLVMUserExpression::IRPasses & passes)163061da546Spatrick bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) {
164061da546Spatrick if (!m_ir_passes)
165061da546Spatrick m_ir_passes = new RSIRPasses(GetProcess());
166061da546Spatrick assert(m_ir_passes);
167061da546Spatrick
168061da546Spatrick passes.EarlyPasses = m_ir_passes->EarlyPasses;
169061da546Spatrick passes.LatePasses = m_ir_passes->LatePasses;
170061da546Spatrick
171061da546Spatrick return true;
172061da546Spatrick }
173061da546Spatrick
174061da546Spatrick namespace lldb_renderscript {
175061da546Spatrick
RSIRPasses(Process * process)176061da546Spatrick RSIRPasses::RSIRPasses(Process *process) {
177061da546Spatrick assert(process);
178061da546Spatrick
179061da546Spatrick EarlyPasses = std::make_shared<llvm::legacy::PassManager>();
180061da546Spatrick assert(EarlyPasses);
181061da546Spatrick EarlyPasses->add(new RenderScriptRuntimeModulePass(process));
182061da546Spatrick }
183061da546Spatrick
184be691f3bSpatrick RSIRPasses::~RSIRPasses() = default;
185061da546Spatrick
186061da546Spatrick } // namespace lldb_renderscript
187061da546Spatrick } // namespace lldb_private
188