From ad8589afb70aaad91625144078c4abb7aaa4bba5 Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Sat, 8 Jul 2017 05:59:10 -0400 Subject: [PATCH] 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 --- src/codegen.cpp | 16 +++++++++------- src/llvm-late-gc-lowering.cpp | 6 ++++++ test/codegen.jl | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 6a4eac92abf7e1..7538267f3d38fb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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; @@ -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), @@ -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); @@ -6352,7 +6354,7 @@ static void init_julia_llvm_env(Module *m) add_named_global(jlvboundserror_func, &jl_bounds_error_tuple_int); std::vector 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 = @@ -6379,13 +6381,13 @@ static void init_julia_llvm_env(Module *m) add_named_global(setjmp_func, &jl_setjmp_f); std::vector 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 te_args(0); te_args.push_back(T_pint8); diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index 25894cbf161f49..b44670a10a7e37 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -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; diff --git a/test/codegen.jl b/test/codegen.jl index 606fe89c6ce066..da80ff1661f039 100644 --- a/test/codegen.jl +++ b/test/codegen.jl @@ -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