Skip to content

Commit

Permalink
Make changes backwards compatible.
Browse files Browse the repository at this point in the history
  • Loading branch information
maleadt committed Mar 18, 2024
1 parent 06276d1 commit 2918cd6
Showing 1 changed file with 134 additions and 30 deletions.
164 changes: 134 additions & 30 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,18 +813,13 @@ 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);

// Generate arguments
std::string arguments;
raw_string_ostream argstream(arguments);
jl_svec_t *tt = ((jl_datatype_t*)at)->parameters;
jl_value_t *rtt = rt;
// Determine argument types
//
// Semantics for arguments are as follows:
// If the argument type is immutable (including bitstype), we pass the loaded llvm value
// type. Otherwise we pass a pointer to a jl_value_t.
jl_svec_t *tt = ((jl_datatype_t *)at)->parameters;
size_t nargt = jl_svec_len(tt);

/*
* Semantics for arguments are as follows:
* If the argument type is immutable (including bitstype), we pass the loaded llvm value
* type. Otherwise we pass a pointer to a jl_value_t.
*/
SmallVector<llvm::Type*, 0> argtypes;
SmallVector<Value *, 8> argvals(nargt);
for (size_t i = 0; i < nargt; ++i) {
Expand All @@ -845,45 +840,87 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
argvals[i] = llvm_type_rewrite(ctx, v, t, issigned);
}

// Determine return type
jl_value_t *rtt = rt;
bool retboxed;
Type *rettype = julia_type_to_llvm(ctx, rtt, &retboxed);

// Make sure to find a unique name
std::string ir_name;
while (true) {
raw_string_ostream(ir_name) << (ctx.f->getName().str()) << "u" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1);
raw_string_ostream(ir_name)
<< (ctx.f->getName().str()) << "u"
<< jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1);
if (jl_Module->getFunction(ir_name) == NULL)
break;
}

// generate a temporary module that contains our IR
std::unique_ptr<Module> Mod;
Function *f;
if (entry == NULL) {
// we only have function IR, which we should put in a function

bool first = true;
// stringify arguments
std::string arguments;
raw_string_ostream argstream(arguments);
for (SmallVector<Type *, 0>::iterator it = argtypes.begin(); it != argtypes.end(); ++it) {
if (!first)
if (it != argtypes.begin())
argstream << ",";
else
first = false;
(*it)->print(argstream);
argstream << " ";
}

// stringify return type
std::string rstring;
raw_string_ostream rtypename(rstring);
rettype->print(rtypename);
std::map<uint64_t,std::string> localDecls;

// generate IR function definition
std::string ir_string;
raw_string_ostream ir_stream(ir_string);
ir_stream << "; Number of arguments: " << nargt << "\n"
<< "define "<<rtypename.str()<<" @\"" << ir_name << "\"("<<argstream.str()<<") {\n"
<< jl_string_data(ir) << "\n}";
ir_stream << "define " << rtypename.str() << " @\"" << ir_name << "\"("
<< argstream.str() << ") {\n"
<< jl_string_data(ir) << "\n}";

SMDiagnostic Err = SMDiagnostic();
Mod = parseAssemblyString(ir_stream.str(), Err, ctx.builder.getContext());

// backwards compatibility: support for IR with integer pointers
if (!Mod) {
std::string compat_arguments;
raw_string_ostream compat_argstream(compat_arguments);
for (size_t i = 0; i < nargt; ++i) {
if (i > 0)
compat_argstream << ",";
jl_value_t *tti = jl_svecref(tt, i);
Type *t;
if (jl_is_cpointer_type(tti))
t = ctx.types().T_size;
else
t = argtypes[i];
t->print(compat_argstream);
compat_argstream << " ";
}

std::string compat_rstring;
raw_string_ostream compat_rtypename(compat_rstring);
if (jl_is_cpointer_type(rtt))
ctx.types().T_size->print(compat_rtypename);
else
rettype->print(compat_rtypename);

std::string compat_ir_string;
raw_string_ostream compat_ir_stream(compat_ir_string);
compat_ir_stream << "define " << compat_rtypename.str() << " @\"" << ir_name
<< "\"(" << compat_argstream.str() << ") {\n"
<< jl_string_data(ir) << "\n}";

SMDiagnostic Err = SMDiagnostic();
Mod =
parseAssemblyString(compat_ir_stream.str(), Err, ctx.builder.getContext());
}

if (!Mod) {
std::string message = "Failed to parse LLVM assembly: \n";
raw_string_ostream stream(message);
Expand All @@ -893,7 +930,7 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
return jl_cgval_t();
}

Function *f = Mod->getFunction(ir_name);
f = Mod->getFunction(ir_name);
f->addFnAttr(Attribute::AlwaysInline);
}
else {
Expand Down Expand Up @@ -931,21 +968,88 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
Mod = std::move(ModuleOrErr.get());
}

