Skip to content

Commit 97d5d44

Browse files
committed
Support Arrays of Union isbits types
1 parent 2e0a048 commit 97d5d44

File tree

8 files changed

+515
-150
lines changed

8 files changed

+515
-150
lines changed

base/array.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ function isassigned(a::Array, i::Int...)
100100
ccall(:jl_array_isassigned, Cint, (Any, UInt), a, ii) == 1
101101
end
102102

103+
## Union isbits selector bytes
104+
function selectorbytes(a::Array{T, N}) where {T, N}
105+
(T isa Union && all(isbits.(Base.uniontypes(T)))) || return UInt8[]
106+
elsize = maximum(sizeof, Base.uniontypes(T))
107+
return unsafe_wrap(Array{UInt8, N}, convert(Ptr{UInt8}, pointer(a)) + length(a) * elsize, size(a))
108+
end
109+
103110
## copy ##
104111

105112
function unsafe_copy!(dest::Ptr{T}, src::Ptr{T}, n) where T

src/array.c

Lines changed: 153 additions & 40 deletions
Large diffs are not rendered by default.

src/ccall.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1795,7 +1795,7 @@ static jl_cgval_t emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
17951795
jl_value_t *aryty = expr_type(aryex, ctx);
17961796
if (jl_is_array_type(aryty)) {
17971797
jl_value_t *ety = jl_tparam0(aryty);
1798-
if (jl_isbits(ety)) {
1798+
if (jl_isbits(ety) || jl_array_store_unboxed(ety)) {
17991799
emit_expr(aryex, ctx);
18001800
emit_expr(idxex, ctx);
18011801
JL_GC_POP();

src/cgutils.cpp

Lines changed: 47 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -628,13 +628,13 @@ static unsigned get_box_tindex(jl_datatype_t *jt, jl_value_t *ut)
628628

629629
static Value *emit_nthptr_addr(Value *v, ssize_t n, bool gctracked = true)
630630
{
631-
return builder.CreateGEP(emit_bitcast(gctracked ? decay_derived(v) : v, T_pprjlvalue),
631+
return builder.CreateGEP(T_prjlvalue, emit_bitcast(gctracked ? decay_derived(v) : v, T_pprjlvalue),
632632
ConstantInt::get(T_size, n));
633633
}
634634

635635
static Value *emit_nthptr_addr(Value *v, Value *idx, bool gctracked = true)
636636
{
637-
return builder.CreateGEP(emit_bitcast(gctracked ? decay_derived(v) : v, T_pprjlvalue), idx);
637+
return builder.CreateGEP(T_prjlvalue, emit_bitcast(gctracked ? decay_derived(v) : v, T_pprjlvalue), idx);
638638
}
639639

640640
static Value *emit_nthptr(Value *v, ssize_t n, MDNode *tbaa)
@@ -750,7 +750,7 @@ static Value *emit_datatype_types(Value *dt)
750750
{
751751
return tbaa_decorate(tbaa_const, builder.
752752
CreateLoad(emit_bitcast(builder.
753-
CreateGEP(emit_bitcast(decay_derived(dt), T_pint8),
753+
CreateGEP(T_int8, emit_bitcast(decay_derived(dt), T_pint8),
754754
ConstantInt::get(T_size, offsetof(jl_datatype_t, types))),
755755
T_ppjlvalue)));
756756
}
@@ -760,7 +760,7 @@ static Value *emit_datatype_nfields(Value *dt)
760760
Value *nf = tbaa_decorate(tbaa_const, builder.CreateLoad(
761761
tbaa_decorate(tbaa_const, builder.CreateLoad(
762762
emit_bitcast(
763-
builder.CreateGEP(
763+
builder.CreateGEP(T_int8,
764764
emit_bitcast(decay_derived(dt), T_pint8),
765765
ConstantInt::get(T_size, offsetof(jl_datatype_t, types))),
766766
T_pint32->getPointerTo())))));
@@ -774,7 +774,7 @@ static Value *emit_datatype_size(Value *dt)
774774
{
775775
Value *size = tbaa_decorate(tbaa_const, builder.
776776
CreateLoad(emit_bitcast(builder.
777-
CreateGEP(emit_bitcast(decay_derived(dt), T_pint8),
777+
CreateGEP(T_int8, emit_bitcast(decay_derived(dt), T_pint8),
778778
ConstantInt::get(T_size, offsetof(jl_datatype_t, size))),
779779
T_pint32)));
780780
return size;
@@ -832,15 +832,15 @@ static Value *emit_sizeof(const jl_cgval_t &p, jl_codectx_t *ctx)
832832
static Value *emit_datatype_mutabl(Value *dt)
833833
{
834834
Value *mutabl = tbaa_decorate(tbaa_const, builder.
835-
CreateLoad(builder.CreateGEP(emit_bitcast(decay_derived(dt), T_pint8),
835+
CreateLoad(builder.CreateGEP(T_int8, emit_bitcast(decay_derived(dt), T_pint8),
836836
ConstantInt::get(T_size, offsetof(jl_datatype_t, mutabl)))));
837837
return builder.CreateTrunc(mutabl, T_int1);
838838
}
839839

840840
static Value *emit_datatype_abstract(Value *dt)
841841
{
842842
Value *abstract = tbaa_decorate(tbaa_const, builder.
843-
CreateLoad(builder.CreateGEP(emit_bitcast(decay_derived(dt), T_pint8),
843+
CreateLoad(builder.CreateGEP(T_int8, emit_bitcast(decay_derived(dt), T_pint8),
844844
ConstantInt::get(T_size, offsetof(jl_datatype_t, abstract)))));
845845
return builder.CreateTrunc(abstract, T_int1);
846846
}
@@ -1141,35 +1141,6 @@ static Value *emit_bounds_check(const jl_cgval_t &ainfo, jl_value_t *ty, Value *
11411141
return im1;
11421142
}
11431143

1144-
// --- loading and storing ---
1145-
1146-
static Value *compute_box_tindex(Value *datatype, jl_value_t *supertype, jl_value_t *ut, jl_codectx_t *ctx)
1147-
{
1148-
Value *tindex = ConstantInt::get(T_int8, 0);
1149-
unsigned counter = 0;
1150-
for_each_uniontype_small(
1151-
[&](unsigned idx, jl_datatype_t *jt) {
1152-
if (jl_subtype((jl_value_t*)jt, supertype)) {
1153-
Value *cmp = builder.CreateICmpEQ(literal_pointer_val((jl_value_t*)jt), datatype);
1154-
tindex = builder.CreateSelect(cmp, ConstantInt::get(T_int8, idx), tindex);
1155-
}
1156-
},
1157-
ut,
1158-
counter);
1159-
return tindex;
1160-
}
1161-
1162-
// get the runtime tindex value
1163-
static Value *compute_tindex_unboxed(const jl_cgval_t &val, jl_value_t *typ, jl_codectx_t *ctx)
1164-
{
1165-
if (val.constant)
1166-
return ConstantInt::get(T_int8, get_box_tindex((jl_datatype_t*)jl_typeof(val.constant), typ));
1167-
if (val.isboxed)
1168-
return compute_box_tindex(emit_typeof_boxed(val, ctx), val.typ, typ, ctx);
1169-
assert(val.TIndex);
1170-
return builder.CreateAnd(val.TIndex, ConstantInt::get(T_int8, 0x7f));
1171-
}
1172-
11731144
// If given alignment is 0 and LLVM's assumed alignment for a load/store via ptr
11741145
// might be stricter than the Julia alignment for jltype, return the alignment of jltype.
11751146
// Otherwise return the given alignment.
@@ -1195,16 +1166,13 @@ static jl_cgval_t typed_load(Value *ptr, Value *idx_0based, jl_value_t *jltype,
11951166
Type *elty = julia_type_to_llvm(jltype, &isboxed);
11961167
if (type_is_ghost(elty))
11971168
return ghostValue(jltype);
1198-
Value *data;
11991169
if (isboxed)
12001170
elty = T_prjlvalue;
1201-
// TODO: preserving_pointercast?
1171+
Value *data = ptr;
12021172
if (ptr->getType()->getContainedType(0) != elty)
12031173
data = emit_bitcast(ptr, PointerType::get(elty, 0));
1204-
else
1205-
data = ptr;
12061174
if (idx_0based)
1207-
data = builder.CreateGEP(data, idx_0based);
1175+
data = builder.CreateGEP(elty, data, idx_0based);
12081176
Value *elt;
12091177
// TODO: can only lazy load if we can create a gc root for ptr for the lifetime of elt
12101178
//if (elty->isAggregateType() && tbaa == tbaa_immut && !alignment) { // can lazy load on demand, no copy needed
@@ -1244,17 +1212,12 @@ static void typed_store(Value *ptr, Value *idx_0based, const jl_cgval_t &rhs,
12441212
else {
12451213
r = maybe_decay_untracked(boxed(rhs, ctx, root_box));
12461214
if (parent != NULL) emit_write_barrier(ctx, parent, r);
1215+
elty = T_prjlvalue;
12471216
}
1248-
Value *data;
1249-
if (ptr->getType()->getContainedType(0) != elty) {
1250-
if (isboxed) {
1251-
data = emit_bitcast(ptr, T_pprjlvalue);
1252-
} else {
1253-
data = emit_bitcast(ptr, PointerType::get(elty, cast<PointerType>(ptr->getType())->getAddressSpace()));
1254-
}
1255-
} else
1256-
data = ptr;
1257-
Instruction *store = builder.CreateAlignedStore(r, builder.CreateGEP(data,
1217+
Value *data = ptr;
1218+
if (ptr->getType()->getContainedType(0) != elty)
1219+
data = emit_bitcast(ptr, elty->getPointerTo());
1220+
Instruction *store = builder.CreateAlignedStore(r, builder.CreateGEP(elty, data,
12581221
idx_0based), isboxed ? alignment : julia_alignment(r, jltype, alignment));
12591222
if (tbaa)
12601223
tbaa_decorate(tbaa, store);
@@ -1488,7 +1451,7 @@ static jl_cgval_t emit_getfield_knownidx(const jl_cgval_t &strct, unsigned idx,
14881451
}
14891452
else if (jl_is_uniontype(jfty)) {
14901453
int fsz = jl_field_size(jt, idx);
1491-
Value *ptindex = builder.CreateGEP(LLVM37_param(T_int8) emit_bitcast(addr, T_pint8), ConstantInt::get(T_size, fsz - 1));
1454+
Value *ptindex = builder.CreateGEP(T_int8, emit_bitcast(addr, T_pint8), ConstantInt::get(T_size, fsz - 1));
14921455
Value *tindex = builder.CreateNUWAdd(ConstantInt::get(T_int8, 1), builder.CreateLoad(ptindex));
14931456
bool isimmutable = strct.isimmutable;
14941457
Value *gcroot = strct.gcroot;
@@ -1643,7 +1606,7 @@ static Value *emit_arraylen_prim(const jl_cgval_t &tinfo, jl_codectx_t *ctx)
16431606
static Value *emit_arraylen(const jl_cgval_t &tinfo, jl_value_t *ex, jl_codectx_t *ctx)
16441607
{
16451608
jl_arrayvar_t *av = arrayvar_for(ex, ctx);
1646-
if (av!=NULL)
1609+
if (av != NULL)
16471610
return builder.CreateLoad(av->len);
16481611
return emit_arraylen_prim(tinfo, ctx);
16491612
}
@@ -1813,7 +1776,7 @@ static Value *emit_array_nd_index(const jl_cgval_t &ainfo, jl_value_t *ex, ssize
18131776
// CreateAlloca is OK here since we are on an error branch
18141777
Value *tmp = builder.CreateAlloca(T_size, ConstantInt::get(T_size, nidxs));
18151778
for(size_t k=0; k < nidxs; k++) {
1816-
builder.CreateStore(idxs[k], builder.CreateGEP(tmp, ConstantInt::get(T_size, k)));
1779+
builder.CreateStore(idxs[k], builder.CreateGEP(T_size, tmp, ConstantInt::get(T_size, k)));
18171780
}
18181781
builder.CreateCall(prepare_call(jlboundserrorv_func),
18191782
{ mark_callee_rooted(a), tmp, ConstantInt::get(T_size, nidxs) });
@@ -1995,7 +1958,32 @@ static Value *_boxed_special(const jl_cgval_t &vinfo, Type *t, jl_codectx_t *ctx
19951958
return box;
19961959
}
19971960

1961+
static Value *compute_box_tindex(Value *datatype, jl_value_t *supertype, jl_value_t *ut, jl_codectx_t *ctx)
1962+
{
1963+
Value *tindex = ConstantInt::get(T_int8, 0);
1964+
unsigned counter = 0;
1965+
for_each_uniontype_small(
1966+
[&](unsigned idx, jl_datatype_t *jt) {
1967+
if (jl_subtype((jl_value_t*)jt, supertype)) {
1968+
Value *cmp = builder.CreateICmpEQ(maybe_decay_untracked(literal_pointer_val((jl_value_t*)jt)), datatype);
1969+
tindex = builder.CreateSelect(cmp, ConstantInt::get(T_int8, idx), tindex);
1970+
}
1971+
},
1972+
ut,
1973+
counter);
1974+
return tindex;
1975+
}
19981976

1977+
// get the runtime tindex value
1978+
static Value *compute_tindex_unboxed(const jl_cgval_t &val, jl_value_t *typ, jl_codectx_t *ctx)
1979+
{
1980+
if (val.constant)
1981+
return ConstantInt::get(T_int8, get_box_tindex((jl_datatype_t*)jl_typeof(val.constant), typ));
1982+
if (val.isboxed)
1983+
return compute_box_tindex(emit_typeof_boxed(val, ctx), val.typ, typ, ctx);
1984+
assert(val.TIndex);
1985+
return builder.CreateAnd(val.TIndex, ConstantInt::get(T_int8, 0x7f));
1986+
}
19991987

20001988
static Value *box_union(const jl_cgval_t &vinfo, jl_codectx_t *ctx, const SmallBitVector &skip)
20011989
{
@@ -2281,7 +2269,7 @@ static void emit_setfield(jl_datatype_t *sty, const jl_cgval_t &strct, size_t id
22812269
{
22822270
if (sty->mutabl || !checked) {
22832271
assert(strct.ispointer());
2284-
Value *addr = builder.CreateGEP(data_pointer(strct, ctx, T_pint8),
2272+
Value *addr = builder.CreateGEP(T_int8, data_pointer(strct, ctx, T_pint8),
22852273
ConstantInt::get(T_size, jl_field_offset(sty, idx0)));
22862274
jl_value_t *jfty = jl_svecref(sty->types, idx0);
22872275
if (jl_field_isptr(sty, idx0)) {
@@ -2295,9 +2283,9 @@ static void emit_setfield(jl_datatype_t *sty, const jl_cgval_t &strct, size_t id
22952283
int fsz = jl_field_size(sty, idx0);
22962284
// compute tindex from rhs
22972285
jl_cgval_t rhs_union = convert_julia_type(rhs, jfty, ctx);
2298-
Value *ptindex = builder.CreateGEP(LLVM37_param(T_int8) emit_bitcast(addr, T_pint8), ConstantInt::get(T_size, fsz - 1));
22992286
Value *tindex = compute_tindex_unboxed(rhs_union, jfty, ctx);
23002287
tindex = builder.CreateNUWSub(tindex, ConstantInt::get(T_int8, 1));
2288+
Value *ptindex = builder.CreateGEP(T_int8, emit_bitcast(addr, T_pint8), ConstantInt::get(T_size, fsz - 1));
23012289
builder.CreateStore(tindex, ptindex);
23022290
// copy data
23032291
emit_unionmove(addr, rhs, NULL, false, NULL, ctx);
@@ -2390,7 +2378,7 @@ static jl_cgval_t emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **arg
23902378
tbaa_decorate(strctinfo.tbaa, builder.CreateStore(
23912379
ConstantPointerNull::get(cast<PointerType>(T_prjlvalue)),
23922380
emit_bitcast(
2393-
builder.CreateGEP(emit_bitcast(decay_derived(strct), T_pint8),
2381+
builder.CreateGEP(T_int8, emit_bitcast(decay_derived(strct), T_pint8),
23942382
ConstantInt::get(T_size, jl_field_offset(sty, i))),
23952383
T_pprjlvalue)));
23962384
}
@@ -2434,7 +2422,7 @@ static Value *emit_exc_in_transit(jl_codectx_t *ctx)
24342422
Value *pexc_in_transit = emit_bitcast(ctx->ptlsStates, T_pprjlvalue);
24352423
Constant *offset = ConstantInt::getSigned(T_int32,
24362424
offsetof(jl_tls_states_t, exception_in_transit) / sizeof(void*));
2437-
return builder.CreateGEP(pexc_in_transit, ArrayRef<Value*>(offset), "jl_exception_in_transit");
2425+
return builder.CreateGEP(T_prjlvalue, pexc_in_transit, ArrayRef<Value*>(offset), "jl_exception_in_transit");
24382426
}
24392427

24402428
static void emit_signal_fence(void)
@@ -2457,7 +2445,7 @@ static Value *emit_defer_signal(jl_codectx_t *ctx)
24572445
PointerType::get(T_sigatomic, 0));
24582446
Constant *offset = ConstantInt::getSigned(T_int32,
24592447
offsetof(jl_tls_states_t, defer_signal) / sizeof(sig_atomic_t));
2460-
return builder.CreateGEP(ptls, ArrayRef<Value*>(offset), "jl_defer_signal");
2448+
return builder.CreateGEP(T_sigatomic, ptls, ArrayRef<Value*>(offset), "jl_defer_signal");
24612449
}
24622450

24632451
static int compare_cgparams(const jl_cgparams_t *a, const jl_cgparams_t *b)

0 commit comments

Comments
 (0)