Skip to content

Commit b11258a

Browse files
vtjnashKristofferC
authored andcommitted
codegen: add handling for undefined phinode values (#45155)
The optimization pass often uses values for phi values (and thus by extension, also for pi, phic and upsilon values) that are invalid. We make sure that these have a null pointer, so that we can detect that case at runtime (at the cost of slightly worse code generation for them), but it means we need to be very careful to check for that. This is identical to #39747, which added the equivalent code to the other side of the conditional there, but missed some additional relevant, but rare, cases that are observed to be possible. The `emit_isa_and_defined` is derived from the LLVM name for this operation: `isa_and_nonnull<T>`. Secondly, we also optimize `emit_unionmove` to change a bad IR case to a better IR form. Fix #44501 (cherry picked from commit 72b80e2)
1 parent 293b513 commit b11258a

File tree

3 files changed

+82
-69
lines changed

3 files changed

+82
-69
lines changed

src/cgutils.cpp

Lines changed: 62 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ static bool is_uniontype_allunboxed(jl_value_t *typ)
761761
return for_each_uniontype_small([&](unsigned, jl_datatype_t*) {}, typ, counter);
762762
}
763763

764-
static Value *emit_typeof_boxed(jl_codectx_t &ctx, const jl_cgval_t &p);
764+
static Value *emit_typeof_boxed(jl_codectx_t &ctx, const jl_cgval_t &p, bool maybenull=false);
765765

766766
static unsigned get_box_tindex(jl_datatype_t *jt, jl_value_t *ut)
767767
{
@@ -814,15 +814,9 @@ static LoadInst *emit_nthptr_recast(jl_codectx_t &ctx, Value *v, ssize_t n, MDNo
814814
}
815815

816816
static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &v);
817+
static Value *emit_typeof(jl_codectx_t &ctx, Value *v, bool maybenull);
817818

818-
// Returns ctx.types().T_prjlvalue
819-
static Value *emit_typeof(jl_codectx_t &ctx, Value *tt)
820-
{
821-
assert(tt != NULL && !isa<AllocaInst>(tt) && "expected a conditionally boxed value");
822-
return ctx.builder.CreateCall(prepare_call(jl_typeof_func), {tt});
823-
}
824-
825-
static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p)
819+
static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p, bool maybenull)
826820
{
827821
// given p, compute its type
828822
if (p.constant)
@@ -835,7 +829,7 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p)
835829
return mark_julia_const(ctx, jl_typeof(tp));
836830
}
837831
}
838-
return mark_julia_type(ctx, emit_typeof(ctx, p.V), true, jl_datatype_type);
832+
return mark_julia_type(ctx, emit_typeof(ctx, p.V, maybenull), true, jl_datatype_type);
839833
}
840834
if (p.TIndex) {
841835
Value *tindex = ctx.builder.CreateAnd(p.TIndex, ConstantInt::get(getInt8Ty(ctx.builder.getContext()), 0x7f));
@@ -870,7 +864,7 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p)
870864
BasicBlock *mergeBB = BasicBlock::Create(ctx.builder.getContext(), "merge", ctx.f);
871865
ctx.builder.CreateCondBr(isnull, boxBB, unboxBB);
872866
ctx.builder.SetInsertPoint(boxBB);
873-
auto boxTy = emit_typeof(ctx, p.Vboxed);
867+
auto boxTy = emit_typeof(ctx, p.Vboxed, maybenull);
874868
ctx.builder.CreateBr(mergeBB);
875869
boxBB = ctx.builder.GetInsertBlock(); // could have changed
876870
ctx.builder.SetInsertPoint(unboxBB);
@@ -892,9 +886,9 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p)
892886
}
893887

894888
// Returns ctx.types().T_prjlvalue
895-
static Value *emit_typeof_boxed(jl_codectx_t &ctx, const jl_cgval_t &p)
889+
static Value *emit_typeof_boxed(jl_codectx_t &ctx, const jl_cgval_t &p, bool maybenull)
896890
{
897-
return boxed(ctx, emit_typeof(ctx, p));
891+
return boxed(ctx, emit_typeof(ctx, p, maybenull));
898892
}
899893

900894
static Value *emit_datatype_types(jl_codectx_t &ctx, Value *dt)
@@ -1129,6 +1123,23 @@ static Value *emit_nullcheck_guard2(jl_codectx_t &ctx, Value *nullcheck1,
11291123
});
11301124
}
11311125

