Skip to content

Commit

Permalink
allow more kinds of fields to take 0 space. fixes JuliaLang#8156
Browse files Browse the repository at this point in the history
also initialize datatype->instance eagerly, so you don't need to check
for that everywhere. this also makes it easier to change the logic
of which types are singletons.
  • Loading branch information
JeffBezanson committed Aug 27, 2014
1 parent 743af1a commit 6667e5d
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 33 deletions.
21 changes: 12 additions & 9 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ static jl_value_t *jl_new_bits_internal(jl_value_t *dt, void *data, size_t *len)

jl_datatype_t *bt = (jl_datatype_t*)dt;
size_t nb = jl_datatype_size(bt);
if (nb == 0)
return jl_new_struct_uninit(bt);
*len = LLT_ALIGN(*len, bt->alignment);
data = (char*)data + (*len);
*len += nb;
Expand Down Expand Up @@ -175,6 +177,7 @@ DLLEXPORT jl_value_t *jl_pointerref(jl_value_t *p, jl_value_t *i)
void jl_assign_bits(void *dest, jl_value_t *bits)
{
size_t nb = jl_datatype_size(jl_typeof(bits));
if (nb == 0) return;
switch (nb) {
case 1: *(int8_t*)dest = *(int8_t*)jl_data_ptr(bits); break;
case 2: *(int16_t*)dest = *(int16_t*)jl_data_ptr(bits); break;
Expand Down Expand Up @@ -270,7 +273,6 @@ DLLEXPORT jl_value_t *jl_new_struct(jl_datatype_t *type, ...)
for(size_t i=0; i < nf; i++) {
jl_set_nth_field(jv, i, va_arg(args, jl_value_t*));
}
if (type->size == 0) type->instance = jv;
va_end(args);
return jv;
}
Expand All @@ -287,16 +289,15 @@ DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uin
if (type->fields[i].isptr)
*(jl_value_t**)((char*)jv+jl_field_offset(type,i)+sizeof(void*)) = NULL;
}
if (type->size == 0) type->instance = jv;
return jv;
}

DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type)
{
if (type->instance != NULL) return type->instance;
jl_value_t *jv = newstruct(type);
if (type->size == 0) type->instance = jv;
else memset(&((void**)jv)[1], 0, type->size);
if (type->size > 0)
memset(&((void**)jv)[1], 0, type->size);
return jv;
}

