Skip to content

Commit

Permalink
Optimizations for Memory{T} allocation calls (#51968)
Browse files Browse the repository at this point in the history
Special case for the Memory{T} allocation in ccall so that we can add
attributes and permit method inlining when constructing an Array by
removing `@noinline`.
  • Loading branch information
gbaraldi authored Nov 8, 2023
1 parent 6f6419c commit 8f8b9ca
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 10 deletions.
4 changes: 0 additions & 4 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -559,20 +559,16 @@ end

# type and dimensionality specified, accepting dims as series of Ints
eval(Core, :(function (self::Type{Array{T,1}})(::UndefInitializer, m::Int) where {T}
@noinline
mem = fieldtype(fieldtype(self, :ref), :mem)(undef, m)
return $(Expr(:new, :self, :(memoryref(mem)), :((m,))))
end))
eval(Core, :(function (self::Type{Array{T,2}})(::UndefInitializer, m::Int, n::Int) where {T}
@noinline
return $(Expr(:new, :self, :(new_as_memoryref(fieldtype(self, :ref), checked_dims(m, n))), :((m, n))))
end))
eval(Core, :(function (self::Type{Array{T,3}})(::UndefInitializer, m::Int, n::Int, o::Int) where {T}
@noinline
return $(Expr(:new, :self, :(new_as_memoryref(fieldtype(self, :ref), checked_dims(m, n, o))), :((m, n, o))))
end))
eval(Core, :(function (self::Type{Array{T, N}})(::UndefInitializer, d::Vararg{Int, N}) where {T, N}
@noinline
return $(Expr(:new, :self, :(new_as_memoryref(fieldtype(self, :ref), checked_dims(d...))), :d))
end))
# type and dimensionality specified, accepting dims as tuples of Ints
Expand Down
28 changes: 28 additions & 0 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ TRANSFORMED_CCALL_STAT(jl_svec_ref);
TRANSFORMED_CCALL_STAT(jl_string_ptr);
TRANSFORMED_CCALL_STAT(jl_symbol_name);
TRANSFORMED_CCALL_STAT(jl_genericmemory_owner);
TRANSFORMED_CCALL_STAT(jl_alloc_genericmemory);
TRANSFORMED_CCALL_STAT(memcpy);
TRANSFORMED_CCALL_STAT(memset);
TRANSFORMED_CCALL_STAT(memmove);
Expand Down Expand Up @@ -1771,6 +1772,33 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs)
JL_GC_POP();
return mark_julia_type(ctx, obj, true, jl_any_type);
}
else if (is_libjulia_func(jl_alloc_genericmemory)) {
++CCALL_STAT(jl_alloc_genericmemory);
assert(lrt == ctx.types().T_prjlvalue);
assert(!isVa && !llvmcall && nccallargs == 2);
const jl_cgval_t &typ = argv[0];
const jl_cgval_t &nel = argv[1];
auto arg_typename = [&] JL_NOTSAFEPOINT {
auto istyp = argv[0].constant;
std::string type_str;
if (istyp && jl_is_datatype(istyp) && jl_is_genericmemory_type(istyp)){
auto eltype = jl_tparam1(istyp);
if (jl_is_datatype(eltype))
type_str = jl_symbol_name(((jl_datatype_t*)eltype)->name->name);
else if (jl_is_uniontype(eltype))
type_str = "Union";
else
type_str = "<unknown type>";
}
else
type_str = "<unknown type>";
return "Memory{" + type_str + "}[]";
};
auto alloc = ctx.builder.CreateCall(prepare_call(jl_allocgenericmemory), { boxed(ctx,typ), emit_unbox(ctx, ctx.types().T_size, nel, (jl_value_t*)jl_ulong_type)});
setName(ctx.emission_context, alloc, arg_typename);
JL_GC_POP();
return mark_julia_type(ctx, alloc, true, jl_any_type);
}
else if (is_libjulia_func(memcpy) && (rt == (jl_value_t*)jl_nothing_type || jl_is_cpointer_type(rt))) {
++CCALL_STAT(memcpy);
const jl_cgval_t &dst = argv[0];
Expand Down
10 changes: 5 additions & 5 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3350,10 +3350,10 @@ static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &vinfo, bool is_promotab
ctx.builder.restoreIP(IP);
} else {
auto arg_typename = [&] JL_NOTSAFEPOINT {
return jl_symbol_name(((jl_datatype_t*)(jt))->name->name);
return "box::" + std::string(jl_symbol_name(((jl_datatype_t*)(jt))->name->name));
};
box = emit_allocobj(ctx, (jl_datatype_t*)jt);
setName(ctx.emission_context, box, "box" + StringRef("::") + arg_typename());
setName(ctx.emission_context, box, arg_typename);
init_bits_cgval(ctx, box, vinfo, jl_is_mutable(jt) ? ctx.tbaa().tbaa_mutab : ctx.tbaa().tbaa_immut);
}
}
Expand Down Expand Up @@ -3693,7 +3693,7 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg
assert(jl_is_concrete_type(ty));
jl_datatype_t *sty = (jl_datatype_t*)ty;
auto arg_typename = [&] JL_NOTSAFEPOINT {
return jl_symbol_name((sty)->name->name);
return "new::" + std::string(jl_symbol_name((sty)->name->name));
};
size_t nf = jl_datatype_nfields(sty);
if (nf > 0 || sty->name->mutabl) {
Expand Down Expand Up @@ -3726,7 +3726,7 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg
}
else {
strct = emit_static_alloca(ctx, lt);
setName(ctx.emission_context, strct, "new" + StringRef("::") + arg_typename());
setName(ctx.emission_context, strct, arg_typename);
if (tracked.count)
undef_derived_strct(ctx, strct, sty, ctx.tbaa().tbaa_stack);
}
Expand Down Expand Up @@ -3897,7 +3897,7 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg
}
}
Value *strct = emit_allocobj(ctx, sty);
setName(ctx.emission_context, strct, "new" + StringRef("::") + arg_typename());
setName(ctx.emission_context, strct, arg_typename);
jl_cgval_t strctinfo = mark_julia_type(ctx, strct, true, ty);
strct = decay_derived(ctx, strct);
undef_derived_strct(ctx, strct, sty, strctinfo.tbaa);
Expand Down
24 changes: 24 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1300,6 +1300,29 @@ static const auto sync_gc_total_bytes_func = new JuliaFunction<>{
{getInt64Ty(C)}, false); },
nullptr,
};
static const auto jl_allocgenericmemory = new JuliaFunction<TypeFnContextAndSizeT>{
XSTR(jl_alloc_genericmemory),
[](LLVMContext &C, Type *T_Size) {
auto T_prjlvalue = JuliaType::get_prjlvalue_ty(C);
return FunctionType::get(T_prjlvalue, // new Memory
{T_prjlvalue, // type
T_Size // nelements
}, false); },
[](LLVMContext &C) {
AttrBuilder FnAttrs(C);
AttrBuilder RetAttrs(C);
#if JL_LLVM_VERSION >= 160000
FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef) | argMemOnly(MemoryEffects::ModRefInfo::Ref));
#endif
FnAttrs.addAttribute(Attribute::WillReturn);
RetAttrs.addAlignmentAttr(Align(16));
RetAttrs.addAttribute(Attribute::NonNull);
RetAttrs.addDereferenceableAttr(16);
return AttributeList::get(C,
AttributeSet::get(C, FnAttrs),
AttributeSet::get(C, RetAttrs),
None); },
};
static const auto jlarray_data_owner_func = new JuliaFunction<>{
XSTR(jl_array_data_owner),
[](LLVMContext &C) {
Expand Down Expand Up @@ -9407,6 +9430,7 @@ static void init_jit_functions(void)
add_named_global(jlfieldindex_func, &jl_field_index);
add_named_global(diff_gc_total_bytes_func, &jl_gc_diff_total_bytes);
add_named_global(sync_gc_total_bytes_func, &jl_gc_sync_total_bytes);
add_named_global(jl_allocgenericmemory, &jl_alloc_genericmemory);
add_named_global(gcroot_flush_func, (void*)NULL);
add_named_global(gc_preserve_begin_func, (void*)NULL);
add_named_global(gc_preserve_end_func, (void*)NULL);
Expand Down
2 changes: 1 addition & 1 deletion test/compiler/irpasses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ function isdefined_elim()
return arr
end
let src = code_typed1(isdefined_elim)
@test is_scalar_replaced(src)
@test count(isisdefined, src.code) == 0
end
@test isdefined_elim() == Any[]

Expand Down
1 change: 1 addition & 0 deletions test/compiler/irutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ end
isnew(@nospecialize x) = isexpr(x, :new)
issplatnew(@nospecialize x) = isexpr(x, :splatnew)
isreturn(@nospecialize x) = isa(x, ReturnNode) && isdefined(x, :val)
isisdefined(@nospecialize x) = isexpr(x, :isdefined)

# check if `x` is a dynamic call of a given function
iscall(y) = @nospecialize(x) -> iscall(y, x)
Expand Down
9 changes: 9 additions & 0 deletions test/llvmpasses/names.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ end
struct Named
x::Int
end

function fmemory(nel)
return Memory{Int64}(undef,nel)
end
# CHECK-LABEL: define {{(swiftcc )?}}double @julia_f1
# CHECK-SAME: double %"a::Float64"
# CHECK-SAME: double %"b::Float64"
Expand Down Expand Up @@ -175,3 +179,8 @@ emit(f8, Barrier, Int)
# CHECK: %parent_bits
# CHECK: %parent_old_marked
emit(Barrier, Named)

# CHECK: define {{(swiftcc )?}}nonnull {} addrspace(10)* @julia_fmemory
# CHECK-SAME: %"nel::Int64"
# CHECK: %"Memory{Int64}[]"
emit(fmemory, Int64)

0 comments on commit 8f8b9ca

Please sign in to comment.