1126+
// Returns typeof(v), or null if v is a null pointer at run time and maybenull is true.
1127+
// This is used when the value might have come from an undefined value (a PhiNode),
1128+
// yet we try to read its type to compute a union index when moving the value (a PiNode).
1129+
// Returns a ctx.types().T_prjlvalue typed Value
1130+
static Value *emit_typeof(jl_codectx_t &ctx, Value *v, bool maybenull)
1131+
{
1132+
assert(v != NULL && !isa<AllocaInst>(v) && "expected a conditionally boxed value");
1133+
Function *typeof = prepare_call(jl_typeof_func);
1134+
if (maybenull)
1135+
return emit_guarded_test(ctx, null_pointer_cmp(ctx, v), Constant::getNullValue(typeof->getReturnType()), [&] {
1136+
// e.g. emit_typeof(ctx, v)
1137+
return ctx.builder.CreateCall(typeof, {v});
1138+
});
1139+
return ctx.builder.CreateCall(typeof, {v});
1140+
}
1141+
1142+
11321143
static void emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, const std::string &msg)
11331144
{
11341145
Value *msg_val = stringConstPtr(ctx.emission_context, ctx.builder, msg);
@@ -1256,7 +1267,7 @@ static std::pair<Value*, bool> emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x,
12561267
BasicBlock *postBB = BasicBlock::Create(ctx.builder.getContext(), "post_isa", ctx.f);
12571268
ctx.builder.CreateCondBr(isboxed, isaBB, postBB);
12581269
ctx.builder.SetInsertPoint(isaBB);
1259-
Value *istype_boxed = ctx.builder.CreateICmpEQ(emit_typeof(ctx, x.Vboxed),
1270+
Value *istype_boxed = ctx.builder.CreateICmpEQ(emit_typeof(ctx, x.Vboxed, false),
12601271
track_pjlvalue(ctx, literal_pointer_val(ctx, intersected_type)));
12611272
ctx.builder.CreateBr(postBB);
12621273
isaBB = ctx.builder.GetInsertBlock(); // could have changed
@@ -1312,6 +1323,20 @@ static std::pair<Value*, bool> emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x,
13121323
ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 0)), false);
13131324
}
13141325

