Skip to content

Commit

Permalink
codegen: parameter attributes on CFunction closures sticks (#41827)
Browse files Browse the repository at this point in the history
When CFunction closures are created an extra argument is added to the
function signature for holding the closure.

Make sure that the parameter attributes on already existing parameters
are not shifted when adding that parameter.
  • Loading branch information
troels authored Aug 26, 2021
1 parent 8464929 commit 08f3422
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
41 changes: 40 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5180,9 +5180,48 @@ static Function* gen_cfun_wrapper(
// add nest parameter (pointer to jl_value_t* data array) after sret arg
assert(closure_types);
std::vector<Type*> fargt_sig(sig.fargt_sig);

fargt_sig.insert(fargt_sig.begin() + sig.sret, T_pprjlvalue);

// Shift LLVM attributes for parameters one to the right, as
// we are adding the extra nest parameter after sret arg.
std::vector<std::pair<unsigned, AttributeSet>> newAttributes;
newAttributes.reserve(attributes.getNumAttrSets() + 1);
auto it = attributes.index_begin();

// Skip past FunctionIndex
if (it == AttributeList::AttrIndex::FunctionIndex) {
++it;
}

// Move past ReturnValue and parameter return value
for (;it < AttributeList::AttrIndex::FirstArgIndex + sig.sret; ++it) {
if (attributes.hasAttributes(it)) {
newAttributes.emplace_back(it, attributes.getAttributes(it));
}
}

// Add the new nest attribute
AttrBuilder attrBuilder;
attrBuilder.addAttribute(Attribute::Nest);
newAttributes.emplace_back(it, AttributeSet::get(jl_LLVMContext, attrBuilder));

// Shift forward the rest of the attributes
for(;it < attributes.index_end(); ++it) {
if (attributes.hasAttributes(it)) {
newAttributes.emplace_back(it + 1, attributes.getAttributes(it));
}
}

// Remember to add back FunctionIndex
if (attributes.hasAttributes(AttributeList::AttrIndex::FunctionIndex)) {
newAttributes.emplace_back(AttributeList::AttrIndex::FunctionIndex,
attributes.getAttributes(AttributeList::AttrIndex::FunctionIndex));
}

// Create the new AttributeList
attributes = AttributeList::get(jl_LLVMContext, newAttributes);
functype = FunctionType::get(sig.sret ? T_void : sig.prt, fargt_sig, /*isVa*/false);
attributes = attributes.addAttribute(jl_LLVMContext, 1 + sig.sret, Attribute::Nest);
}
else {
functype = sig.functype();
Expand Down
20 changes: 20 additions & 0 deletions test/ccall.jl
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,26 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64),
end
end


#issue 40164
@testset "llvm parameter attributes on cfunction closures" begin
struct Struct40164
x::Cdouble
y::Cdouble
z::Cdouble
end

function test_40164()
ret = Struct40164[]
f = x::Struct40164 -> (push!(ret, x); nothing)
f_c = @cfunction($f, Cvoid, (Struct40164,))
ccall(f_c.ptr, Ptr{Cvoid}, (Struct40164,), Struct40164(0, 1, 2))
ret
end

@test test_40164() == [Struct40164(0, 1, 2)]
end

else

@test_broken "cfunction: no support for closures on this platform"
Expand Down

0 comments on commit 08f3422

Please sign in to comment.