Skip to content

Commit 11d3c96

Browse files
authored
Merge pull request #18732 from JuliaLang/ob/udvopt
Avoid boxing variables that may be used undef
2 parents 3f20191 + 9231c93 commit 11d3c96

File tree

1 file changed

+73
-40
lines changed

1 file changed

+73
-40
lines changed

src/codegen.cpp

Lines changed: 73 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,9 @@ struct jl_varinfo_t {
490490
#else
491491
DIVariable dinfo;
492492
#endif
493+
// if the variable might be used undefined and is not boxed
494+
// this i1 flag is true when it is defined
495+
Value *defFlag;
493496
bool isSA;
494497
bool isVolatile;
495498
bool isArgument;
@@ -503,6 +506,7 @@ struct jl_varinfo_t {
503506
#else
504507
dinfo(DIVariable()),
505508
#endif
509+
defFlag(NULL),
506510
isSA(false),
507511
isVolatile(false), isArgument(false),
508512
escapes(true), usedUndef(false), used(false)
@@ -727,7 +731,7 @@ static bool store_unboxed_p(int s, jl_codectx_t *ctx)
727731
jl_varinfo_t &vi = ctx->slots[s];
728732
// only store a variable unboxed if type inference has run, which
729733
// checks that the variable is not referenced undefined.
730-
return (ctx->source->inferred && !vi.usedUndef &&
734+
return (ctx->source->inferred &&
731735
// don't unbox vararg tuples
732736
s != ctx->vaSlot && store_unboxed_p(vi.value.typ));
733737
}
@@ -737,6 +741,22 @@ static jl_sym_t *slot_symbol(int s, jl_codectx_t *ctx)
737741
return (jl_sym_t*)jl_array_ptr_ref(ctx->source->slotnames, s);
738742
}
739743

744+
static void store_def_flag(const jl_varinfo_t &vi, bool val)
745+
{
746+
assert(!vi.memloc); // undefinedness is null pointer for boxed things
747+
assert(vi.usedUndef && vi.defFlag);
748+
builder.CreateStore(ConstantInt::get(T_int1, val), vi.defFlag);
749+
}
750+
751+
static void alloc_def_flag(jl_varinfo_t& vi, jl_codectx_t* ctx)
752+
{
753+
assert(!vi.memloc); // same as above, not used for pointers
754+
if (vi.usedUndef) {
755+
vi.defFlag = emit_static_alloca(T_int1, ctx);
756+
store_def_flag(vi, false);
757+
}
758+
}
759+
740760
static Value *alloc_local(int s, jl_codectx_t *ctx)
741761
{
742762
jl_varinfo_t &vi = ctx->slots[s];
@@ -753,6 +773,7 @@ static Value *alloc_local(int s, jl_codectx_t *ctx)
753773
vi.value = mark_julia_slot(lv, jt, tbaa_stack);
754774
// slot is not immutable if there are multiple assignments
755775
vi.value.isimmutable &= (vi.isSA && s >= ctx->nargs);
776+
alloc_def_flag(vi, ctx);
756777
assert(vi.value.isboxed == false);
757778
return lv;
758779
}
@@ -2974,9 +2995,8 @@ static jl_cgval_t emit_call(jl_expr_t *ex, jl_codectx_t *ctx)
29742995

29752996
// --- accessing and assigning variables ---
29762997

2977-
static void undef_var_error_if_null(Value *v, jl_sym_t *name, jl_codectx_t *ctx)
2998+
static void undef_var_error_ifnot(Value *ok, jl_sym_t *name, jl_codectx_t *ctx)
29782999
{
2979-
Value *ok = builder.CreateICmpNE(v, V_null);
29803000
BasicBlock *err = BasicBlock::Create(jl_LLVMContext, "err", ctx->f);
29813001
BasicBlock *ifok = BasicBlock::Create(jl_LLVMContext, "ok");
29823002
builder.CreateCondBr(ok, ifok, err);
@@ -3045,7 +3065,7 @@ static jl_cgval_t emit_checked_var(Value *bp, jl_sym_t *name, jl_codectx_t *ctx,
30453065
Instruction *v = builder.CreateLoad(bp, isvol);
30463066
if (tbaa)
30473067
tbaa_decorate(tbaa, v);
3048-
undef_var_error_if_null(v, name, ctx);
3068+
undef_var_error_ifnot(builder.CreateICmpNE(v, V_null), name, ctx);
30493069
return mark_julia_type(v, true, jl_any_type, ctx);
30503070
}
30513071

@@ -3110,14 +3130,20 @@ static jl_cgval_t emit_local(jl_value_t *slotload, jl_codectx_t *ctx)
31103130
return v;
31113131
}
31123132
}
3113-
else if (!vi.isVolatile || vi.isArgument) {
3114-
return vi.value;
3115-
}
31163133
else {
3117-
// copy value to a non-mutable location
3118-
Type *T = julia_type_to_llvm(vi.value.typ)->getPointerTo();
3119-
Value *v = data_pointer(vi.value, ctx, T);
3120-
return mark_julia_type(builder.CreateLoad(v, vi.isVolatile), false, vi.value.typ, ctx);
3134+
if (vi.usedUndef) {
3135+
assert(vi.defFlag);
3136+
undef_var_error_ifnot(builder.CreateLoad(vi.defFlag), sym, ctx);
3137+
}
3138+
if (!vi.isVolatile || vi.isArgument) {
3139+
return vi.value;
3140+
}
3141+
else {
3142+
// copy value to a non-mutable location
3143+
Type *T = julia_type_to_llvm(vi.value.typ)->getPointerTo();
3144+
Value *v = data_pointer(vi.value, ctx, T);
3145+
return mark_julia_type(builder.CreateLoad(v, vi.isVolatile), false, vi.value.typ, ctx);
3146+
}
31213147
}
31223148
}
31233149

