Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix codegen not handling invoke exprs with Codeinstances iwith jl_fptr_sparam_addr invoke types. #56817

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Compiler/test/codegen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1027,3 +1027,12 @@ for a in ((@noinline Ref{Int}(2)),
@test ex === a
end
end

# Make sure that code that has unbound sparams works
#https://github.com/JuliaLang/julia/issues/56739

f56739(a) where {T} = a

@test f56739(1) == 1
g56739(x) = @noinline f56739(x)
@test g56739(1) == 1
106 changes: 57 additions & 49 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5484,62 +5484,70 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR
result = mark_julia_const(ctx, codeinst->rettype_const);
handled = true;
}
else if (invoke != jl_fptr_sparam_addr) {
else {
bool specsig, needsparams;
std::tie(specsig, needsparams) = uses_specsig(mi, codeinst->rettype, ctx.params->prefer_specsig);
std::string name;
StringRef protoname;
bool need_to_emit = true;
bool cache_valid = ctx.use_cache || ctx.external_linkage;
bool external = false;

// Check if we already queued this up
auto it = ctx.call_targets.find(codeinst);
if (need_to_emit && it != ctx.call_targets.end()) {
assert(it->second.specsig == specsig);
protoname = it->second.decl->getName();
need_to_emit = cache_valid = false;
}
if (needsparams) {
if (trim_may_error(ctx.params->trim))
push_frames(ctx, ctx.linfo, mi);
Value *r = emit_jlcall(ctx, jlinvoke_func, track_pjlvalue(ctx, literal_pointer_val(ctx, (jl_value_t*)mi)), argv, nargs, julia_call2);
result = mark_julia_type(ctx, r, true, rt);
handled = true;
} else {
std::string name;
StringRef protoname;
bool need_to_emit = true;
bool cache_valid = ctx.use_cache || ctx.external_linkage;
bool external = false;

// Check if we already queued this up
auto it = ctx.call_targets.find(codeinst);
if (need_to_emit && it != ctx.call_targets.end()) {
assert(it->second.specsig == specsig);
protoname = it->second.decl->getName();
need_to_emit = cache_valid = false;
}

// Check if it is already compiled (either JIT or externally)
if (need_to_emit && cache_valid) {
// optimization: emit the correct name immediately, if we know it
// TODO: use `emitted` map here too to try to consolidate names?
uint8_t specsigflags;
jl_callptr_t invoke;
void *fptr;
jl_read_codeinst_invoke(codeinst, &specsigflags, &invoke, &fptr, 0);
if (specsig ? specsigflags & 0b1 : invoke == jl_fptr_args_addr) {
protoname = jl_ExecutionEngine->getFunctionAtAddress((uintptr_t)fptr, invoke, codeinst);
if (ctx.external_linkage) {
// TODO: Add !specsig support to aotcompile.cpp
// Check that the codeinst is containing native code
if (specsig && (specsigflags & 0b100)) {
external = true;
// Check if it is already compiled (either JIT or externally)
if (need_to_emit && cache_valid) {
// optimization: emit the correct name immediately, if we know it
// TODO: use `emitted` map here too to try to consolidate names?
uint8_t specsigflags;
jl_callptr_t invoke;
void *fptr;
jl_read_codeinst_invoke(codeinst, &specsigflags, &invoke, &fptr, 0);
if (specsig ? specsigflags & 0b1 : invoke == jl_fptr_args_addr) {
protoname = jl_ExecutionEngine->getFunctionAtAddress((uintptr_t)fptr, invoke, codeinst);
if (ctx.external_linkage) {
// TODO: Add !specsig support to aotcompile.cpp
// Check that the codeinst is containing native code
if (specsig && (specsigflags & 0b100)) {
external = true;
need_to_emit = false;
}
}
else { // ctx.use_cache
need_to_emit = false;
}
}
else { // ctx.use_cache
need_to_emit = false;
}
}
}
if (need_to_emit) {
raw_string_ostream(name) << (specsig ? "j_" : "j1_") << name_from_method_instance(mi) << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1);
protoname = StringRef(name);
}
jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed;
unsigned return_roots = 0;
if (specsig)
result = emit_call_specfun_other(ctx, mi, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok);
else
result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt, age_ok);
handled = true;
if (need_to_emit) {
Function *trampoline_decl = cast<Function>(jl_Module->getNamedValue(protoname));
ctx.call_targets[codeinst] = {cc, return_roots, trampoline_decl, nullptr, specsig};
if (trim_may_error(ctx.params->trim))
push_frames(ctx, ctx.linfo, mi);
if (need_to_emit) {
raw_string_ostream(name) << (specsig ? "j_" : "j1_") << name_from_method_instance(mi) << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1);
protoname = StringRef(name);
}
jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed;
unsigned return_roots = 0;
if (specsig)
result = emit_call_specfun_other(ctx, mi, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok);
else
result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt, age_ok);
handled = true;
if (need_to_emit) {
Function *trampoline_decl = cast<Function>(jl_Module->getNamedValue(protoname));
ctx.call_targets[codeinst] = {cc, return_roots, trampoline_decl, nullptr, specsig};
if (trim_may_error(ctx.params->trim))
push_frames(ctx, ctx.linfo, mi);
}
}
}
}
Expand Down
Loading