Skip to content

Commit

Permalink
fix #5142
Browse files Browse the repository at this point in the history
This teaches jl_new_bits how to create heap-allocated tuples from flat, stack-allocated
bits-type tuples. It also ensures that allocate_box_dynamic always marks the
julia type of its return values.
  • Loading branch information
vtjnash committed Jan 11, 2014
1 parent 72b5b70 commit b2de71c
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 96 deletions.
53 changes: 43 additions & 10 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,43 @@ typedef struct {
int64_t b;
} bits128_t;

jl_value_t *jl_new_bits(jl_datatype_t *bt, void *data)
{
if (bt == jl_uint8_type) return jl_box_uint8(*(uint8_t*)data);
else if (bt == jl_int64_type) return jl_box_int64(*(int64_t*)data);
else if (bt == jl_bool_type) return (*(int8_t*)data) ? jl_true:jl_false;
else if (bt == jl_int32_type) return jl_box_int32(*(int32_t*)data);
else if (bt == jl_float64_type) return jl_box_float64(*(double*)data);

static size_t jl_new_bits_align(jl_value_t *dt) {
if (jl_is_tuple(dt)) {
size_t i, l = jl_tuple_len(dt), align = 0;
for (i = 0; i < l; i++) {
size_t l = jl_new_bits_align(jl_tupleref(dt,i));
if (l > align)
align = l;
}
return align;
}
return ((jl_datatype_t*)dt)->alignment;
}

static jl_value_t *jl_new_bits_internal(jl_value_t *dt, void *data, size_t *len)
{
if (jl_is_tuple(dt)) {
jl_tuple_t *tuple = (jl_tuple_t*)dt;
*len = LLT_ALIGN(*len, jl_new_bits_align(dt));
size_t i, l = jl_tuple_len(tuple);
jl_value_t *v = (jl_value_t*) jl_alloc_tuple_uninit(l);
for (i = 0; i < l; i++) {
jl_tupleset(v,i,jl_new_bits_internal(jl_tupleref(tuple,i), (char*)data, len));
}
return v;
}

jl_datatype_t *bt = (jl_datatype_t*)dt;
size_t nb = jl_datatype_size(bt);
*len = LLT_ALIGN(*len, bt->alignment);
data = (char*)data + (*len);
*len += nb;
if (bt == jl_uint8_type) return jl_box_uint8(*(uint8_t*)data);
if (bt == jl_int64_type) return jl_box_int64(*(int64_t*)data);
if (bt == jl_bool_type) return (*(int8_t*)data) ? jl_true:jl_false;
if (bt == jl_int32_type) return jl_box_int32(*(int32_t*)data);
if (bt == jl_float64_type) return jl_box_float64(*(double*)data);

jl_value_t *v =
(jl_value_t*)allocobj((NWORDS(LLT_ALIGN(nb,sizeof(void*)))+1)*
sizeof(void*));
Expand All @@ -117,6 +145,12 @@ jl_value_t *jl_new_bits(jl_datatype_t *bt, void *data)
return v;
}

jl_value_t *jl_new_bits(jl_value_t *bt, void *data)
{
size_t len = 0;
return jl_new_bits_internal(bt, data, &len);
}

void jl_assign_bits(void *dest, jl_value_t *bits)
{
size_t nb = jl_datatype_size(jl_typeof(bits));
Expand Down Expand Up @@ -150,8 +184,7 @@ jl_value_t *jl_get_nth_field(jl_value_t *v, size_t i)
if (st->fields[i].isptr) {
return *(jl_value_t**)((char*)v + offs);
}
return jl_new_bits((jl_datatype_t*)jl_tupleref(st->types,i),
(char*)v + offs);
return jl_new_bits(jl_tupleref(st->types,i), (char*)v + offs);
}

int jl_field_isdefined(jl_value_t *v, jl_sym_t *fld, int err)
Expand Down
3 changes: 1 addition & 2 deletions src/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,7 @@ jl_value_t *jl_arrayref(jl_array_t *a, size_t i)
jl_value_t *el_type = (jl_value_t*)jl_tparam0(jl_typeof(a));
jl_value_t *elt;
if (!a->ptrarray) {
elt = jl_new_bits((jl_datatype_t*)el_type,
&((char*)a->data)[i*a->elsize]);
elt = jl_new_bits(el_type, &((char*)a->data)[i*a->elsize]);
}
else {
elt = ((jl_value_t**)a->data)[i];
Expand Down
182 changes: 100 additions & 82 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ static Type *julia_type_to_llvm(jl_value_t *jt)
break;
}
if (purebits) {
// Can't be bool due to
// Can't be bool due to
// http://llvm.org/bugs/show_bug.cgi?id=12618
if (isvector && type != T_int1 && type != T_void) {
Type *ret = NULL;
Expand Down Expand Up @@ -261,7 +261,7 @@ static Type *julia_type_to_llvm(jl_value_t *jt)
#ifndef DISABLE_FLOAT16
if (nb == 2)
return Type::getHalfTy(jl_LLVMContext);
else
else
#endif
if (nb == 4)
return Type::getFloatTy(jl_LLVMContext);
Expand Down Expand Up @@ -779,7 +779,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl
#endif
builder.CreateStore(x,slot);
return tuple;
}
}
else {
Value *ret = NULL;
ConstantInt *idx = dyn_cast<ConstantInt>(i);
Expand All @@ -794,7 +794,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl
else if (iity->getBitWidth() < 32)
i = builder.CreateZExt(i,T_int32);
ret = builder.CreateInsertElement(tuple,x,builder.CreateSub(i,ConstantInt::get(T_int32,1)));
}
}
else {
unsigned ci = (unsigned)idx->getZExtValue()-1;
size_t n = jl_tuple_len(jt);
Expand All @@ -803,7 +803,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl
if (ci == i) {
if (ty == T_void || ty->isEmptyTy())
return tuple;
else
else
ret = builder.CreateInsertValue(tuple,x,ArrayRef<unsigned>(j));
}
if (ty != T_void)
Expand All @@ -814,6 +814,9 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl
}
}

