mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-12 22:14:54 +03:00
Small jit fixes (#2570)
* Better thunks stripping from jit module. * Fixes to jit disassembler * Strip comdats from jit module
This commit is contained in:
parent
16ecb3e79f
commit
bfd412cdf9
5 changed files with 145 additions and 49 deletions
|
@ -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);
|
||||
|
|
|
@ -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("");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
54
tests/dynamiccompile/jit_module_stripping.d
Normal file
54
tests/dynamiccompile/jit_module_stripping.d
Normal 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"));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue