201 lines
6.6 KiB
C++
201 lines
6.6 KiB
C++
//===-- RenderScriptExpressionOpts.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/Target/Process.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Utility/Log.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
|
|
LLVM_FALLTHROUGH;
|
|
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
|