119459580SLuke Drummond //===-- ExpressionOpts.cpp --------------------------------------*- C++ -*-===//
219459580SLuke Drummond //
319459580SLuke Drummond //                     The LLVM Compiler Infrastructure
419459580SLuke Drummond //
519459580SLuke Drummond // This file is distributed under the University of Illinois Open Source
619459580SLuke Drummond // License. See LICENSE.TXT for details.
719459580SLuke Drummond //
819459580SLuke Drummond //===----------------------------------------------------------------------===//
919459580SLuke Drummond 
1019459580SLuke Drummond // C Includes
1119459580SLuke Drummond // C++ Includes
1219459580SLuke Drummond #include <string>
1319459580SLuke Drummond 
1419459580SLuke Drummond // Other libraries and framework includes
1519459580SLuke Drummond #include "llvm/ADT/None.h"
1619459580SLuke Drummond #include "llvm/ADT/StringRef.h"
1719459580SLuke Drummond #include "llvm/IR/Instruction.h"
1819459580SLuke Drummond #include "llvm/IR/Instructions.h"
1919459580SLuke Drummond #include "llvm/IR/LegacyPassManager.h"
2019459580SLuke Drummond #include "llvm/IR/Module.h"
2119459580SLuke Drummond #include "llvm/Support/TargetRegistry.h"
2219459580SLuke Drummond #include "llvm/Target/TargetMachine.h"
2319459580SLuke Drummond #include "llvm/Target/TargetOptions.h"
2419459580SLuke Drummond 
2519459580SLuke Drummond #include "clang/Basic/TargetOptions.h"
2619459580SLuke Drummond 
2719459580SLuke Drummond // Project includes
2819459580SLuke Drummond #include "lldb/Core/Log.h"
2919459580SLuke Drummond #include "lldb/Target/Process.h"
3019459580SLuke Drummond #include "lldb/Target/Target.h"
3119459580SLuke Drummond 
3219459580SLuke Drummond #include "RenderScriptExpressionOpts.h"
3319459580SLuke Drummond #include "RenderScriptRuntime.h"
3419459580SLuke Drummond #include "RenderScriptx86ABIFixups.h"
3519459580SLuke Drummond 
3619459580SLuke Drummond using namespace lldb_private;
3719459580SLuke Drummond using namespace lldb_renderscript;
3819459580SLuke Drummond 
3919459580SLuke Drummond // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang),
40*b9c1b51eSKate Stone // the compiler frontend for RenderScript embeds an ARM specific triple in IR
41*b9c1b51eSKate Stone // that is shipped in the app, after
4219459580SLuke Drummond // generating IR that has some assumptions that an ARM device is the target.
43*b9c1b51eSKate Stone // As the IR is then compiled on a device of unknown (at time the IR was
44*b9c1b51eSKate Stone // generated at least) architecture,
45*b9c1b51eSKate Stone // when calling RenderScript API function as part of debugger expressions, we
46*b9c1b51eSKate Stone // have to perform a fixup pass that
47*b9c1b51eSKate Stone // removes those assumptions right before the module is sent to be generated by
48*b9c1b51eSKate Stone // the llvm backend.
4919459580SLuke Drummond 
50*b9c1b51eSKate Stone namespace {
51*b9c1b51eSKate Stone bool registerRSDefaultTargetOpts(clang::TargetOptions &proto,
52*b9c1b51eSKate Stone                                  const llvm::Triple::ArchType &arch) {
53*b9c1b51eSKate Stone   switch (arch) {
5419459580SLuke Drummond   case llvm::Triple::ArchType::x86:
5519459580SLuke Drummond     proto.Triple = "i686--linux-android";
5619459580SLuke Drummond     proto.CPU = "atom";
5719459580SLuke Drummond     proto.Features.push_back("+long64");
5819459580SLuke Drummond   // Fallthrough for common x86 family features
5919459580SLuke Drummond   case llvm::Triple::ArchType::x86_64:
6019459580SLuke Drummond     proto.Features.push_back("+mmx");
6119459580SLuke Drummond     proto.Features.push_back("+sse");
6219459580SLuke Drummond     proto.Features.push_back("+sse2");
6319459580SLuke Drummond     proto.Features.push_back("+sse3");
6419459580SLuke Drummond     proto.Features.push_back("+ssse3");
6519459580SLuke Drummond     proto.Features.push_back("+sse4.1");
6619459580SLuke Drummond     proto.Features.push_back("+sse4.2");
6719459580SLuke Drummond     break;
6819459580SLuke Drummond   case llvm::Triple::ArchType::mipsel:
6919459580SLuke Drummond     // pretend this is `arm' for the front-end
7019459580SLuke Drummond     proto.Triple = "armv7-none-linux-android";
7119459580SLuke Drummond     proto.CPU = "";
7219459580SLuke Drummond     proto.Features.push_back("+long64");
7319459580SLuke Drummond     break;
7419459580SLuke Drummond   case llvm::Triple::ArchType::mips64el:
7519459580SLuke Drummond     // pretend this is `aarch64' for the front-end
7619459580SLuke Drummond     proto.Triple = "aarch64-none-linux-android";
7719459580SLuke Drummond     proto.CPU = "";
7819459580SLuke Drummond     break;
7919459580SLuke Drummond   default:
8019459580SLuke Drummond     return false;
8119459580SLuke Drummond   }
8219459580SLuke Drummond   return true;
8319459580SLuke Drummond }
8419459580SLuke Drummond } // end anonymous namespace
8519459580SLuke Drummond 
86*b9c1b51eSKate Stone bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) {
8719459580SLuke Drummond   bool changed_module = false;
88*b9c1b51eSKate Stone   Log *log(
89*b9c1b51eSKate Stone       GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS));
9019459580SLuke Drummond 
9119459580SLuke Drummond   std::string err;
92*b9c1b51eSKate Stone   llvm::StringRef real_triple =
93*b9c1b51eSKate Stone       m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple();
94*b9c1b51eSKate Stone   const llvm::Target *target_info =
95*b9c1b51eSKate Stone       llvm::TargetRegistry::lookupTarget(real_triple, err);
96*b9c1b51eSKate Stone   if (!target_info) {
9719459580SLuke Drummond     if (log)
98*b9c1b51eSKate Stone       log->Warning("couldn't determine real target architecture: '%s'",
99*b9c1b51eSKate Stone                    err.c_str());
10019459580SLuke Drummond     return false;
10119459580SLuke Drummond   }
10219459580SLuke Drummond 
10319459580SLuke Drummond   llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None;
10419459580SLuke Drummond   assert(m_process_ptr && "no available lldb process");
105*b9c1b51eSKate Stone   switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) {
10619459580SLuke Drummond   case llvm::Triple::ArchType::x86:
10719459580SLuke Drummond     changed_module |= fixupX86FunctionCalls(module);
108*b9c1b51eSKate Stone     // For some reason this triple gets totally missed by the backend, and must
109*b9c1b51eSKate Stone     // be set manually.
110*b9c1b51eSKate Stone     // There a reference in bcc/Main.cpp about auto feature-detection being
111*b9c1b51eSKate Stone     // removed from LLVM3.5, but I can't
11219459580SLuke Drummond     // see that discussion anywhere public.
11319459580SLuke Drummond     real_triple = "i686--linux-android";
11419459580SLuke Drummond     break;
11519459580SLuke Drummond   case llvm::Triple::ArchType::x86_64:
11619459580SLuke Drummond     changed_module |= fixupX86_64FunctionCalls(module);
11719459580SLuke Drummond     break;
11819459580SLuke Drummond   case llvm::Triple::ArchType::mipsel:
11919459580SLuke Drummond   case llvm::Triple::ArchType::mips64el:
12019459580SLuke Drummond     // No actual IR fixup pass is needed on MIPS, but the datalayout
12119459580SLuke Drummond     // and targetmachine do need to be explicitly set.
12219459580SLuke Drummond 
12319459580SLuke Drummond     // bcc explicitly compiles MIPS code to use the static relocation
12419459580SLuke Drummond     // model due to an issue with relocations in mclinker.
12519459580SLuke Drummond     // see libbcc/support/CompilerConfig.cpp for details
12619459580SLuke Drummond     reloc_model = llvm::Reloc::Static;
12719459580SLuke Drummond     changed_module = true;
12819459580SLuke Drummond     break;
12919459580SLuke Drummond   case llvm::Triple::ArchType::arm:
13019459580SLuke Drummond   case llvm::Triple::ArchType::aarch64:
131*b9c1b51eSKate Stone     // ARM subtargets need no fixup passes as they are the initial target as
132*b9c1b51eSKate Stone     // generated by the
13319459580SLuke Drummond     // slang compiler frontend.
13419459580SLuke Drummond     break;
13519459580SLuke Drummond   default:
13619459580SLuke Drummond     if (log)
13719459580SLuke Drummond       log->Warning("Ignoring unknown renderscript target");
13819459580SLuke Drummond     return false;
13919459580SLuke Drummond   }
14019459580SLuke Drummond 
141*b9c1b51eSKate Stone   if (changed_module) {
14219459580SLuke Drummond     llvm::TargetOptions options;
143*b9c1b51eSKate Stone     llvm::TargetMachine *target_machine = target_info->createTargetMachine(
144*b9c1b51eSKate Stone         real_triple, "", "", options, reloc_model);
145*b9c1b51eSKate Stone     assert(target_machine &&
146*b9c1b51eSKate Stone            "failed to identify RenderScriptRuntime target machine");
147*b9c1b51eSKate Stone     // We've been using a triple and datalayout of some ARM variant all along,
148*b9c1b51eSKate Stone     // so
14919459580SLuke Drummond     // we need to let the backend know that this is no longer the case.
150*b9c1b51eSKate Stone     if (log) {
151*b9c1b51eSKate Stone       log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__,
152*b9c1b51eSKate Stone                   real_triple.str().c_str());
153*b9c1b51eSKate Stone       log->Printf(
154*b9c1b51eSKate Stone           "%s - Changing RS datalayout to '%s'", __FUNCTION__,
15519459580SLuke Drummond           target_machine->createDataLayout().getStringRepresentation().c_str());
15619459580SLuke Drummond     }
15719459580SLuke Drummond     module.setTargetTriple(real_triple);
15819459580SLuke Drummond     module.setDataLayout(target_machine->createDataLayout());
15919459580SLuke Drummond   }
16019459580SLuke Drummond   return changed_module;
16119459580SLuke Drummond }
16219459580SLuke Drummond 
16319459580SLuke Drummond char RenderScriptRuntimeModulePass::ID = 0;
16419459580SLuke Drummond 
165*b9c1b51eSKate Stone namespace lldb_private {
16619459580SLuke Drummond 
167*b9c1b51eSKate Stone bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) {
16819459580SLuke Drummond   auto *process = GetProcess();
16919459580SLuke Drummond   assert(process);
170*b9c1b51eSKate Stone   return registerRSDefaultTargetOpts(
171*b9c1b51eSKate Stone       proto, process->GetTarget().GetArchitecture().GetMachine());
17219459580SLuke Drummond }
17319459580SLuke Drummond 
174*b9c1b51eSKate Stone bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) {
17519459580SLuke Drummond   if (!m_ir_passes)
17619459580SLuke Drummond     m_ir_passes = new RSIRPasses(GetProcess());
17719459580SLuke Drummond   assert(m_ir_passes);
17819459580SLuke Drummond 
17919459580SLuke Drummond   passes.EarlyPasses = m_ir_passes->EarlyPasses;
18019459580SLuke Drummond   passes.LatePasses = m_ir_passes->LatePasses;
18119459580SLuke Drummond 
18219459580SLuke Drummond   return true;
18319459580SLuke Drummond }
18419459580SLuke Drummond 
185*b9c1b51eSKate Stone namespace lldb_renderscript {
18619459580SLuke Drummond 
187*b9c1b51eSKate Stone RSIRPasses::RSIRPasses(Process *process) {
18819459580SLuke Drummond   IRPasses();
18919459580SLuke Drummond   assert(process);
19019459580SLuke Drummond 
19119459580SLuke Drummond   EarlyPasses = std::make_shared<llvm::legacy::PassManager>();
19219459580SLuke Drummond   assert(EarlyPasses);
19319459580SLuke Drummond   EarlyPasses->add(new RenderScriptRuntimeModulePass(process));
19419459580SLuke Drummond }
19519459580SLuke Drummond 
196*b9c1b51eSKate Stone RSIRPasses::~RSIRPasses() {}
19719459580SLuke Drummond 
19819459580SLuke Drummond } // namespace lldb_renderscript
19919459580SLuke Drummond } // namespace lldb_private
200