Skip to content

Commit

Permalink
better optimize code for copying a value to an unboxed union
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Feb 21, 2017
1 parent 76edf67 commit 4109326
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 34 deletions.
70 changes: 68 additions & 2 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ static Value *literal_pointer_val_slot(jl_value_t *p)
static Value *literal_pointer_val(jl_value_t *p)
{
if (p == NULL)
return ConstantPointerNull::get((PointerType*)T_pjlvalue);
return V_null;
if (!imaging_mode)
return literal_static_pointer_val(p, T_pjlvalue);
Value *pgv = literal_pointer_val_slot(p);
Expand All @@ -331,7 +331,7 @@ static Value *literal_pointer_val(jl_binding_t *p)
{
// emit a pointer to any jl_value_t which will be valid across reloading code
if (p == NULL)
return ConstantPointerNull::get((PointerType*)T_pjlvalue);
return V_null;
if (!imaging_mode)
return literal_static_pointer_val(p, T_pjlvalue);
// bindings are prefixed with jl_bnd#
Expand Down Expand Up @@ -764,6 +764,7 @@ static Value *emit_datatype_size(Value *dt)
return size;
}

/* this is valid code, it's simply unused
static Value *emit_sizeof(const jl_cgval_t &p, jl_codectx_t *ctx)
{
if (p.TIndex) {
Expand Down Expand Up @@ -810,6 +811,7 @@ static Value *emit_sizeof(const jl_cgval_t &p, jl_codectx_t *ctx)
return dyn_size;
}
}
*/

static Value *emit_datatype_mutabl(Value *dt)
{
Expand Down Expand Up @@ -1956,6 +1958,70 @@ static Value *boxed(const jl_cgval_t &vinfo, jl_codectx_t *ctx, bool gcrooted)
return box;
}

// copy src to dest, if src is isbits. if skip is true, the value of dest is undefined
static void emit_unionmove(Value *dest, const jl_cgval_t &src, Value *skip, bool isVolatile, MDNode *tbaa, jl_codectx_t *ctx)
{
if (jl_is_leaf_type(src.typ) || src.constant) {
jl_value_t *typ = src.constant ? jl_typeof(src.constant) : src.typ;
Type *store_ty = julia_type_to_llvm(typ);
assert(skip || jl_isbits(typ));
if (jl_isbits(typ)) {
if (!src.ispointer() || src.constant) {
emit_unbox(store_ty, src, typ, dest, isVolatile);
}
else {
Value *src_ptr = data_pointer(src, ctx, T_pint8);
if (dest->getType() != T_pint8)
dest = emit_bitcast(dest, T_pint8);
if (skip) // copy dest -> dest to simulate an undef value / conditional copy
src_ptr = builder.CreateSelect(skip, dest, src_ptr);
unsigned nb = jl_datatype_size(typ);
unsigned alignment = 0;
builder.CreateMemCpy(dest, src_ptr, nb, alignment, tbaa);
}
}
}
else if (src.TIndex) {
Value *tindex = builder.CreateAnd(src.TIndex, ConstantInt::get(T_int8, 0x7f));
Value *copy_bytes = ConstantInt::get(T_int32, -1);
unsigned counter = 0;
bool allunboxed = for_each_uniontype_small(
[&](unsigned idx, jl_datatype_t *jt) {
Value *cmp = builder.CreateICmpEQ(tindex, ConstantInt::get(T_int8, idx));
copy_bytes = builder.CreateSelect(cmp, ConstantInt::get(T_int32, jl_datatype_size(jt)), copy_bytes);
},
src.typ,
counter);
Value *src_ptr = data_pointer(src, ctx, T_pint8);
if (dest->getType() != T_pint8)
dest = emit_bitcast(dest, T_pint8);
if (skip) {
if (allunboxed) // copy dest -> dest to simulate an undef value / conditional copy
src_ptr = builder.CreateSelect(skip, dest, src_ptr);
else
copy_bytes = builder.CreateSelect(skip, ConstantInt::get(copy_bytes->getType(), 0), copy_bytes);
}
#ifndef NDEBUG
// try to catch codegen errors early, before it uses this to memcpy over the entire stack
CreateConditionalAbort(builder, builder.CreateICmpEQ(copy_bytes, ConstantInt::get(T_int32, -1)));
#endif
builder.CreateMemCpy(dest,
src_ptr,
copy_bytes,
/*TODO: min-align*/1);
}
else {
Value *datatype = emit_typeof_boxed(src, ctx);
Value *copy_bytes = emit_datatype_size(datatype);
if (skip)
copy_bytes = builder.CreateSelect(skip, ConstantInt::get(copy_bytes->getType(), 0), copy_bytes);
builder.CreateMemCpy(dest,
data_pointer(src, ctx, T_pint8),
copy_bytes,
/*TODO: min-align*/1);
}
}


static void emit_cpointercheck(const jl_cgval_t &x, const std::string &msg, jl_codectx_t *ctx)
{
Expand Down
53 changes: 21 additions & 32 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3659,15 +3659,8 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx)
builder.CreateAnd(slot.TIndex, ConstantInt::get(T_int8, 0x80)),
ConstantInt::get(T_int8, 0));
}
if (dest) {
Value *copy_bytes = emit_sizeof(slot, ctx);
if (isboxed)
copy_bytes = builder.CreateSelect(isboxed, ConstantInt::get(copy_bytes->getType(), 0), copy_bytes);
builder.CreateMemCpy(dest,
data_pointer(slot, ctx, T_pint8),
copy_bytes,
min_align);
}
if (dest)
emit_unionmove(dest, slot, isboxed, false, NULL, ctx);
Value *gcroot = NULL;
if (isboxed) {
if (slot.gcroot)
Expand Down Expand Up @@ -3770,6 +3763,8 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx)
tindex = compute_tindex_unboxed(rval_info, vi.value.typ, ctx);
if (vi.boxroot)
tindex = builder.CreateOr(tindex, ConstantInt::get(T_int8, 0x80));
if (!vi.boxroot)
rval_info.TIndex = tindex;
}
builder.CreateStore(tindex, vi.pTIndex, vi.isVolatile);
}
Expand Down Expand Up @@ -3838,22 +3833,19 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx)
// x.tbaa ∪ tbaa_stack = tbaa_root if x.tbaa != tbaa_stack
if (tbaa != tbaa_stack)
tbaa = NULL;
Value *copy_bytes;
if (vi.pTIndex == NULL) {
assert(jl_is_leaf_type(vi.value.typ));
copy_bytes = ConstantInt::get(T_int32, jl_datatype_size(vi.value.typ));
Value *copy_bytes = ConstantInt::get(T_int32, jl_datatype_size(vi.value.typ));
builder.CreateMemCpy(vi.value.V,
data_pointer(rval_info, ctx, T_pint8),
copy_bytes,
/*TODO: min_align*/1,
vi.isVolatile,
tbaa);
}
else {
copy_bytes = emit_sizeof(rval_info, ctx);
if (isboxed)
copy_bytes = builder.CreateSelect(isboxed, ConstantInt::get(copy_bytes->getType(), 0), copy_bytes);
emit_unionmove(vi.value.V, rval_info, isboxed, vi.isVolatile, tbaa, ctx);
}
builder.CreateMemCpy(vi.value.V,
data_pointer(rval_info, ctx, T_pint8),
copy_bytes,
/*TODO: min_align*/1,
vi.isVolatile,
tbaa);
}
}
else {
Expand Down Expand Up @@ -5965,7 +5957,7 @@ static std::unique_ptr<Module> emit_function(
continue;
}

Value *isunboxed_union = NULL;
Value *isboxed_union = NULL;
Value *retval;
Value *sret = ctx.has_sret ? &*f->arg_begin() : NULL;
Type *retty = f->getReturnType();
Expand Down Expand Up @@ -5996,10 +5988,10 @@ static std::unique_ptr<Module> emit_function(
if (retvalinfo.ispointer() && !isa<AllocaInst>(retvalinfo.V)) {
// also need to account for the possibility the return object is boxed
// and avoid / skip copying it to the stack
isunboxed_union = builder.CreateICmpEQ(
isboxed_union = builder.CreateICmpNE(
builder.CreateAnd(tindex, ConstantInt::get(T_int8, 0x80)),
ConstantInt::get(T_int8, 0));
data = builder.CreateSelect(isunboxed_union, data, emit_bitcast(retvalinfo.V, T_pjlvalue));
data = builder.CreateSelect(isboxed_union, emit_bitcast(retvalinfo.V, T_pjlvalue), data);
}
}
}
Expand All @@ -6022,20 +6014,17 @@ static std::unique_ptr<Module> emit_function(
}
if (sret) {
if (retvalinfo.ispointer()) {
Value *copy_bytes;
if (returninfo.cc == jl_returninfo_t::SRet) {
assert(jl_is_leaf_type(jlrettype));
copy_bytes = ConstantInt::get(T_int32, jl_datatype_size(jlrettype));
Value *copy_bytes = ConstantInt::get(T_int32, jl_datatype_size(jlrettype));
builder.CreateMemCpy(sret,
data_pointer(retvalinfo, &ctx, T_pint8),
copy_bytes,
returninfo.union_minalign);
}
else {
copy_bytes = emit_sizeof(retvalinfo, &ctx);
if (isunboxed_union)
copy_bytes = builder.CreateSelect(isunboxed_union, copy_bytes, ConstantInt::get(copy_bytes->getType(), 0));
emit_unionmove(sret, retvalinfo, isboxed_union, false, NULL, &ctx);
}
builder.CreateMemCpy(sret,
data_pointer(retvalinfo, &ctx, T_pint8),
copy_bytes,
returninfo.union_minalign);
}
else {
Type *store_ty = julia_type_to_llvm(retvalinfo.typ);
Expand Down

0 comments on commit 4109326

Please sign in to comment.