1326+
// If this might have been sourced from a PhiNode object, it is possible our
1327+
// Vboxed pointer itself is null (undef) at runtime even if we thought we should
1328+
// know exactly the type of the bytes that should have been inside.
1329+
//
1330+
// n.b. It is also possible the value is a ghost of some sort, and we will
1331+
// declare that the pointer is legal (for zero bytes) even though it might be undef.
1332+
static Value *emit_isa_and_defined(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *typ)
1333+
{
1334+
return emit_nullcheck_guard(ctx, val.ispointer() ? val.V : nullptr, [&] {
1335+
return emit_isa(ctx, val, typ, nullptr).first;
1336+
});
1337+
}
1338+
1339+
13151340
static void emit_typecheck(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *type, const std::string &msg)
13161341
{
13171342
Value *istype;
@@ -2885,42 +2910,16 @@ static Value *compute_box_tindex(jl_codectx_t &ctx, Value *datatype, jl_value_t
28852910
return tindex;
28862911
}
28872912

2888-
// Returns typeof(v), or null if v is a null pointer at run time.
2889-
// This is used when the value might have come from an undefined variable,
2890-
// yet we try to read its type to compute a union index when moving the value.
2891-
static Value *emit_typeof_or_null(jl_codectx_t &ctx, Value *v)
2892-
{
2893-
BasicBlock *nonnull = BasicBlock::Create(ctx.builder.getContext(), "nonnull", ctx.f);
2894-
BasicBlock *postBB = BasicBlock::Create(ctx.builder.getContext(), "postnull", ctx.f);
2895-
Value *isnull = ctx.builder.CreateICmpEQ(v, Constant::getNullValue(v->getType()));
2896-
ctx.builder.CreateCondBr(isnull, postBB, nonnull);
2897-
BasicBlock *entry = ctx.builder.GetInsertBlock();
2898-
ctx.builder.SetInsertPoint(nonnull);
2899-
Value *typof = emit_typeof(ctx, v);
2900-
ctx.builder.CreateBr(postBB);
2901-
nonnull = ctx.builder.GetInsertBlock(); // could have changed
2902-
ctx.builder.SetInsertPoint(postBB);
2903-
PHINode *ti = ctx.builder.CreatePHI(typof->getType(), 2);
2904-
ti->addIncoming(Constant::getNullValue(typof->getType()), entry);
2905-
ti->addIncoming(typof, nonnull);
2906-
return ti;
2907-
}
2908-
29092913
// get the runtime tindex value, assuming val is already converted to type typ if it has a TIndex
2910-
static Value *compute_tindex_unboxed(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *typ)
2914+
static Value *compute_tindex_unboxed(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *typ, bool maybenull=false)
29112915
{
29122916
if (val.typ == jl_bottom_type)
29132917
return UndefValue::get(getInt8Ty(ctx.builder.getContext()));
29142918
if (val.constant)
29152919
return ConstantInt::get(getInt8Ty(ctx.builder.getContext()), get_box_tindex((jl_datatype_t*)jl_typeof(val.constant), typ));
2916-
29172920
if (val.TIndex)
29182921
return ctx.builder.CreateAnd(val.TIndex, ConstantInt::get(getInt8Ty(ctx.builder.getContext()), 0x7f));
2919-
Value *typof;
2920-
if (val.isboxed && !jl_is_concrete_type(val.typ) && !jl_is_type_type(val.typ))
2921-
typof = emit_typeof_or_null(ctx, val.V);
2922-
else
2923-
typof = emit_typeof_boxed(ctx, val);
2922+
Value *typof = emit_typeof_boxed(ctx, val, maybenull);
29242923
return compute_box_tindex(ctx, typof, val.typ, typ);
29252924
}
29262925

@@ -3102,14 +3101,17 @@ static void emit_unionmove(jl_codectx_t &ctx, Value *dest, MDNode *tbaa_dst, con
31023101
Value *src_ptr = data_pointer(ctx, src);
31033102
unsigned nb = jl_datatype_size(typ);
31043103
unsigned alignment = julia_alignment(typ);
3105-
Value *nbytes = ConstantInt::get(getSizeTy(ctx.builder.getContext()), nb);
3106-
if (skip) {
3107-
// TODO: this Select is very bad for performance, but is necessary to work around LLVM bugs with the undef option that we want to use:
3108-
// select copy dest -> dest to simulate an undef value / conditional copy
3109-
// src_ptr = ctx.builder.CreateSelect(skip, dest, src_ptr);
3110-
nbytes = ctx.builder.CreateSelect(skip, Constant::getNullValue(getSizeTy(ctx.builder.getContext())), nbytes);
3111-
}
3112-
emit_memcpy(ctx, dest, tbaa_dst, src_ptr, src.tbaa, nbytes, alignment, isVolatile);
3104+
// TODO: this branch may be bad for performance, but is necessary to work around LLVM bugs with the undef option that we want to use:
3105+
// select copy dest -> dest to simulate an undef value / conditional copy
3106+
// if (skip) src_ptr = ctx.builder.CreateSelect(skip, dest, src_ptr);
3107+
auto f = [&] {
3108+
(void)emit_memcpy(ctx, dest, tbaa_dst, src_ptr, src.tbaa, nb, alignment, isVolatile);
3109+
return nullptr;
3110+
};
3111+
if (skip)
3112+
emit_guarded_test(ctx, skip, nullptr, f);
3113+
else
3114+
f();
31133115
}
31143116
}
31153117
}
@@ -3162,12 +3164,16 @@ static void emit_unionmove(jl_codectx_t &ctx, Value *dest, MDNode *tbaa_dst, con
31623164
}
31633165
else {
31643166
assert(src.isboxed && "expected boxed value for sizeof/alignment computation");
3165-
Value *datatype = emit_typeof_boxed(ctx, src);
3166-
Value *copy_bytes = emit_datatype_size(ctx, datatype);
3167-
if (skip) {
3168-
copy_bytes = ctx.builder.CreateSelect(skip, ConstantInt::get(copy_bytes->getType(), 0), copy_bytes);
3169-
}
3170-
emit_memcpy(ctx, dest, tbaa_dst, src, copy_bytes, /*TODO: min-align*/1, isVolatile);
3167+
auto f = [&] {
3168+
Value *datatype = emit_typeof_boxed(ctx, src);
3169+
Value *copy_bytes = emit_datatype_size(ctx, datatype);
3170+
emit_memcpy(ctx, dest, tbaa_dst, src, copy_bytes, /*TODO: min-align*/1, isVolatile);
3171+
return nullptr;
3172+
};
3173+
if (skip)
3174+
emit_guarded_test(ctx, skip, nullptr, f);
3175+
else
3176+
f();
31713177
}
31723178
}
31733179

