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