Small jit fixes (#2570)

* Better thunks stripping from jit module.
    * Fixes to jit disassembler
    * Strip comdats from jit module
This commit is contained in:
Ivan Butygin 2018-02-14 17:57:37 +03:00 committed by GitHub
parent 16ecb3e79f
commit bfd412cdf9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 145 additions and 49 deletions

View file

@ -193,47 +193,39 @@ void fixRtModule(llvm::Module &newModule,
// Replace call to thunks in jitted code with direct calls to functions
for (auto &&fun : newModule.functions()) {
iterateFuncInstructions(fun, [&](llvm::Instruction &instr) -> bool {
if (auto call = llvm::dyn_cast<llvm::CallInst>(&instr)) {
auto callee = call->getCalledValue();
assert(nullptr != callee);
for (auto &op : instr.operands()) {
auto val = op.get();
if (auto callee = llvm::dyn_cast<llvm::Function>(val)) {
auto it = thunkFun2func.find(callee->getName());
if (thunkFun2func.end() != it) {
auto realFunc = newModule.getFunction(it->second);
assert(nullptr != realFunc);
call->setCalledFunction(realFunc);
op.set(realFunc);
}
}
}
return false;
});
}
int objectsFixed = 0;
for (auto &&obj : newModule.globals()) {
auto it = thunkVar2func.find(obj.getName());
if (thunkVar2func.end() != it) {
if (obj.hasInitializer()) {
auto func = newModule.getFunction(it->second);
assert(nullptr != func);
obj.setConstant(true);
obj.setInitializer(func);
// Thunks should be unused now, strip them
for (auto &&it : funcs) {
assert(nullptr != it.first);
assert(nullptr != it.second.thunkFunc);
auto func = newModule.getFunction(it.second.thunkFunc->getName());
assert(func != nullptr);
if (func->use_empty()) {
func->eraseFromParent();
}
++objectsFixed;
if (nullptr != it.second.thunkVar) {
auto var = newModule.getGlobalVariable(it.second.thunkVar->getName());
assert(var != nullptr);
if (var->use_empty()) {
var->eraseFromParent();
}
}
for (auto &&obj : newModule.functions()) {
if (contains(externalFuncs, obj.getName())) {
obj.setLinkage(llvm::GlobalValue::ExternalLinkage);
obj.setVisibility(llvm::GlobalValue::DefaultVisibility);
++objectsFixed;
} else {
if (llvm::GlobalValue::ExternalLinkage == obj.getLinkage() &&
!obj.isDeclaration()) {
obj.setLinkage(llvm::GlobalValue::InternalLinkage);
};
}
}
assert((thunkVar2func.size() + externalFuncs.size()) ==
static_cast<std::size_t>(objectsFixed));
}
void removeFunctionsTargets(IRState *irs, llvm::Module &module) {
@ -615,15 +607,6 @@ llvm::PointerType *getModListHeadType(llvm::LLVMContext &context,
llvm::GlobalVariable *declareModListHead(llvm::Module &module,
const Types &types) {
auto type = getModListHeadType(module.getContext(), types);
// auto existingVar =
// module.getGlobalVariable(DynamicCompileModulesHeadName); if (nullptr !=
// existingVar) {
// if (type != existingVar->getType()) {
// error(Loc(), "Invalid DynamicCompileModulesHeadName type");
// fatal();
// }
// return existingVar;
// }
return new llvm::GlobalVariable(module, type, false,
llvm::GlobalValue::ExternalLinkage, nullptr,
DynamicCompileModulesHeadName);

View file

@ -9,6 +9,7 @@
#include "disassembler.h"
#include <algorithm>
#include <unordered_map>
#include <llvm/ADT/Triple.h>
@ -201,16 +202,20 @@ public:
};
void processRelocations(SymTable &symTable,
uint64_t offset,
const llvm::object::ObjectFile &object,
const llvm::object::SectionRef &sec) {
for (const auto &reloc : sec.relocations()) {
const auto symIt = reloc.getSymbol();
if (object.symbol_end() != symIt) {
const auto sym = *symIt;
symTable.addExternalSymbolRel(reloc.getOffset(),
auto relOffet = reloc.getOffset();
if (relOffet >= offset) {
symTable.addExternalSymbolRel(relOffet - offset,
llvm::cantFail(sym.getName()));
}
}
}
}
}
@ -286,6 +291,21 @@ void disassemble(const llvm::TargetMachine &tm,
asmStreamer->InitSections(false);
std::unordered_map<uint64_t, std::vector<uint64_t>> sectionsToProcess;
for (const auto &symbol : object.symbols()) {
const auto secIt = llvm::cantFail(symbol.getSection());
if (object.section_end() != secIt) {
auto offset = symbol.getValue();
sectionsToProcess[secIt->getIndex()].push_back(offset);
}
}
for (auto &sec : sectionsToProcess) {
auto &vec = sec.second;
std::sort(vec.begin(), vec.end());
auto end = std::unique(vec.begin(), vec.end());
vec.erase(end, vec.end());
}
for (const auto &symbol : object.symbols()) {
const auto name = llvm::cantFail(symbol.getName());
const auto secIt = llvm::cantFail(symbol.getSection());
@ -293,20 +313,32 @@ void disassemble(const llvm::TargetMachine &tm,
const auto sec = *secIt;
llvm::StringRef data;
sec.getContents(data);
llvm::ArrayRef<uint8_t> buff(
reinterpret_cast<const uint8_t *>(data.data()), data.size());
if (llvm::object::SymbolRef::ST_Function ==
llvm::cantFail(symbol.getType())) {
symTable.reset();
symTable.addLabel(0, 0, name); // Function start
processRelocations(symTable, object, sec);
auto offset = symbol.getValue();
processRelocations(symTable, offset, object, sec);
// TODO: something more optimal
for (const auto &globalSec : object.sections()) {
if (globalSec.getRelocatedSection() == secIt) {
processRelocations(symTable, object, globalSec);
processRelocations(symTable, offset, object, globalSec);
}
}
auto size = data.size() - offset;
auto &ranges = sectionsToProcess[sec.getIndex()];
if (!ranges.empty()) {
for (std::size_t i = 0; i < ranges.size() - 1; ++i) {
if (ranges[i] == offset) {
size = std::min(size, ranges[i + 1] - offset);
}
}
}
llvm::ArrayRef<uint8_t> buff(
reinterpret_cast<const uint8_t *>(data.data() + offset),
size);
printFunction(*disasm, *mcia, buff, symTable, *sti, *asmStreamer);
asmStreamer->EmitRawText("");

View file

@ -109,10 +109,23 @@ struct FuncFinalizer final {
~FuncFinalizer() { fpm.doFinalization(); }
};
void stripComdat(llvm::Module &module) {
for (auto &&func : module.functions()) {
func.setComdat(nullptr);
}
for (auto &&var : module.globals()) {
var.setComdat(nullptr);
}
module.getComdatSymbolTable().clear();
}
} // anon namespace
void optimizeModule(const Context &context, llvm::TargetMachine &targetMachine,
const OptimizerSettings &settings, llvm::Module &module) {
// There is llvm bug related tp comdat and IR based pgo
// and anyway comdat is useless at this stage
stripComdat(module);
llvm::legacy::PassManager mpm;
llvm::legacy::FunctionPassManager fpm(&module);
const auto name = module.getName();

View file

@ -14,6 +14,16 @@ __gshared int value = 32;
return value;
}
@dynamicCompile int bar()
{
return 7;
}
@dynamicCompile int baz()
{
return 8;
}
void main(string[] args)
{
auto dump = appender!string();
@ -28,6 +38,10 @@ void main(string[] args)
compileDynamicCode(settings);
// Check function and variables names in asm
assert(-1 != indexOf(dump.data, foo.mangleof));
assert(-1 != indexOf(dump.data, value.mangleof));
assert(1 == count(dump.data, foo.mangleof));
assert(1 == count(dump.data, bar.mangleof));
assert(1 == count(dump.data, baz.mangleof));
assert(1 == count(dump.data, value.mangleof));
assert(1 == count(dump.data, "7"));
assert(1 == count(dump.data, "8"));
}

View file

@ -0,0 +1,54 @@
// REQUIRES: atleast_llvm500
// RUN: %ldc -enable-dynamic-compile -run %s
import std.array;
import std.string;
import ldc.attributes;
import ldc.dynamic_compile;
__gshared int value = 32;
@dynamicCompile int foo()
{
return 42;
}
@dynamicCompile int bar()
{
return foo();
}
void fun(int function())
{
}
@dynamicCompile void baz()
{
fun(&foo);
}
class Foo()
{
@dynamicCompile int foo()
{
return 43;
}
}
void main(string[] args)
{
auto dump = appender!string();
CompilerSettings settings;
settings.dumpHandler = (DumpStage stage, in char[] str)
{
if (DumpStage.OriginalModule == stage)
{
dump.put(str);
}
};
compileDynamicCode(settings);
assert(0 == count(dump.data, "thunk"));
}