src/codegen.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,7 +1743,7 @@ static jl_cgval_t convert_julia_type_union(jl_codectx_t &ctx, const jl_cgval_t &
17431743
if (!union_isaBB) {
17441744
union_isaBB = BasicBlock::Create(ctx.builder.getContext(), "union_isa", ctx.f);
17451745
ctx.builder.SetInsertPoint(union_isaBB);
1746-
union_box_dt = emit_typeof_or_null(ctx, v.Vboxed);
1746+
union_box_dt = emit_typeof(ctx, v.Vboxed, skip != NULL);
17471747
post_union_isaBB = ctx.builder.GetInsertBlock();
17481748
}
17491749
};
@@ -1842,22 +1842,27 @@ static jl_cgval_t convert_julia_type(jl_codectx_t &ctx, const jl_cgval_t &v, jl_
18421842
return ghostValue(ctx, typ);
18431843
Value *new_tindex = NULL;
18441844
if (jl_is_concrete_type(typ)) {
1845-
assert(skip == nullptr && "skip only valid for union type return");
18461845
if (v.TIndex && !jl_is_pointerfree(typ)) {
18471846
// discovered that this union-split type must actually be isboxed
18481847
if (v.Vboxed) {
18491848
return jl_cgval_t(v.Vboxed, nullptr, true, typ, NULL, ctx.tbaa());
18501849
}
18511850
else {
18521851
// type mismatch: there weren't any boxed values in the union
1853-
CreateTrap(ctx.builder);
1852+
if (skip)
1853+
*skip = ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 1);
1854+
else
1855+
CreateTrap(ctx.builder);
18541856
return jl_cgval_t(ctx.builder.getContext());
18551857
}
18561858
}
18571859
if (jl_is_concrete_type(v.typ) && !jl_is_kind(v.typ)) {
18581860
if (jl_is_concrete_type(typ) && !jl_is_kind(typ)) {
18591861
// type mismatch: changing from one leaftype to another
1860-
CreateTrap(ctx.builder);
1862+
if (skip)
1863+
*skip = ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 1);
1864+
else
1865+
CreateTrap(ctx.builder);
18611866
return jl_cgval_t(ctx.builder.getContext());
18621867
}
18631868
}
@@ -2802,7 +2807,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
28022807
}
28032808

28042809
else if (f == jl_builtin_typeof && nargs == 1) {
2805-
*ret = emit_typeof(ctx, argv[1]);
2810+
*ret = emit_typeof(ctx, argv[1], false);
28062811
return true;
28072812
}
28082813

