@dynamicCompileEmit attribute (#2747)

This commit is contained in:
Ivan Butygin 2018-06-26 21:59:02 +03:00 committed by GitHub
parent 00c3e89933
commit cbeb2b45d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 101 additions and 28 deletions

View file

@ -465,6 +465,7 @@ immutable Msgtable[] msgtable =
{ "udaKernel", "_kernel" },
{ "udaDynamicCompile", "_dynamicCompile" },
{ "udaDynamicCompileConst", "_dynamicCompileConst" },
{ "udaDynamicCompileEmit", "_dynamicCompileEmit" },
// IN_LLVM: DCompute specific types and functionss
{ "dcompute" },

View file

@ -87,6 +87,7 @@ public:
static Identifier *udaCompute;
static Identifier *udaDynamicCompile;
static Identifier *udaDynamicCompileConst;
static Identifier *udaDynamicCompileEmit;
#endif
};

View file

@ -192,10 +192,11 @@ void fixRtModule(llvm::Module &newModule,
std::unordered_set<std::string> externalFuncs;
for (auto &&it : funcs) {
assert(nullptr != it.first);
assert(nullptr != it.second.thunkFunc);
if (nullptr == it.second.thunkVar) {
// thunkVar is not available
// e.g. runtimeCompile function from other module, ignore
if (nullptr == it.second.thunkVar ||
nullptr == it.second.thunkFunc) {
// thunkVar or thunkFunc is not available
// e.g. dynamicCompile function from other module or emit-only dynamic
// function, ignore
continue;
}
assert(!contains(thunkVar2func, it.second.thunkVar->getName()));
@ -225,11 +226,12 @@ void fixRtModule(llvm::Module &newModule,
// 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();
if (nullptr != it.second.thunkFunc) {
auto func = newModule.getFunction(it.second.thunkFunc->getName());
assert(func != nullptr);
if (func->use_empty()) {
func->eraseFromParent();
}
}
if (nullptr != it.second.thunkVar) {
@ -525,7 +527,6 @@ generateFuncList(IRState *irs, const Types &types) {
std::vector<llvm::Constant *> elements;
for (auto &&it : irs->dynamicCompiledFunctions) {
assert(nullptr != it.first);
assert(nullptr != it.second.thunkFunc);
if (nullptr == it.second.thunkVar) {
// thunkVar is not available
// e.g. runtimeCompile function from other module, ignore
@ -775,9 +776,13 @@ void declareDynamicCompiledFunction(IRState *irs, IrFunction *func) {
if (!opts::enableDynamicCompile) {
return;
}
auto srcFunc = func->getLLVMFunc();
auto thunkFunc = duplicateFunc(irs->module, srcFunc);
func->rtCompileFunc = thunkFunc;
llvm::Function *thunkFunc = nullptr;
if (func->dynamicCompile) {
thunkFunc = duplicateFunc(irs->module, srcFunc);
func->rtCompileFunc = thunkFunc;
}
assert(!contains(irs->dynamicCompiledFunctions, srcFunc));
irs->dynamicCompiledFunctions.insert(
std::make_pair(srcFunc, IRState::RtCompiledFuncDesc{nullptr, thunkFunc}));
@ -787,21 +792,24 @@ void defineDynamicCompiledFunction(IRState *irs, IrFunction *func) {
assert(nullptr != irs);
assert(nullptr != func);
assert(nullptr != func->getLLVMFunc());
assert(nullptr != func->rtCompileFunc);
if (!opts::enableDynamicCompile) {
return;
}
auto srcFunc = func->getLLVMFunc();
auto it = irs->dynamicCompiledFunctions.find(srcFunc);
assert(irs->dynamicCompiledFunctions.end() != it);
auto thunkVarType = srcFunc->getFunctionType()->getPointerTo();
auto thunkVar = new llvm::GlobalVariable(
irs->module, thunkVarType, false, llvm::GlobalValue::PrivateLinkage,
llvm::ConstantPointerNull::get(thunkVarType),
".rtcompile_thunkvar_" + srcFunc->getName());
auto dstFunc = it->second.thunkFunc;
createThunkFunc(irs->module, srcFunc, dstFunc, thunkVar);
it->second.thunkVar = thunkVar;
if (func->dynamicCompile) {
assert(nullptr != func->rtCompileFunc);
auto srcFunc = func->getLLVMFunc();
auto it = irs->dynamicCompiledFunctions.find(srcFunc);
assert(irs->dynamicCompiledFunctions.end() != it);
auto thunkVarType = srcFunc->getFunctionType()->getPointerTo();
auto thunkVar = new llvm::GlobalVariable(
irs->module, thunkVarType, false, llvm::GlobalValue::PrivateLinkage,
llvm::ConstantPointerNull::get(thunkVarType),
".rtcompile_thunkvar_" + srcFunc->getName());
auto dstFunc = it->second.thunkFunc;
createThunkFunc(irs->module, srcFunc, dstFunc, thunkVar);
it->second.thunkVar = thunkVar;
}
}
void addDynamicCompiledVar(IRState *irs, IrGlobal *var) {

View file

@ -584,7 +584,7 @@ void DtoDeclareFunction(FuncDeclaration *fdecl) {
applyTargetMachineAttributes(*func, *gTargetMachine);
applyFuncDeclUDAs(fdecl, irFunc);
if(irFunc->dynamicCompile) {
if(irFunc->isDynamicCompiled()) {
declareDynamicCompiledFunction(gIR, irFunc);
}
@ -976,7 +976,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
}
SCOPE_EXIT {
if (irFunc->dynamicCompile) {
if (irFunc->isDynamicCompiled()) {
defineDynamicCompiledFunction(gIR, irFunc);
}
};

View file

@ -376,7 +376,8 @@ void applyVarDeclUDAs(VarDeclaration *decl, llvm::GlobalVariable *gvar) {
applyAttrAssumeUsed(*gIR, sle, gvar);
} else if (ident == Id::udaWeak) {
// @weak is applied elsewhere
} else if (ident == Id::udaDynamicCompile) {
} else if (ident == Id::udaDynamicCompile ||
ident == Id::udaDynamicCompileEmit) {
sle->error(
"Special attribute `ldc.attributes.%s` is only valid for functions",
ident->toChars());
@ -423,6 +424,8 @@ void applyFuncDeclUDAs(FuncDeclaration *decl, IrFunction *irFunc) {
// @weak and @kernel are applied elsewhere
} else if (ident == Id::udaDynamicCompile) {
irFunc->dynamicCompile = true;
} else if (ident == Id::udaDynamicCompileEmit) {
irFunc->dynamicCompileEmit = true;
} else if (ident == Id::udaDynamicCompileConst) {
sle->error(
"Special attribute `ldc.attributes.%s` is only valid for variables",

View file

@ -80,6 +80,10 @@ llvm::Function *IrFunction::getLLVMCallee() const {
return rtCompileFunc != nullptr ? rtCompileFunc : func;
}
bool IrFunction::isDynamicCompiled() const {
return dynamicCompile || dynamicCompileEmit;
}
IrFunction *getIrFunc(FuncDeclaration *decl, bool create) {
if (!isIrFuncCreated(decl) && create) {
assert(decl->ir->irFunc == NULL);

View file

@ -50,6 +50,8 @@ struct IrFunction {
/// some sort of wrapper, e.g., a JIT wrapper).
llvm::Function *getLLVMCallee() const;
bool isDynamicCompiled() const;
FuncDeclaration *decl = nullptr;
TypeFunction *type = nullptr;
@ -90,6 +92,9 @@ struct IrFunction {
/// This functions was marked for dynamic compilation
bool dynamicCompile = false;
/// This functions was marked emit-only for dynamic compilation
bool dynamicCompileEmit = false;
/// Dynamic compilation thunk, all attempts to call or take address of the
/// original function will be redirected to it
llvm::Function *rtCompileFunc = nullptr;

@ -1 +1 @@
Subproject commit 41e9dece3fc6c2bc966cfa327ae8160f67a4c569
Subproject commit cefb4fc03c5cf8d4ee6f7644b126ddaf5b86c7a1

View file

@ -0,0 +1,51 @@
// RUN: %ldc -enable-dynamic-compile -run %s
import std.stdio;
import std.array;
import std.string;
import ldc.attributes;
import ldc.dynamic_compile;
int foo()
{
return 42;
}
@dynamicCompileEmit int bar()
{
return 43;
}
@dynamicCompileEmit @dynamicCompile int baz()
{
return 44;
}
void main(string[] args)
{
assert(43 == bar());
auto dump = appender!string();
CompilerSettings settings;
settings.dumpHandler = (DumpStage stage, in char[] str)
{
if (DumpStage.OriginalModule == stage)
{
write(str);
dump.put(str);
}
};
writeln("===========================================");
compileDynamicCode(settings);
writeln();
writeln("===========================================");
stdout.flush();
assert(44 == baz());
// Check function name in original IR
assert(count(dump.data, foo.mangleof) == 0);
assert(count(dump.data, bar.mangleof) > 0);
assert(count(dump.data, baz.mangleof) > 0);
}