Files
llvm-project/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp
T

202 lines
7.0 KiB
C++
Raw Normal View History

//===-- ExpressionOpts.cpp --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
#include <string>
// Other libraries and framework includes
#include "llvm/ADT/None.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "clang/Basic/TargetOptions.h"
// Project includes
#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "RenderScriptExpressionOpts.h"
#include "RenderScriptRuntime.h"
#include "RenderScriptx86ABIFixups.h"
using namespace lldb_private;
using namespace lldb_renderscript;
// [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang),
// the compiler frontend for RenderScript embeds an ARM specific triple in IR that is shipped in the app, after
// generating IR that has some assumptions that an ARM device is the target.
// As the IR is then compiled on a device of unknown (at time the IR was generated at least) architecture,
// when calling RenderScript API function as part of debugger expressions, we have to perform a fixup pass that
// removes those assumptions right before the module is sent to be generated by the llvm backend.
namespace
{
bool
registerRSDefaultTargetOpts(clang::TargetOptions &proto, const llvm::Triple::ArchType &arch)
{
switch (arch)
{
case llvm::Triple::ArchType::x86:
proto.Triple = "i686--linux-android";
proto.CPU = "atom";
proto.Features.push_back("+long64");
// Fallthrough for common x86 family features
case llvm::Triple::ArchType::x86_64:
proto.Features.push_back("+mmx");
proto.Features.push_back("+sse");
proto.Features.push_back("+sse2");
proto.Features.push_back("+sse3");
proto.Features.push_back("+ssse3");
proto.Features.push_back("+sse4.1");
proto.Features.push_back("+sse4.2");
break;
case llvm::Triple::ArchType::mipsel:
// pretend this is `arm' for the front-end
proto.Triple = "armv7-none-linux-android";
proto.CPU = "";
proto.Features.push_back("+long64");
break;
case llvm::Triple::ArchType::mips64el:
// pretend this is `aarch64' for the front-end
proto.Triple = "aarch64-none-linux-android";
proto.CPU = "";
break;
default:
return false;
}
return true;
}
} // end anonymous namespace
bool
RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module)
{
bool changed_module = false;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS));
std::string err;
llvm::StringRef real_triple = m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple();
const llvm::Target *target_info = llvm::TargetRegistry::lookupTarget(real_triple, err);
if (!target_info)
{
if (log)
log->Warning("couldn't determine real target architecture: '%s'", err.c_str());
return false;
}
llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None;
assert(m_process_ptr && "no available lldb process");
switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine())
{
case llvm::Triple::ArchType::x86:
changed_module |= fixupX86FunctionCalls(module);
// For some reason this triple gets totally missed by the backend, and must be set manually.
// There a reference in bcc/Main.cpp about auto feature-detection being removed from LLVM3.5, but I can't
// see that discussion anywhere public.
real_triple = "i686--linux-android";
break;
case llvm::Triple::ArchType::x86_64:
changed_module |= fixupX86_64FunctionCalls(module);
break;
case llvm::Triple::ArchType::mipsel:
case llvm::Triple::ArchType::mips64el:
// No actual IR fixup pass is needed on MIPS, but the datalayout
// and targetmachine do need to be explicitly set.
// bcc explicitly compiles MIPS code to use the static relocation
// model due to an issue with relocations in mclinker.
// see libbcc/support/CompilerConfig.cpp for details
reloc_model = llvm::Reloc::Static;
changed_module = true;
break;
case llvm::Triple::ArchType::arm:
case llvm::Triple::ArchType::aarch64:
// ARM subtargets need no fixup passes as they are the initial target as generated by the
// slang compiler frontend.
break;
default:
if (log)
log->Warning("Ignoring unknown renderscript target");
return false;
}
if (changed_module)
{
llvm::TargetOptions options;
llvm::TargetMachine *target_machine =
target_info->createTargetMachine(real_triple, "", "", options, reloc_model);
assert(target_machine && "failed to identify RenderScriptRuntime target machine");
// We've been using a triple and datalayout of some ARM variant all along, so
// we need to let the backend know that this is no longer the case.
if (log)
{
log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__, real_triple.str().c_str());
log->Printf("%s - Changing RS datalayout to '%s'", __FUNCTION__,
target_machine->createDataLayout().getStringRepresentation().c_str());
}
module.setTargetTriple(real_triple);
module.setDataLayout(target_machine->createDataLayout());
}
return changed_module;
}
char RenderScriptRuntimeModulePass::ID = 0;
namespace lldb_private
{
bool
RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto)
{
auto *process = GetProcess();
assert(process);
return registerRSDefaultTargetOpts(proto, process->GetTarget().GetArchitecture().GetMachine());
}
bool
RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes)
{
if (!m_ir_passes)
m_ir_passes = new RSIRPasses(GetProcess());
assert(m_ir_passes);
passes.EarlyPasses = m_ir_passes->EarlyPasses;
passes.LatePasses = m_ir_passes->LatePasses;
return true;
}
namespace lldb_renderscript
{
RSIRPasses::RSIRPasses(Process *process)
{
IRPasses();
assert(process);
EarlyPasses = std::make_shared<llvm::legacy::PassManager>();
assert(EarlyPasses);
EarlyPasses->add(new RenderScriptRuntimeModulePass(process));
}
RSIRPasses::~RSIRPasses()
{
}
} // namespace lldb_renderscript
} // namespace lldb_private