Function *f = Mod->getFunction(jl_string_data(entry));
f = Mod->getFunction(jl_string_data(entry));
if (!f) {
emit_error(ctx, "Module IR does not contain specified entry function");
JL_GC_POP();
return jl_cgval_t();
}
assert(!f->isDeclaration());
f->setName(ir_name);
}

// verify the function type
assert(!f->isDeclaration());
assert(f->getReturnType() == rettype);
int i = 0;
for (SmallVector<Type *, 0>::iterator it = argtypes.begin();
it != argtypes.end(); ++it, ++i)
assert(*it == f->getFunctionType()->getParamType(i));
// backwards compatibility: support for IR with integer pointers
bool mismatched_pointers = false;
for (size_t i = 0; i < nargt; ++i) {
jl_value_t *tti = jl_svecref(tt, i);
if (jl_is_cpointer_type(tti) &&
!f->getFunctionType()->getParamType(i)->isPointerTy()) {
mismatched_pointers = true;
break;
}
}
if (mismatched_pointers) {
if (jl_options.depwarn) {
if (jl_options.depwarn == JL_OPTIONS_DEPWARN_ERROR)
jl_error("llvmcall with integer pointers is deprecated, "
"use an actual pointer type instead.");
jl_printf(JL_STDERR,
"WARNING: llvmcall with integer pointers is deprecated.\n"
"Use actual pointers instead, replacing i32 or i64 with i8* or ptr");
if (jl_lineno != 0)
jl_printf(JL_STDERR, ", likely near %s:%d", jl_filename, jl_lineno);
jl_printf(JL_STDERR, "\n");
}

// wrap the function, performing the necesary pointer conversion

Check warning on line 1004 in src/ccall.cpp

View workflow job for this annotation

GitHub Actions / Check for new typos

perhaps "necesary" should be "necessary".

Function *inner = f;
inner->setName(ir_name + ".inner");

FunctionType *wrapper_ft = FunctionType::get(rettype, argtypes, false);
Function *wrapper =
Function::Create(wrapper_ft, inner->getLinkage(), ir_name, *Mod);

wrapper->copyAttributesFrom(inner);
inner->addFnAttr(Attribute::AlwaysInline);

BasicBlock *entry = BasicBlock::Create(ctx.builder.getContext(), "", wrapper);
IRBuilder<> irbuilder(entry);
SmallVector<Value *, 0> wrapper_args;
for (size_t i = 0; i < nargt; ++i) {
jl_value_t *tti = jl_svecref(tt, i);
Value *v = wrapper->getArg(i);
if (jl_is_cpointer_type(tti))
v = irbuilder.CreatePtrToInt(v, ctx.types().T_size);
wrapper_args.push_back(v);
}
Value *call = irbuilder.CreateCall(inner, wrapper_args);
// check if void
if (rettype->isVoidTy())
irbuilder.CreateRetVoid();
else {
if (jl_is_cpointer_type(rtt))
call = irbuilder.CreateIntToPtr(call, ctx.types().T_ptr);
irbuilder.CreateRet(call);
}

f = wrapper;
}

// verify the function type
assert(f->getReturnType() == rettype);
int i = 0;
for (SmallVector<Type *, 0>::iterator it = argtypes.begin(); it != argtypes.end();
++it, ++i) {
if (*it != f->getFunctionType()->getParamType(i)) {
std::string message;
raw_string_ostream stream(message);
stream << "Malformed llvmcall: argument " << i + 1 << " type "
<< *f->getFunctionType()->getParamType(i)
<< " does not match expected argument type " << **it;
emit_error(ctx, stream.str());
return jl_cgval_t();
}
}

// copy module properties that should always match
Expand Down Expand Up @@ -983,7 +1087,7 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
if (inst->getType() != rettype) {
std::string message;
raw_string_ostream stream(message);
stream << "llvmcall return type " << *inst->getType()
stream << "Malformed llvmcall: return type " << *inst->getType()
<< " does not match declared return type" << *rettype;
emit_error(ctx, stream.str());
return jl_cgval_t();
Expand Down

0 comments on commit 2918cd6

Please sign in to comment.