Skip to content

Commit

Permalink
Add a white list of known non-safepoint functions
Browse files Browse the repository at this point in the history
These are functions we emit in codegen directly that are known to not contain any safepoint
  • Loading branch information
yuyichao committed Jul 8, 2017
1 parent 0c9a858 commit ad8589a
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 8 deletions.
16 changes: 9 additions & 7 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ static Function *jlisa_func;
static Function *jlsubtype_func;
static Function *jlapplytype_func;
static Function *setjmp_func;
static Function *memcmp_func;
static Function *memcmp_derived_func;
static Function *box_int8_func;
static Function *box_uint8_func;
static Function *box_int16_func;
Expand Down Expand Up @@ -2280,7 +2280,7 @@ static Value *emit_bits_compare(jl_codectx_t &ctx, const jl_cgval_t &arg1, const
assert(arg1.ispointer() && arg2.ispointer());
size_t sz = jl_datatype_size(arg1.typ);
if (sz > 512 && !((jl_datatype_t*)arg1.typ)->layout->haspadding) {
Value *answer = ctx.builder.CreateCall(prepare_call(memcmp_func),
Value *answer = ctx.builder.CreateCall(prepare_call(memcmp_derived_func),
{
data_pointer(ctx, arg1, T_pint8),
data_pointer(ctx, arg2, T_pint8),
Expand Down Expand Up @@ -6138,6 +6138,8 @@ static void init_julia_llvm_env(Module *m)
T_void = Type::getVoidTy(jl_LLVMContext);
T_pvoidfunc = FunctionType::get(T_void, /*isVarArg*/false)->getPointerTo();

auto T_pint8_derived = PointerType::get(T_int8, AddressSpace::Derived);

// This type is used to create undef Values for use in struct declarations to skip indices
NoopType = ArrayType::get(T_int1, 0);

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

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

std::vector<Type*> args_memcmp(0);
args_memcmp.push_back(T_pint8);
args_memcmp.push_back(T_pint8);
args_memcmp.push_back(T_pint8_derived);
args_memcmp.push_back(T_pint8_derived);
args_memcmp.push_back(T_size);
memcmp_func =
memcmp_derived_func =
Function::Create(FunctionType::get(T_int32, args_memcmp, false),
Function::ExternalLinkage, "memcmp", m);
add_named_global(memcmp_func, &memcmp);
add_named_global(memcmp_derived_func, &memcmp);

std::vector<Type*> te_args(0);
te_args.push_back(T_pint8);
Expand Down
6 changes: 6 additions & 0 deletions src/llvm-late-gc-lowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,12 @@ State LateLowerGCFrame::LocalScan(Function &F) {
if (CI->canReturnTwice()) {
S.ReturnsTwice.push_back(CI);
}
if (auto callee = CI->getCalledFunction()) {
// Known functions emitted in codegen that are not safepoints
if (callee == pointer_from_objref_func || callee->getName() == "memcmp") {
continue;
}
}
int SafepointNumber = NoteSafepoint(S, BBS, CI);
BBS.HasSafepoint = true;
BBS.TopmostSafepoint = SafepointNumber;
Expand Down
35 changes: 34 additions & 1 deletion test/codegen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,37 @@ if opt_level > 0
test_jl_dump_compiles_toplevel_thunks()
end

@test !contains(get_llvm(isequal, Tuple{Nullable{BigFloat}, Nullable{BigFloat}}), "%gcframe")
# Make sure we will not elide the allocation
@noinline create_ref1() = Ref(1)
function pointer_not_safepoint()
a = create_ref1()
unsafe_store!(Ptr{Int}(pointer_from_objref(a)), 3)
return a[]
end
@test pointer_not_safepoint() == 3

# The current memcmp threshold is 512bytes, make sure this struct has the same size on
# 32bits and 64bits
struct LargeStruct
x::NTuple{1024,Int8}
LargeStruct() = new()
end

const large_struct = LargeStruct()
@noinline create_ref_struct() = Ref(large_struct)
function compare_large_struct(a)
b = create_ref_struct()
if a[] === b[]
b[].x[1]
else
a[].x[2]
end
end

if opt_level > 0
@test !contains(get_llvm(isequal, Tuple{Nullable{BigFloat}, Nullable{BigFloat}}), "%gcframe")
@test !contains(get_llvm(pointer_not_safepoint, Tuple{}), "%gcframe")
compare_large_struct_ir = get_llvm(compare_large_struct, Tuple{typeof(create_ref_struct())})
@test contains(compare_large_struct_ir, "call i32 @memcmp")
@test !contains(compare_large_struct_ir, "%gcframe")
end

0 comments on commit ad8589a

Please sign in to comment.