static Value *allocate_box_dynamic(Value *jlty, int nb, Value *v);
static void jl_add_linfo_root(jl_lambda_info_t *li, jl_value_t *val);

// Julia semantics
static Value *emit_tupleref(Value *tuple, Value *ival, jl_value_t *jt, jl_codectx_t *ctx)
{
Expand All @@ -831,83 +834,100 @@ static Value *emit_tupleref(Value *tuple, Value *ival, jl_value_t *jt, jl_codect
builder.CreateAdd(ConstantInt::get(T_size,1),ival));
#endif
return builder.CreateLoad(slot);
}
else {
if (ty->isVectorTy()) {
Type *ity = ival->getType();
assert(ity->isIntegerTy());
IntegerType *iity = dyn_cast<IntegerType>(ity);
// ExtractElement needs i32 *sigh*
if (iity->getBitWidth() > 32)
ival = builder.CreateTrunc(ival,T_int32);
else if (iity->getBitWidth() < 32)
ival = builder.CreateZExt(ival,T_int32);
return builder.CreateExtractElement(tuple,builder.CreateSub(ival,ConstantInt::get(T_int32,1)));
}
ConstantInt *idx = dyn_cast<ConstantInt>(ival);
unsigned ci = idx ? (unsigned)idx->getZExtValue()-1 : (unsigned)-1;
if (ty->isVectorTy()) {
Type *ity = ival->getType();
assert(ity->isIntegerTy());
IntegerType *iity = dyn_cast<IntegerType>(ity);
// ExtractElement needs i32 *sigh*
if (iity->getBitWidth() > 32)
ival = builder.CreateTrunc(ival,T_int32);
else if (iity->getBitWidth() < 32)
ival = builder.CreateZExt(ival,T_int32);
Value *v = builder.CreateExtractElement(tuple,builder.CreateSub(ival,ConstantInt::get(T_int32,1)));
if (idx)
v = mark_julia_type(v,jl_tupleref(jt,ci));
else {
if (sizeof(void*) != 4)
ival = builder.CreateZExt(ival,T_size);
jl_add_linfo_root(ctx->linfo, jt);
v = allocate_box_dynamic(emit_tupleref(literal_pointer_val(jt), ival, jl_typeof(jt), ctx), ty->getScalarSizeInBits(), v);
}
ConstantInt *idx = dyn_cast<ConstantInt>(ival);
if (idx != 0) {
unsigned ci = (unsigned)idx->getZExtValue()-1;
size_t n = jl_tuple_len(jt);
for (size_t i = 0,j = 0; i<n; ++i) {
Type *ty = julia_struct_to_llvm(jl_tupleref(jt,i));
if (ci == i) {
if (ty == T_void || ty->isEmptyTy())
return mark_julia_type(UndefValue::get(NoopType),jl_tupleref(jt,i));
else
return mark_julia_type(builder.CreateExtractValue(tuple,ArrayRef<unsigned>(j)),jl_tupleref(jt,i));
}
if (ty != T_void)
++j;
return v;
}
if (idx) {
size_t n = jl_tuple_len(jt);
for (size_t i = 0,j = 0; i<n; ++i) {
Type *ty = julia_struct_to_llvm(jl_tupleref(jt,i));
if (ci == i) {
if (ty == T_void || ty->isEmptyTy())
return mark_julia_type(UndefValue::get(NoopType),jl_tupleref(jt,i));
else
return mark_julia_type(builder.CreateExtractValue(tuple,ArrayRef<unsigned>(j)),jl_tupleref(jt,i));
}
assert("Out of bounds!");
return NULL;
if (ty != T_void) ++j;
}
else if (ty->isArrayTy()) {
ArrayType *at = dyn_cast<ArrayType>(ty);
Value *tempSpace = builder.CreateAlloca(at);
builder.CreateStore(tuple,tempSpace);
Value *idxs[2];
idxs[0] = ConstantInt::get(T_size,0);
idxs[1] = builder.CreateSub(ival,ConstantInt::get(T_size,1));
return builder.CreateLoad(builder.CreateGEP(tempSpace,ArrayRef<Value*>(&idxs[0],2)));
assert("Out of bounds!");

This comment has been minimized.

Copy link
@JeffBezanson

JeffBezanson Jan 11, 2014

Member

should this be 0 && "Out of bounds!" ?

This comment has been minimized.

Copy link
@vtjnash

vtjnash Jan 11, 2014

Author Member

yes, that would probably be more useful

return NULL;
}
if (ty->isArrayTy()) {
ArrayType *at = dyn_cast<ArrayType>(ty);
Value *tempSpace = builder.CreateAlloca(at);
builder.CreateStore(tuple,tempSpace);
Value *idxs[2];
idxs[0] = ConstantInt::get(T_size,0);
idxs[1] = builder.CreateSub(ival,ConstantInt::get(T_size,1));
Value *v = builder.CreateGEP(tempSpace,ArrayRef<Value*>(&idxs[0],2));
if (idx)
v = mark_julia_type(builder.CreateLoad(v),jl_tupleref(jt,ci));
else {
jl_add_linfo_root(ctx->linfo, jt);
Value *lty = emit_tupleref(literal_pointer_val(jt), ival, jl_typeof(jt), ctx);
size_t i, l = jl_tuple_len(jt);
for (i = 0; i < l; jt++)
if (!jl_isbits(jl_tupleref(jt,i)))
return builder.CreateCall2(jlnewbits_func, boxed(lty,ctx), builder.CreatePointerCast(v,T_pint8));
unsigned nb = (ty->getSequentialElementType()->getPrimitiveSizeInBits()+7)/8;
v = allocate_box_dynamic(lty, nb, builder.CreateLoad(v));
}
return v;
}
assert(ty->isStructTy());
StructType *st = dyn_cast<StructType>(ty);
size_t n = st->getNumElements();
Value *ret = builder.CreateAlloca(jl_pvalue_llvmt);
BasicBlock *after = BasicBlock::Create(getGlobalContext(),"after_switch",ctx->f);
BasicBlock *deflt = BasicBlock::Create(getGlobalContext(),"default_case",ctx->f);
// Create the switch
SwitchInst *sw = builder.CreateSwitch(ival,deflt,n);
// Anything else is a bounds error
builder.SetInsertPoint(deflt);
builder.CreateCall2(jlthrow_line_func, builder.CreateLoad(jlboundserr_var),
ConstantInt::get(T_int32, ctx->lineno));
builder.CreateUnreachable();
// Now for the cases
for (size_t i = 0, j = 0; i < jl_tuple_len(jt); ++i) {
BasicBlock *blk = BasicBlock::Create(getGlobalContext(),"case",ctx->f);
sw->addCase(ConstantInt::get((IntegerType*)T_size,i+1),blk);
builder.SetInsertPoint(blk);
jl_value_t *jltype = jl_tupleref(jt,i);
Type *ty = julia_struct_to_llvm(jltype);
Value *val;
if (ty != T_void) {
val = boxed(builder.CreateExtractValue(tuple,ArrayRef<unsigned>(j)),ctx,jltype);
j++;
}
else {
assert(ty->isStructTy());
StructType *st = dyn_cast<StructType>(ty);
size_t n = st->getNumElements();
Value *ret = builder.CreateAlloca(jl_pvalue_llvmt);
BasicBlock *after = BasicBlock::Create(getGlobalContext(),"after_switch",ctx->f);
BasicBlock *deflt = BasicBlock::Create(getGlobalContext(),"default_case",ctx->f);
// Create the switch
SwitchInst *sw = builder.CreateSwitch(ival,deflt,n);
// Anything else is a bounds error
builder.SetInsertPoint(deflt);
builder.CreateCall2(jlthrow_line_func, builder.CreateLoad(jlboundserr_var),
ConstantInt::get(T_int32, ctx->lineno));
builder.CreateUnreachable();
// Now for the cases
for (size_t i = 0, j = 0; i < jl_tuple_len(jt); ++i) {
BasicBlock *blk = BasicBlock::Create(getGlobalContext(),"case",ctx->f);
sw->addCase(ConstantInt::get((IntegerType*)T_size,i+1),blk);
builder.SetInsertPoint(blk);
jl_value_t *jltype = jl_tupleref(jt,i);
Type *ty = julia_struct_to_llvm(jltype);
Value *val;
if (ty != T_void) {
val = boxed(builder.CreateExtractValue(tuple,ArrayRef<unsigned>(j)),ctx,jltype);
j++;
}
else {
val = boxed(NULL,ctx,jltype);
}
builder.CreateStore(val,ret);
builder.CreateBr(after);

}
builder.SetInsertPoint(after);
return builder.CreateLoad(ret);
val = boxed(NULL,ctx,jltype);
}
builder.CreateStore(val,ret);
builder.CreateBr(after);

}
builder.SetInsertPoint(after);
return builder.CreateLoad(ret);
}


Expand Down Expand Up @@ -1127,7 +1147,7 @@ static jl_value_t *static_void_instance(jl_value_t *jt)
jl_new_struct_uninit(jb);
assert(jb->instance != NULL);
return (jl_value_t*)jb->instance;
}
}
else if (jt == jl_typeof(jl_nothing) || jt == jl_bottom_type) {
return (jl_value_t*)jl_nothing;
}
Expand All @@ -1151,23 +1171,23 @@ static jl_value_t *static_constant_instance(Constant *constant, jl_value_t *jt)
ConstantInt *cint = dyn_cast<ConstantInt>(constant);
if (cint != NULL) {
assert(jl_is_datatype(jt));
return jl_new_bits((jl_datatype_t*)jt,
return jl_new_bits(jt,
const_cast<uint64_t *>(cint->getValue().getRawData()));
}

ConstantFP *cfp = dyn_cast<ConstantFP>(constant);
if (cfp != NULL) {
assert(jl_is_datatype(jt));
return jl_new_bits((jl_datatype_t*)jt,
return jl_new_bits(jt,
const_cast<uint64_t *>(cfp->getValueAPF().bitcastToAPInt().getRawData()));
}

ConstantPointerNull *cpn = dyn_cast<ConstantPointerNull>(constant);
if (cpn != NULL) {
assert(jl_is_cpointer_type(jt));
uint64_t val = 0;
return jl_new_bits((jl_datatype_t*)jt,&val);
}
return jl_new_bits(jt,&val);
}

assert(jl_is_tuple(jt));

Expand Down Expand Up @@ -1195,8 +1215,6 @@ static jl_value_t *static_constant_instance(Constant *constant, jl_value_t *jt)
}


static void jl_add_linfo_root(jl_lambda_info_t *li, jl_value_t *val);

// this is used to wrap values for generic contexts, where a
// dynamically-typed value is required (e.g. argument to unknown function).
// if it's already a pointer it's left alone.
Expand Down
11 changes: 10 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ static Function *box32_func;
static Function *box64_func;
static Function *jlputs_func;
static Function *jldlsym_func;
static Function *jlnewbits_func;
#ifdef _OS_WINDOWS_
static Function *resetstkoflw_func;
#endif
Expand Down Expand Up @@ -3736,9 +3737,17 @@ static void init_julia_llvm_env(Module *m)
"jl_load_and_lookup", jl_Module);
jl_ExecutionEngine->addGlobalMapping(jldlsym_func, (void*)&jl_load_and_lookup);

std::vector<Type *> newbits_args(0);
newbits_args.push_back(jl_pvalue_llvmt);
newbits_args.push_back(T_pint8);
jlnewbits_func =
Function::Create(FunctionType::get(jl_pvalue_llvmt, newbits_args, false),
Function::ExternalLinkage,
"jl_new_bits", jl_Module);
jl_ExecutionEngine->addGlobalMapping(jlnewbits_func, (void*)&jl_new_bits);

// set up optimization passes
FPM = new FunctionPassManager(jl_Module);


#ifdef LLVM32
jl_data_layout = new DataLayout(*jl_ExecutionEngine->getDataLayout());
Expand Down
2 changes: 1 addition & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ jl_datatype_t *jl_wrap_Type(jl_value_t *t); // x -> Type{x}
void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super);

// constructors
jl_value_t *jl_new_bits(jl_datatype_t *bt, void *data);
DLLEXPORT jl_value_t *jl_new_bits(jl_value_t *bt, void *data);
void jl_assign_bits(void *dest, jl_value_t *bits);
DLLEXPORT jl_value_t *jl_new_struct(jl_datatype_t *type, ...);
DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uint32_t na);
Expand Down
Loading

1 comment on commit b2de71c

@staticfloat
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<applause>

Please sign in to comment.