Expand Down Expand Up @@ -661,9 +662,9 @@ void jl_compute_field_offsets(jl_datatype_t *st)
for(size_t i=0; i < jl_tuple_len(st->types); i++) {
jl_value_t *ty = jl_tupleref(st->types, i);
size_t fsz, al;
if (jl_isbits(ty) && (al=((jl_datatype_t*)ty)->alignment)!=0 &&
jl_is_leaf_type(ty)) {
if (jl_isbits(ty) && jl_is_leaf_type(ty)) {
fsz = jl_datatype_size(ty);
al = ((jl_datatype_t*)ty)->alignment;
st->fields[i].isptr = 0;
}
else {
Expand All @@ -672,9 +673,11 @@ void jl_compute_field_offsets(jl_datatype_t *st)
st->fields[i].isptr = 1;
ptrfree = 0;
}
sz = LLT_ALIGN(sz, al);
if (al > alignm)
alignm = al;
if (al != 0) {
sz = LLT_ALIGN(sz, al);
if (al > alignm)
alignm = al;
}
st->fields[i].offset = sz;
st->fields[i].size = fsz;
sz += fsz;
Expand Down
23 changes: 11 additions & 12 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,10 +476,7 @@ DLLEXPORT Type *julia_type_to_llvm(jl_value_t *jt)
}
if (jl_isbits(jt)) {
if (((jl_datatype_t*)jt)->size == 0) {
// TODO: come up with a representation for a 0-size value,
// and make this 0 size everywhere. as an argument, simply
// skip passing it.
return jl_pvalue_llvmt;
return T_void;
}
return julia_struct_to_llvm(jt);
}
Expand All @@ -495,7 +492,7 @@ static Type *julia_struct_to_llvm(jl_value_t *jt)
jl_datatype_t *jst = (jl_datatype_t*)jt;
if (jst->struct_decl == NULL) {
size_t ntypes = jl_tuple_len(jst->types);
if (ntypes == 0)
if (ntypes == 0 || jst->size == 0)
return T_void;
StructType *structdecl = StructType::create(getGlobalContext(), jst->name->name->name);
jst->struct_decl = structdecl;
Expand Down Expand Up @@ -881,12 +878,16 @@ static Value *emit_nthptr_recast(Value *v, size_t n, MDNode *tbaa, Type* ptype)
Value *vptr = emit_nthptr_addr(v, n);
return tbaa_decorate(tbaa,builder.CreateLoad(builder.CreateBitCast(vptr,ptype), false));
}

static Value *ghostValue(jl_value_t *ty);

static Value *typed_load(Value *ptr, Value *idx_0based, jl_value_t *jltype,
jl_codectx_t *ctx)
{
Type *elty = julia_type_to_llvm(jltype);
assert(elty != NULL);
if (elty == T_void)
return ghostValue(jltype);
bool isbool=false;
if (elty==T_int1) { elty = T_int8; isbool=true; }
Value *data;
Expand All @@ -905,11 +906,13 @@ static Value *typed_load(Value *ptr, Value *idx_0based, jl_value_t *jltype,

static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt);

static Value *typed_store(Value *ptr, Value *idx_0based, Value *rhs,
jl_value_t *jltype, jl_codectx_t *ctx)
static void typed_store(Value *ptr, Value *idx_0based, Value *rhs,
jl_value_t *jltype, jl_codectx_t *ctx)
{
Type *elty = julia_type_to_llvm(jltype);
assert(elty != NULL);
if (elty == T_void)
return;
if (elty==T_int1) { elty = T_int8; }
if (jl_isbits(jltype) && ((jl_datatype_t*)jltype)->size > 0)
rhs = emit_unbox(elty, rhs, jltype);
Expand All @@ -920,7 +923,7 @@ static Value *typed_store(Value *ptr, Value *idx_0based, Value *rhs,
data = builder.CreateBitCast(ptr, PointerType::get(elty, 0));
else
data = ptr;
return tbaa_decorate(tbaa_user, builder.CreateStore(rhs, builder.CreateGEP(data, idx_0based)));
tbaa_decorate(tbaa_user, builder.CreateStore(rhs, builder.CreateGEP(data, idx_0based)));
}

// --- convert boolean value to julia ---
Expand Down Expand Up @@ -1443,8 +1446,6 @@ static jl_value_t *static_void_instance(jl_value_t *jt)
}
if (jl_is_datatype(jt)) {
jl_datatype_t *jb = (jl_datatype_t*)jt;
if (jb->instance == NULL)
jl_new_struct_uninit(jb);
if (jb->instance == NULL)
// if we can't get an instance then this was an UndefValue due
// to throwing an error.
Expand Down Expand Up @@ -1612,8 +1613,6 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt)
}

if (!jb->abstract && jb->size == 0) {
if (jb->instance == NULL)
jl_new_struct_uninit(jb);
assert(jb->instance != NULL);
return literal_pointer_val(jb->instance);
}
Expand Down
13 changes: 7 additions & 6 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2025,8 +2025,8 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs,
JL_GC_POP();
if (jl_array_store_unboxed(ety) &&
((jl_datatype_t*)ety)->size == 0) {
jl_new_struct_uninit((jl_datatype_t*)ety);
assert(jl_is_datatype(ety));
assert(((jl_datatype_t*)ety)->instance != NULL);
return literal_pointer_val(((jl_datatype_t*)ety)->instance);
}
return typed_load(emit_arrayptr(ary, args[1], ctx), idx, ety, ctx);
Expand Down Expand Up @@ -2419,9 +2419,10 @@ static Value *ghostValue(jl_value_t *ty)
{
if (jl_is_datatype(ty)) {
Type *llvmty = julia_struct_to_llvm(ty);
assert(llvmty != T_void);
if (llvmty == T_void)
return mark_julia_type(UndefValue::get(NoopType),ty);
return UndefValue::get(llvmty);
}
}
else {
return mark_julia_type(UndefValue::get(NoopType),ty);
}
Expand Down Expand Up @@ -2798,7 +2799,8 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed,
if (nf > 0) {
if (jl_isbits(sty)) {
Type *lt = julia_type_to_llvm(ty);
assert(lt != T_void);
if (lt == T_void)
return mark_julia_type(UndefValue::get(NoopType),ty);
Value *strct = UndefValue::get(lt);
size_t na = nargs-1 < nf ? nargs-1 : nf;
unsigned idx = 0;
Expand Down Expand Up @@ -3202,8 +3204,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct
Value *theArg = builder.CreateLoad(argPtr, false);
Value *theNewArg = theArg;
argIdx++;
if ((jl_is_leaf_type(ty) && jl_isbits(ty) &&
((jl_datatype_t*)ty)->size > 0)) {
if (jl_is_leaf_type(ty) && jl_isbits(ty)) {
Type *lty = julia_struct_to_llvm(ty);
assert(lty != NULL);
if (lty == T_void || lty->isEmptyTy())
Expand Down
2 changes: 2 additions & 0 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl)
((jl_tvar_t*)jl_tupleref(para,i))->bound = 0;
}
jl_compute_field_offsets(dt);
if (para == (jl_value_t*)jl_null && dt->size == 0)
dt->instance = newstruct(dt);

b->value = temp;
if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) {
Expand Down
2 changes: 1 addition & 1 deletion src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ static Value *emit_pointerset(jl_value_t *e, jl_value_t *x, jl_value_t *i, jl_co
else
val = emit_unboxed(x,ctx);
}
(void)typed_store(thePtr, im1, val, ety, ctx);
typed_store(thePtr, im1, val, ety, ctx);
}
return mark_julia_type(thePtr, aty);
}
Expand Down
14 changes: 9 additions & 5 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1949,18 +1949,22 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_value_t **env, size_t n,
// recursively instantiate the types of the fields
ndt->types = (jl_tuple_t*)inst_type_w_((jl_value_t*)ftypes, env, n, stack, 1);
if (!isabstract) {
jl_compute_field_offsets(ndt);
if (jl_tuple_len(ftypes) == 0) {
ndt->alignment = ndt->size = dt->size;
ndt->pointerfree = dt->pointerfree;
}
else {
jl_compute_field_offsets(ndt);
}
if (ndt->size == 0 && tn != jl_array_typename)
ndt->instance = newstruct(ndt);
}
else {
ndt->size = 0;
ndt->pointerfree = 0;
}
if (tn == jl_array_typename)
ndt->pointerfree = 0;
if (jl_tuple_len(ftypes) == 0) {
ndt->alignment = ndt->size = dt->size;
ndt->pointerfree = dt->pointerfree;
}
}
if (cacheable) cache_type_((jl_value_t*)ndt);
result = (jl_value_t*)ndt;
Expand Down

0 comments on commit 6667e5d

Please sign in to comment.