@@ -3203,13 +3229,18 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx)
32033229
Value *rval = boxed(rval_info, ctx, false); // no root needed on the temporary since it is about to be assigned to the variable slot
32043230
builder.CreateStore(rval, vi.memloc, vi.isVolatile);
32053231
}
3206-
else if (vi.value.constant) {
3207-
// virtual store
3208-
}
32093232
else {
3210-
// store unboxed
3211-
assert(vi.value.ispointer());
3212-
emit_unbox(julia_type_to_llvm(vi.value.typ), rval_info, vi.value.typ, vi.value.V, vi.isVolatile);
3233+
if (vi.usedUndef)
3234+
store_def_flag(vi, true);
3235+
3236+
if (vi.value.constant) {
3237+
// virtual store
3238+
}
3239+
else {
3240+
// store unboxed
3241+
assert(vi.value.ispointer());
3242+
emit_unbox(julia_type_to_llvm(vi.value.typ), rval_info, vi.value.typ, vi.value.V, vi.isVolatile);
3243+
}
32133244
}
32143245
}
32153246

@@ -3254,10 +3285,12 @@ static void emit_stmtpos(jl_value_t *expr, jl_codectx_t *ctx)
32543285
assert(jl_is_slot(var));
32553286
jl_varinfo_t &vi = ctx->slots[jl_slot_number(var)-1];
32563287
Value *lv = vi.memloc;
3257-
if (lv != NULL) {
3288+
if (vi.usedUndef) {
32583289
// create a new uninitialized variable
3259-
if (vi.usedUndef)
3290+
if (lv != NULL)
32603291
builder.CreateStore(V_null, lv);
3292+
else
3293+
store_def_flag(vi, false);
32613294
}
32623295
return;
32633296
}
@@ -4448,32 +4481,32 @@ static std::unique_ptr<Module> emit_function(jl_method_instance_t *lam, jl_code_
44484481
if (s == unused_sym) continue;
44494482
jl_varinfo_t &varinfo = ctx.slots[i];
44504483
assert(!varinfo.memloc); // variables shouldn't have memory locs already
4451-
if (!varinfo.usedUndef) {
4452-
if (varinfo.value.constant) {
4453-
// no need to explicitly load/store a constant/ghost value
4454-
continue;
4455-
}
4456-
else if (jl_is_type_type(varinfo.value.typ) && jl_is_leaf_type(jl_tparam0(varinfo.value.typ))) {
4457-
// replace T::Type{T} with T
4458-
varinfo.value = mark_julia_const(jl_tparam0(varinfo.value.typ));
4459-
continue;
4460-
}
4461-
else if (store_unboxed_p(i, &ctx)) {
4462-
if (!varinfo.isArgument) { // otherwise, just leave it in the input register
4463-
Value *lv = alloc_local(i, &ctx); (void)lv;
4484+
if (varinfo.value.constant) {
4485+
// no need to explicitly load/store a constant/ghost value
4486+
alloc_def_flag(varinfo, &ctx);
4487+
continue;
4488+
}
4489+
else if (jl_is_type_type(varinfo.value.typ) && jl_is_leaf_type(jl_tparam0(varinfo.value.typ))) {
4490+
// replace T::Type{T} with T
4491+
varinfo.value = mark_julia_const(jl_tparam0(varinfo.value.typ));
4492+
alloc_def_flag(varinfo, &ctx);
4493+
continue;
4494+
}
4495+
else if (store_unboxed_p(i, &ctx)) {
4496+
if (!varinfo.isArgument) { // otherwise, just leave it in the input register
4497+
Value *lv = alloc_local(i, &ctx); (void)lv;
44644498
#if JL_LLVM_VERSION >= 30600
4465-
if (ctx.debug_enabled && varinfo.dinfo) {
4466-
assert((Metadata*)varinfo.dinfo->getType() != jl_pvalue_dillvmt);
4467-
dbuilder.insertDeclare(lv, varinfo.dinfo, dbuilder.createExpression(),
4499+
if (ctx.debug_enabled && varinfo.dinfo) {
4500+
assert((Metadata*)varinfo.dinfo->getType() != jl_pvalue_dillvmt);
4501+
dbuilder.insertDeclare(lv, varinfo.dinfo, dbuilder.createExpression(),
44684502
#if JL_LLVM_VERSION >= 30700
4469-
topdebugloc,
4470-
#endif
4471-
builder.GetInsertBlock());
4472-
}
4503+
topdebugloc,
44734504
#endif
4505+
builder.GetInsertBlock());
44744506
}
4475-
continue;
4507+
#endif
44764508
}
4509+
continue;
44774510
}
44784511
if (!varinfo.isArgument || // always need a slot if the variable is assigned
44794512
specsig || // for arguments, give them stack slots if they aren't in `argArray` (otherwise, will use that pointer)

0 commit comments

Comments
 (0)