diff --git a/Compiler/test/codegen.jl b/Compiler/test/codegen.jl index 45db9e73d5a3f..3ff9790e29cf8 100644 --- a/Compiler/test/codegen.jl +++ b/Compiler/test/codegen.jl @@ -1033,3 +1033,7 @@ end const x57872 = "Hello" f57872() = (Core.isdefinedglobal(@__MODULE__, Base.compilerbarrier(:const, :x57872)), x57872) # Extra globalref here to force world age bounds @test f57872() == (true, "Hello") + +@noinline f_mutateany(@nospecialize x) = x[] = 1 +g_mutateany() = (y = Ref(0); f_mutateany(y); y[]) +@test g_mutateany() === 1 diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 5b6d3ab963e55..359aaf0772d49 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1479,6 +1479,7 @@ static Value *emit_sizeof(jl_codectx_t &ctx, const jl_cgval_t &p) return dyn_size; } } +*/ static Value *emit_datatype_mutabl(jl_codectx_t &ctx, Value *dt) { @@ -1493,7 +1494,6 @@ static Value *emit_datatype_mutabl(jl_codectx_t &ctx, Value *dt) mutabl = ctx.builder.CreateLShr(mutabl, 1); return ctx.builder.CreateTrunc(mutabl, getInt1Ty(ctx.builder.getContext())); } -*/ static Value *emit_datatype_isprimitivetype(jl_codectx_t &ctx, Value *typ) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 97f2b8b98f2db..28d3281584b85 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1600,7 +1600,7 @@ static MDNode *best_tbaa(jl_tbaacache_t &tbaa_cache, jl_value_t *jt) { // note that this includes jl_isbits, although codegen should work regardless static bool jl_is_concrete_immutable(jl_value_t* t) { - return jl_is_immutable_datatype(t) && ((jl_datatype_t*)t)->isconcretetype; + return jl_may_be_immutable_datatype(t) && ((jl_datatype_t*)t)->isconcretetype; } static bool jl_is_pointerfree(jl_value_t* t) @@ -7385,8 +7385,8 @@ static Function *gen_cfun_wrapper( inputarg = mark_julia_type(ctx, val, false, jargty); } } - else if (static_at || (!jl_is_typevar(jargty) && !jl_is_immutable_datatype(jargty))) { - // must be a jl_value_t* (because it's mutable or contains gc roots) + else if (static_at || (!jl_is_typevar(jargty) && (!jl_is_datatype(jargty) || jl_is_abstracttype(jargty) || jl_is_mutable_datatype(jargty)))) { + // must be a jl_value_t* (because it is mutable or abstract) inputarg = mark_julia_type(ctx, maybe_decay_untracked(ctx, val), true, jargty_proper); } else { @@ -7400,31 +7400,36 @@ static Function *gen_cfun_wrapper( emit_ptrgep(ctx, nestPtr, jl_array_nrows(*closure_types) * ctx.types().sizeof_ptr), Align(sizeof(void*))); BasicBlock *boxedBB = BasicBlock::Create(ctx.builder.getContext(), "isboxed", cw); - BasicBlock *loadBB = BasicBlock::Create(ctx.builder.getContext(), "need-load", cw); + BasicBlock *notanyBB = BasicBlock::Create(ctx.builder.getContext(), "not-any", cw); BasicBlock *unboxedBB = BasicBlock::Create(ctx.builder.getContext(), "maybe-unboxed", cw); BasicBlock *isanyBB = BasicBlock::Create(ctx.builder.getContext(), "any", cw); BasicBlock *afterBB = BasicBlock::Create(ctx.builder.getContext(), "after", cw); - Value *isrtboxed = ctx.builder.CreateIsNull(val); // XXX: this is the wrong condition and should be inspecting runtime_dt instead - ctx.builder.CreateCondBr(isrtboxed, boxedBB, loadBB); - ctx.builder.SetInsertPoint(boxedBB); - Value *p1 = val; - p1 = track_pjlvalue(ctx, p1); - ctx.builder.CreateBr(afterBB); - ctx.builder.SetInsertPoint(loadBB); Value *isrtany = ctx.builder.CreateICmpEQ( - literal_pointer_val(ctx, (jl_value_t*)jl_any_type), val); - ctx.builder.CreateCondBr(isrtany, isanyBB, unboxedBB); + track_pjlvalue(ctx,literal_pointer_val(ctx, (jl_value_t*)jl_any_type)), runtime_dt); + ctx.builder.CreateCondBr(isrtany, isanyBB, notanyBB); ctx.builder.SetInsertPoint(isanyBB); - Value *p2 = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, val, Align(sizeof(void*))); + Value *p1 = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, val, Align(sizeof(void*))); + ctx.builder.CreateBr(afterBB); + isanyBB = ctx.builder.GetInsertBlock(); // could have changed + ctx.builder.SetInsertPoint(notanyBB); + jl_cgval_t runtime_dt_val = mark_julia_type(ctx, runtime_dt, true, jl_any_type); + Value *isrtboxed = // (!jl_is_datatype(runtime_dt) || !jl_is_concrete_datatype(runtime_dt) || jl_is_mutable_datatype(runtime_dt)) + emit_guarded_test(ctx, emit_exactly_isa(ctx, runtime_dt_val, jl_datatype_type), true, [&] { + return ctx.builder.CreateOr(ctx.builder.CreateNot(emit_isconcrete(ctx, runtime_dt)), emit_datatype_mutabl(ctx, runtime_dt)); + }); + ctx.builder.CreateCondBr(isrtboxed, boxedBB, unboxedBB); + ctx.builder.SetInsertPoint(boxedBB); + Value *p2 = track_pjlvalue(ctx, val); ctx.builder.CreateBr(afterBB); + boxedBB = ctx.builder.GetInsertBlock(); // could have changed ctx.builder.SetInsertPoint(unboxedBB); Value *p3 = emit_new_bits(ctx, runtime_dt, val); unboxedBB = ctx.builder.GetInsertBlock(); // could have changed ctx.builder.CreateBr(afterBB); ctx.builder.SetInsertPoint(afterBB); PHINode *p = ctx.builder.CreatePHI(ctx.types().T_prjlvalue, 3); - p->addIncoming(p1, boxedBB); - p->addIncoming(p2, isanyBB); + p->addIncoming(p1, isanyBB); + p->addIncoming(p2, boxedBB); p->addIncoming(p3, unboxedBB); inputarg = mark_julia_type(ctx, p, true, jargty_proper); } @@ -7980,7 +7985,7 @@ static jl_returninfo_t get_specsig_function(jl_codegen_params_t ¶ms, Module param.addAttribute(Attribute::ReadOnly); ty = PointerType::get(M->getContext(), AddressSpace::Derived); } - else if (isboxed && jl_is_immutable_datatype(jt)) { + else if (isboxed && jl_may_be_immutable_datatype(jt) && !jl_is_abstracttype(jt)) { param.addAttribute(Attribute::ReadOnly); } else if (jl_is_primitivetype(jt) && ty->isIntegerTy()) { diff --git a/src/julia.h b/src/julia.h index 95241aa6f48a8..08ae5d6eaed62 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1617,7 +1617,7 @@ static inline int jl_field_isconst(jl_datatype_t *st, int i) JL_NOTSAFEPOINT #define jl_is_mutable(t) (((jl_datatype_t*)t)->name->mutabl) #define jl_is_mutable_datatype(t) (jl_is_datatype(t) && (((jl_datatype_t*)t)->name->mutabl)) #define jl_is_immutable(t) (!((jl_datatype_t*)t)->name->mutabl) -#define jl_is_immutable_datatype(t) (jl_is_datatype(t) && (!((jl_datatype_t*)t)->name->mutabl)) +#define jl_may_be_immutable_datatype(t) (jl_is_datatype(t) && (!((jl_datatype_t*)t)->name->mutabl)) #define jl_is_uniontype(v) jl_typetagis(v,jl_uniontype_tag<<4) #define jl_is_typevar(v) jl_typetagis(v,jl_tvar_tag<<4) #define jl_is_unionall(v) jl_typetagis(v,jl_unionall_tag<<4)