From 390450dc42fa3f16becba31dda0db788ce983ca5 Mon Sep 17 00:00:00 2001 From: Troels Nielsen Date: Thu, 26 Aug 2021 17:44:27 +0200 Subject: [PATCH] codegen: parameter attributes on CFunction closures sticks (#41827) 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. (cherry picked from commit 08f342230e056c118dedd9889c558ebcbbb26603) --- src/codegen.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- test/ccall.jl | 20 ++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 60a5fb98da25f..59f5d9e8b7d84 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4826,9 +4826,48 @@ static Function* gen_cfun_wrapper( // add nest parameter (pointer to jl_value_t* data array) after sret arg assert(closure_types); std::vector 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> 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(); diff --git a/test/ccall.jl b/test/ccall.jl index 5f5272c372a11..1da7e2a145ee2 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -979,6 +979,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"