Skip to content

Commit fc31ce5

Browse files
committed
Add a white list of known non-safepoint functions
These are functions we emit in codegen directly that are known to not contain any safepoint
1 parent e5cc4d7 commit fc31ce5

File tree

3 files changed

+49
-8
lines changed

3 files changed

+49
-8
lines changed

src/codegen.cpp

+9-7
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ static Function *jlisa_func;
321321
static Function *jlsubtype_func;
322322
static Function *jlapplytype_func;
323323
static Function *setjmp_func;
324-
static Function *memcmp_func;
324+
static Function *memcmp_derived_func;
325325
static Function *box_int8_func;
326326
static Function *box_uint8_func;
327327
static Function *box_int16_func;
@@ -2280,7 +2280,7 @@ static Value *emit_bits_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const
22802280
assert(arg1.ispointer() && arg2.ispointer());
22812281
size_t sz = jl_datatype_size(arg1.typ);
22822282
if (sz > 512 && !((jl_datatype_t*)arg1.typ)->layout->haspadding) {
2283-
Value *answer = ctx.builder.CreateCall(prepare_call(memcmp_func),
2283+
Value *answer = ctx.builder.CreateCall(prepare_call(memcmp_derived_func),
22842284
{
22852285
data_pointer(ctx, arg1, T_pint8),
22862286
data_pointer(ctx, arg2, T_pint8),
@@ -6138,6 +6138,8 @@ static void init_julia_llvm_env(Module *m)
61386138
T_void = Type::getVoidTy(jl_LLVMContext);
61396139
T_pvoidfunc = FunctionType::get(T_void, /*isVarArg*/false)->getPointerTo();
61406140

6141+
auto T_pint8_derived = PointerType::get(T_int8, AddressSpace::Derived);
6142+
61416143
// This type is used to create undef Values for use in struct declarations to skip indices
61426144
NoopType = ArrayType::get(T_int1, 0);
61436145

@@ -6352,7 +6354,7 @@ static void init_julia_llvm_env(Module *m)
63526354
add_named_global(jlvboundserror_func, &jl_bounds_error_tuple_int);
63536355

63546356
std::vector<Type*> args3_uboundserror(0);
6355-
args3_uboundserror.push_back(PointerType::get(T_int8, AddressSpace::Derived));
6357+
args3_uboundserror.push_back(T_pint8_derived);
63566358
args3_uboundserror.push_back(T_prjlvalue);
63576359
args3_uboundserror.push_back(T_size);
63586360
jluboundserror_func =
@@ -6379,13 +6381,13 @@ static void init_julia_llvm_env(Module *m)
63796381
add_named_global(setjmp_func, &jl_setjmp_f);
63806382

63816383
std::vector<Type*> args_memcmp(0);
6382-
args_memcmp.push_back(T_pint8);
6383-
args_memcmp.push_back(T_pint8);
6384+
args_memcmp.push_back(T_pint8_derived);
6385+
args_memcmp.push_back(T_pint8_derived);
63846386
args_memcmp.push_back(T_size);
6385-
memcmp_func =
6387+
memcmp_derived_func =
63866388
Function::Create(FunctionType::get(T_int32, args_memcmp, false),
63876389
Function::ExternalLinkage, "memcmp", m);
6388-
add_named_global(memcmp_func, &memcmp);
6390+
add_named_global(memcmp_derived_func, &memcmp);
63896391

63906392
std::vector<Type*> te_args(0);
63916393
te_args.push_back(T_pint8);

src/llvm-late-gc-lowering.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,12 @@ State LateLowerGCFrame::LocalScan(Function &F) {
729729
if (CI->canReturnTwice()) {
730730
S.ReturnsTwice.push_back(CI);
731731
}
732+
if (auto callee = CI->getCalledFunction()) {
733+
// Known functions emitted in codegen that are not safepoints
734+
if (callee == pointer_from_objref_func || callee->getName() == "memcmp") {
735+
continue;
736+
}
737+
}
732738
int SafepointNumber = NoteSafepoint(S, BBS, CI);
733739
BBS.HasSafepoint = true;
734740
BBS.TopmostSafepoint = SafepointNumber;

test/codegen.jl

+34-1
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,37 @@ if opt_level > 0
101101
test_jl_dump_compiles_toplevel_thunks()
102102
end
103103

104-
@test !contains(get_llvm(isequal, Tuple{Nullable{BigFloat}, Nullable{BigFloat}}), "%gcframe")
104+
# Make sure we will not elide the allocation
105+
@noinline create_ref1() = Ref(1)
106+
function pointer_not_safepoint()
107+
a = create_ref1()
108+
unsafe_store!(Ptr{Int}(pointer_from_objref(a)), 3)
109+
return a[]
110+
end
111+
@test pointer_not_safepoint() == 3
112+
113+
# The current memcmp threshold is 512bytes, make sure this struct has the same size on
114+
# 32bits and 64bits
115+
struct LargeStruct
116+
x::NTuple{1024,Int8}
117+
LargeStruct() = new()
118+
end
119+
120+
const large_struct = LargeStruct()
121+
@noinline create_ref_struct() = Ref(large_struct)
122+
function compare_large_struct(a)
123+
b = create_ref_struct()
124+
if a[] === b[]
125+
b[].x[1]
126+
else
127+
a[].x[2]
128+
end
129+
end
130+
131+
if opt_level > 0
132+
@test !contains(get_llvm(isequal, Tuple{Nullable{BigFloat}, Nullable{BigFloat}}), "%gcframe")
133+
@test !contains(get_llvm(pointer_not_safepoint, Tuple{}), "%gcframe")
134+
compare_large_struct_ir = get_llvm(compare_large_struct, Tuple{typeof(create_ref_struct())})
135+
@test contains(compare_large_struct_ir, "call i32 @memcmp")
136+
@test !contains(compare_large_struct_ir, "%gcframe")
137+
end

0 commit comments

Comments
 (0)