Skip to content

Commit

Permalink
Merge pull request #36482 from JuliaLang/jn/codegen-anon-globals
Browse files Browse the repository at this point in the history
attempts at minor codegen improvements
  • Loading branch information
vtjnash authored Jul 2, 2020
2 parents ab05173 + 8803113 commit 7dba988
Show file tree
Hide file tree
Showing 26 changed files with 842 additions and 865 deletions.
2 changes: 0 additions & 2 deletions src/anticodegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

#include "intrinsics.h"

int globalUnique = 0;

#define UNAVAILABLE { jl_errorf("%s: not available in this build of Julia", __func__); }

void jl_dump_native(const char *bc_fname, const char *unopt_bc_fname, const char *obj_fname, const char *asm_fname, const char *sysimg_data, size_t sysimg_len) UNAVAILABLE
Expand Down
8 changes: 1 addition & 7 deletions src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,13 +565,6 @@ void jl_dump_native(void *native_code,
sysimage->setDataLayout(data->M->getDataLayout());
data->M.reset(); // free memory for data->M

addComdat(new GlobalVariable(*sysimage,
T_size,
true,
GlobalVariable::ExternalLinkage,
ConstantInt::get(T_size, globalUnique + 1),
"jl_globalUnique"));

if (sysimg_data) {
Constant *data = ConstantDataArray::get(Context,
ArrayRef<uint8_t>((const unsigned char*)sysimg_data, sysimg_len));
Expand Down Expand Up @@ -619,6 +612,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level,
PM->add(createVerifierPass());
#endif

PM->add(createConstantMergePass());
if (opt_level < 2) {
PM->add(createCFGSimplificationPass());
if (opt_level == 1) {
Expand Down
52 changes: 24 additions & 28 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ static bool runtime_sym_gvs(jl_codegen_params_t &emission_context, const char *f

GlobalVariable *&llvmgv = (*symMap)[f_name];
if (llvmgv == NULL) {
// MCJIT forces this to have external linkage eventually, so we would clobber
// the symbol of the actual function.
std::string name = "ccall_";
name += f_name;
name += "_";
Expand Down Expand Up @@ -154,20 +152,19 @@ static GlobalVariable *emit_plt_thunk(
PointerType *funcptype = PointerType::get(functype, 0);
libptrgv = prepare_global_in(M, libptrgv);
llvmgv = prepare_global_in(M, llvmgv);
std::stringstream funcName;
funcName << "jlplt_" << f_name << "_" << globalUnique++;
auto fname = funcName.str();
std::string fname;
raw_string_ostream(fname) << "jlplt_" << f_name << "_" << globalUnique++;
Function *plt = Function::Create(functype,
GlobalVariable::ExternalLinkage,
fname, M);
plt->setAttributes(attrs);
if (cc != CallingConv::C)
plt->setCallingConv(cc);
funcName << "_got";
auto gname = funcName.str();
fname += "_got";
GlobalVariable *got = new GlobalVariable(*M, T_pvoidfunc, false,
GlobalVariable::ExternalLinkage,
ConstantExpr::getBitCast(plt, T_pvoidfunc), gname);
ConstantExpr::getBitCast(plt, T_pvoidfunc),
fname);
BasicBlock *b0 = BasicBlock::Create(jl_LLVMContext, "top", plt);
IRBuilder<> irbuilder(b0);
Value *ptr = runtime_sym_lookup(emission_context, irbuilder, funcptype, f_lib, f_name, plt, libptrgv,
Expand Down Expand Up @@ -383,7 +380,8 @@ static Value *runtime_apply_type_env(jl_codectx_t &ctx, jl_value_t *ty)

static const std::string make_errmsg(const char *fname, int n, const char *err)
{
std::stringstream msg;
std::string _msg;
raw_string_ostream msg(_msg);
msg << fname;
if (n > 0)
msg << " argument " << n;
Expand Down Expand Up @@ -866,11 +864,12 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
JL_TYPECHK(llvmcall, type, rt);
JL_TYPECHK(llvmcall, type, at);

std::stringstream ir_stream;
std::string ir_string;
raw_string_ostream ir_stream(ir_string);

// Generate arguments
std::string arguments;
llvm::raw_string_ostream argstream(arguments);
raw_string_ostream argstream(arguments);
jl_svec_t *tt = ((jl_datatype_t*)at)->parameters;
jl_value_t *rtt = rt;
size_t nargt = jl_svec_len(tt);
Expand Down Expand Up @@ -905,9 +904,7 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
// Make sure to find a unique name
std::string ir_name;
while (true) {
std::stringstream name;
name << (ctx.f->getName().str()) << "u" << globalUnique++;
ir_name = name.str();
raw_string_ostream(ir_name) << (ctx.f->getName().str()) << "u" << globalUnique++;
if (jl_Module->getFunction(ir_name) == NULL)
break;
}
Expand All @@ -923,25 +920,25 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
}

std::string rstring;
llvm::raw_string_ostream rtypename(rstring);
raw_string_ostream rtypename(rstring);
rettype->print(rtypename);
std::map<uint64_t,std::string> localDecls;

if (decl != NULL) {
std::stringstream declarations(jl_string_data(decl));

// parse string line by line
std::string declstr;
while (std::getline(declarations, declstr, '\n')) {
StringRef declarations(jl_string_data(decl), jl_string_len(decl));
while (!declarations.empty()) {
StringRef declstr;
std::tie(declstr, declarations) = declarations.split('\n');
// Find name of declaration by searching for '@'
std::string::size_type atpos = declstr.find('@') + 1;
size_t atpos = declstr.find('@') + 1;
// Find end of declaration by searching for '('
std::string::size_type bracepos = declstr.find('(', atpos);
size_t bracepos = declstr.find('(', atpos);
// Declaration name is the string between @ and (
std::string declname = declstr.substr(atpos, bracepos - atpos);
StringRef declname = declstr.substr(atpos, bracepos - atpos);

// Check if declaration already present in module
if(jl_Module->getNamedValue(declname) == NULL) {
if (jl_Module->getNamedValue(declname) == NULL) {
ir_stream << "; Declarations\n" << declstr << "\n";
}
}
Expand All @@ -950,11 +947,10 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
<< "define "<<rtypename.str()<<" @\"" << ir_name << "\"("<<argstream.str()<<") {\n"
<< jl_string_data(ir) << "\n}";
SMDiagnostic Err = SMDiagnostic();
std::string ir_string = ir_stream.str();
// Do not enable update debug info since it runs the verifier on the whole module
// and will error on the function we are currently emitting.
ModuleSummaryIndex index = ModuleSummaryIndex(true);
bool failed = parseAssemblyInto(MemoryBufferRef(ir_string, "llvmcall"),
bool failed = parseAssemblyInto(MemoryBufferRef(ir_stream.str(), "llvmcall"),
jl_Module, &index, Err, nullptr,
/* UpdateDebugInfo */ false);
f = jl_Module->getFunction(ir_name);
Expand Down Expand Up @@ -999,9 +995,9 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
// a regular call
if (!isString) {
static int llvmcallnumbering = 0;
std::stringstream name;
name << "jl_llvmcall" << llvmcallnumbering++;
f->setName(name.str());
std::string name;
llvm::raw_string_ostream(name) << "jl_llvmcall" << llvmcallnumbering++;
f->setName(name);
f = prepare_llvmcall(jl_Module, llvmcall_proto(f));
}
else {
Expand Down
66 changes: 30 additions & 36 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,27 +94,16 @@ static Value *stringConstPtr(
IRBuilder<> &irbuilder,
const std::string &txt)
{
StringRef ctxt(txt.c_str(), txt.size() + 1);
StringMap<GlobalVariable*>::iterator pooledval =
emission_context.stringConstants.insert(std::pair<StringRef, GlobalVariable*>(ctxt, NULL)).first;
Module *M = jl_builderModule(irbuilder);
if (pooledval->second == NULL) {
static int strno = 0;
std::stringstream ssno;
ssno << "_j_str" << strno++;
GlobalVariable *gv = get_pointer_to_constant(
ConstantDataArray::get(jl_LLVMContext, ArrayRef<char>(ctxt.data(), ctxt.size())),
ssno.str(), *M);
pooledval->second = gv;
}
GlobalVariable *v = prepare_global_in(M, pooledval->second);
if (v != pooledval->second)
v->setInitializer(pooledval->second->getInitializer());
StringRef ctxt(txt.c_str(), txt.size() + 1);
Constant *Data = ConstantDataArray::get(jl_LLVMContext, arrayRefFromStringRef(ctxt));
GlobalVariable *gv = get_pointer_to_constant(emission_context, Data, "_j_str", *M);
Value *zero = ConstantInt::get(Type::getInt32Ty(jl_LLVMContext), 0);
Value *Args[] = { zero, zero };
return irbuilder.CreateInBoundsGEP(v->getValueType(), v, Args);
return irbuilder.CreateInBoundsGEP(gv->getValueType(), gv, Args);
}


// --- MDNode ---
Metadata *to_md_tree(jl_value_t *val) {
if (val == jl_nothing)
Expand Down Expand Up @@ -170,8 +159,8 @@ static DIType *_julia_type_to_di(jl_codegen_params_t *ctx, jl_value_t *jt, DIBui
Elements[i] = di;
}
DINodeArray ElemArray = dbuilder->getOrCreateArray(Elements);
std::stringstream unique_name;
unique_name << (uintptr_t)jdt;
std::string unique_name;
raw_string_ostream(unique_name) << (uintptr_t)jdt;
ditype = dbuilder->createStructType(
NULL, // Scope
tname, // Name
Expand All @@ -184,7 +173,7 @@ static DIType *_julia_type_to_di(jl_codegen_params_t *ctx, jl_value_t *jt, DIBui
ElemArray, // Elements
dwarf::DW_LANG_Julia, // RuntimeLanguage
nullptr, // VTableHolder
unique_name.str() // UniqueIdentifier
unique_name // UniqueIdentifier
);
}
else {
Expand Down Expand Up @@ -237,23 +226,28 @@ static inline Constant *literal_static_pointer_val(const void *p, Type *T = T_pj

static Value *julia_pgv(jl_codectx_t &ctx, const char *cname, void *addr)
{
// first see if there already is a GlobalVariable for this address
// emit a GlobalVariable for a jl_value_t named "cname"
// store the name given so we can reuse it (facilitating merging later)
// so first see if there already is a GlobalVariable for this address
GlobalVariable* &gv = ctx.global_targets[addr];
Module *M = jl_Module;
StringRef localname;
std::string gvname;
if (!gv) {
// otherwise emit a new GlobalVariable for a jl_value_t named "cname"
std::stringstream gvname;
gvname << cname << globalUnique++;
// no existing GlobalVariable, create one and store it
gv = new GlobalVariable(*M, T_pjlvalue,
false, GlobalVariable::ExternalLinkage,
NULL, gvname.str());
raw_string_ostream(gvname) << cname << ctx.global_targets.size();
localname = StringRef(gvname);
}
else if (gv->getParent() != M) {
// re-use the same name, but move it to the new module
// this will help simplify merging them later
gv = prepare_global_in(M, gv);
else {
localname = gv->getName();
if (gv->getParent() != M)
gv = cast_or_null<GlobalVariable>(M->getNamedValue(localname));
}
if (gv == nullptr)
gv = new GlobalVariable(*M, T_pjlvalue,
false, GlobalVariable::PrivateLinkage,
NULL, localname);
assert(localname == gv->getName());
assert(!gv->hasInitializer());
return gv;
}

Expand Down Expand Up @@ -291,6 +285,8 @@ static Value *literal_pointer_val_slot(jl_codectx_t &ctx, jl_value_t *p)
// emit a pointer to a jl_value_t* which will allow it to be valid across reloading code
// also, try to give it a nice name for gdb, for easy identification
if (!imaging_mode) {
// TODO: this is an optimization, but is it useful or premature
// (it'll block any attempt to cache these, but can be simply deleted)
Module *M = jl_Module;
GlobalVariable *gv = new GlobalVariable(
*M, T_pjlvalue, true, GlobalVariable::PrivateLinkage,
Expand Down Expand Up @@ -1423,12 +1419,10 @@ static Value *data_pointer(jl_codectx_t &ctx, const jl_cgval_t &x)
Value *data = x.V;
if (x.constant) {
Constant *val = julia_const_to_llvm(ctx, x.constant);
if (val) {
data = get_pointer_to_constant(val, "", *jl_Module);
}
else {
if (val)
data = get_pointer_to_constant(ctx.emission_context, val, "_j_const", *jl_Module);
else
data = literal_pointer_val(ctx, x.constant);
}
}
return data;
}
Expand Down
Loading

2 comments on commit 7dba988

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing the daily benchmark build, I will reply here when finished:

@nanosoldier runbenchmarks(ALL, isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan

Please sign in to comment.