@@ -3944,7 +3949,7 @@ static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i)
39443949
ctx.spvals_ptr,
39453950
i + sizeof(jl_svec_t) / sizeof(jl_value_t*));
39463951
Value *sp = tbaa_decorate(ctx.tbaa().tbaa_const, ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*))));
3947-
Value *isnull = ctx.builder.CreateICmpNE(emit_typeof(ctx, sp),
3952+
Value *isnull = ctx.builder.CreateICmpNE(emit_typeof(ctx, sp, false),
39483953
track_pjlvalue(ctx, literal_pointer_val(ctx, (jl_value_t*)jl_tvar_type)));
39493954
jl_unionall_t *sparam = (jl_unionall_t*)ctx.linfo->def.method->sig;
39503955
for (size_t j = 0; j < i; j++) {
@@ -4018,7 +4023,7 @@ static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym)
40184023
ctx.spvals_ptr,
40194024
i + sizeof(jl_svec_t) / sizeof(jl_value_t*));
40204025
Value *sp = tbaa_decorate(ctx.tbaa().tbaa_const, ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*))));
4021-
isnull = ctx.builder.CreateICmpNE(emit_typeof(ctx, sp),
4026+
isnull = ctx.builder.CreateICmpNE(emit_typeof(ctx, sp, false),
40224027
track_pjlvalue(ctx, literal_pointer_val(ctx, (jl_value_t*)jl_tvar_type)));
40234028
}
40244029
else {
@@ -4191,7 +4196,7 @@ static void emit_vi_assignment_unboxed(jl_codectx_t &ctx, jl_varinfo_t &vi, Valu
41914196
}
41924197
}
41934198
else {
4194-
emit_unionmove(ctx, vi.value.V, ctx.tbaa().tbaa_stack, rval_info, isboxed, vi.isVolatile);
4199+
emit_unionmove(ctx, vi.value.V, ctx.tbaa().tbaa_stack, rval_info, /*skip*/isboxed, vi.isVolatile);
41954200
}
41964201
}
41974202
}
@@ -4655,7 +4660,8 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval)
46554660
jl_error("GotoIfNot in value position");
46564661
}
46574662
if (jl_is_pinode(expr)) {
4658-
return convert_julia_type(ctx, emit_expr(ctx, jl_fieldref_noalloc(expr, 0)), jl_fieldref_noalloc(expr, 1));
4663+
Value *skip = NULL;
4664+
return convert_julia_type(ctx, emit_expr(ctx, jl_fieldref_noalloc(expr, 0)), jl_fieldref_noalloc(expr, 1), &skip);
46594665
}
46604666
if (!jl_is_expr(expr)) {
46614667
int needroot = true;
@@ -7504,7 +7510,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
75047510
else {
75057511
// must be careful to emit undef here (rather than a bitcast or
75067512
// load of val) if the runtime type of val isn't phiType
7507-
Value *isvalid = emit_isa(ctx, val, phiType, NULL).first;
7513+
Value *isvalid = emit_isa_and_defined(ctx, val, phiType);
75087514
V = emit_guarded_test(ctx, isvalid, undef_value_for_type(VN->getType()), [&] {
75097515
return emit_unbox(ctx, VN->getType(), val, phiType);
75107516
});
@@ -7516,7 +7522,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
75167522
// must be careful to emit undef here (rather than a bitcast or
75177523
// load of val) if the runtime type of val isn't phiType
75187524
assert(lty != ctx.types().T_prjlvalue);
7519-
Value *isvalid = emit_isa(ctx, val, phiType, NULL).first;
7525+
Value *isvalid = emit_isa_and_defined(ctx, val, phiType);
75207526
emit_guarded_test(ctx, isvalid, nullptr, [&] {
75217527
(void)emit_unbox(ctx, lty, val, phiType, maybe_decay_tracked(ctx, dest), ctx.tbaa().tbaa_stack);
75227528
return nullptr;
@@ -7558,7 +7564,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
75587564
RTindex = new_union.TIndex;
75597565
if (!RTindex) {
75607566
assert(new_union.isboxed && new_union.Vboxed && "convert_julia_type failed");
7561-
RTindex = compute_tindex_unboxed(ctx, new_union, phiType);
7567+
RTindex = compute_tindex_unboxed(ctx, new_union, phiType, true);
75627568
if (dest) {
75637569
// If dest is not set, this is a ghost union, the recipient of which
75647570
// is often not prepared to handle a boxed representation of the ghost.

src/llvm-late-gc-lowering.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1065,8 +1065,9 @@ void RecursivelyVisit(callback f, Value *V) {
10651065
if (isa<VisitInst>(TheUser))
10661066
f(VU);
10671067
if (isa<CallInst>(TheUser) || isa<LoadInst>(TheUser) ||
1068-
isa<SelectInst>(TheUser) || isa<PHINode>(TheUser) ||
1068+
isa<SelectInst>(TheUser) || isa<PHINode>(TheUser) || // TODO: should these be removed from this list?
10691069
isa<StoreInst>(TheUser) || isa<PtrToIntInst>(TheUser) ||
1070+
isa<ICmpInst>(TheUser) || // ICmpEQ/ICmpNE can be used with ptr types
10701071
isa<AtomicCmpXchgInst>(TheUser) || isa<AtomicRMWInst>(TheUser))
10711072
continue;
10721073
if (isa<GetElementPtrInst>(TheUser) || isa<BitCastInst>(TheUser) || isa<AddrSpaceCastInst>(TheUser)) {

0 commit comments

Comments
 (0)