Skip to content

Commit

Permalink
feature-complete compiler support for immutable aggregates
Browse files Browse the repository at this point in the history
add immutable keyword in frontend, and fix lowering of new() for it
codegen support for unboxed aggregates
  • Loading branch information
JeffBezanson committed Feb 22, 2013
1 parent f6cc185 commit 03ace87
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 95 deletions.
3 changes: 3 additions & 0 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,9 @@ function abstract_eval(e::Expr, vtypes, sv::StaticVarInfo)
else
t = Any
end
for i = 2:length(e.args)
abstract_eval(e.args[i], vtypes, sv)
end
elseif is(e.head,:&)
abstract_eval(e.args[1], vtypes, sv)
t = Any
Expand Down
6 changes: 3 additions & 3 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
}
//TODO: check instead that prefix matches
//if (!jl_is_structtype(aty))
// emit_typecheck(emit_typeof(jv), (jl_value_t*)jl_struct_kind, "ccall: Struct argument called with something that isn't a CompositeKind", ctx);
// emit_typecheck(emit_typeof(jv), (jl_value_t*)jl_struct_kind, "ccall: Struct argument called with something that isn't a struct", ctx);
// //safe thing would be to also check that jl_typeof(aty)->size > sizeof(ty) here and/or at runtime
Value *pjv = builder.CreateBitCast(emit_nthptr_addr(jv, (size_t)1), PointerType::get(ty,0));
return builder.CreateLoad(pjv, false);
Expand All @@ -294,7 +294,7 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
msg << "ccall argument ";
msg << argn;
emit_typecheck(jv, jt, msg.str(), ctx);
Value *p = bitstype_pointer(jv);
Value *p = data_pointer(jv);
return builder.CreateLoad(builder.CreateBitCast(p,
PointerType::get(ty,0)),
false);
Expand Down Expand Up @@ -436,7 +436,7 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
std::stringstream msg;
msg << "ccall: the type of argument ";
msg << i+1;
msg << " doesn't correspond to a C type containing only BitsKinds";
msg << " doesn't correspond to a C type";
emit_error(msg.str(), ctx);
return literal_pointer_val(jl_nothing);
}
Expand Down
33 changes: 18 additions & 15 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ static Value *literal_pointer_val(void *p)

// --- mapping between julia and llvm types ---

static Type *julia_struct_to_llvm(jl_value_t *jt);

static Type *julia_type_to_llvm(jl_value_t *jt)
{
if (jt == (jl_value_t*)jl_bool_type) return T_int1;
Expand All @@ -81,6 +83,9 @@ static Type *julia_type_to_llvm(jl_value_t *jt)
if (nb == 64) return T_int64;
else return Type::getIntNTy(getGlobalContext(), nb);
}
if (jl_isbits(jt)) {
return julia_struct_to_llvm(jt);
}
if (jt == (jl_value_t*)jl_bottom_type) return T_void;
return jl_pvalue_llvmt;
}
Expand All @@ -99,15 +104,14 @@ static Type *julia_struct_to_llvm(jl_value_t *jt)
size_t i;
for(i = 0; i < ntypes; i++) {
jl_value_t *ty = jl_tupleref(jst->types, i);
Type *lty = julia_type_to_llvm(ty);
Type *lty = ty==(jl_value_t*)jl_bool_type ? T_int8 : julia_type_to_llvm(ty);
if (lty == jl_pvalue_llvmt)
return NULL;
latypes.push_back(lty);
}
jst->struct_decl = (void*)StructType::create(latypes, jst->name->name->name);
}
Type *t = (Type*)jst->struct_decl;
return t;
return (Type*)jst->struct_decl;
}
return julia_type_to_llvm(jt);
}
Expand Down Expand Up @@ -200,16 +204,16 @@ static jl_value_t *julia_type_of(Value *v)
return jl_typeid_to_type(id);
}

static Value *NoOpCast(Value *v)
static Value *NoOpInst(Value *v)
{
v = CastInst::Create(Instruction::BitCast, v, v->getType());
v = SelectInst::Create(ConstantInt::get(T_int1,1), v, v);
builder.Insert((Instruction*)v);
return v;
}

static Value *mark_julia_type(Value *v, jl_value_t *jt)
{
if (jt == (jl_value_t*)jl_any_type)
if (jt == (jl_value_t*)jl_any_type || v->getType()==jl_pvalue_llvmt)
return v;
if (has_julia_type(v)) {
if (julia_type_of(v) == jt)
Expand All @@ -219,7 +223,7 @@ static Value *mark_julia_type(Value *v, jl_value_t *jt)
return v;
}
if (dyn_cast<Instruction>(v) == NULL)
v = NoOpCast(v);
v = NoOpInst(v);
assert(dyn_cast<Instruction>(v));
char name[3];
int id = jl_type_to_typeid(jt);
Expand Down Expand Up @@ -252,7 +256,7 @@ static Value *emit_typeof(Value *p)
false);
return tt;
}
return literal_pointer_val(llvm_type_to_julia(p->getType()));
return literal_pointer_val(julia_type_of(p));
}

static void emit_error(const std::string &txt, jl_codectx_t *ctx)
Expand Down Expand Up @@ -434,7 +438,7 @@ static Value *typed_store(Value *ptr, Value *idx_0based, Value *rhs,
Type *elty = julia_type_to_llvm(jltype);
assert(elty != NULL);
if (elty==T_int1) { elty = T_int8; }
if (jl_is_bitstype(jltype))
if (jl_isbits(jltype))
rhs = emit_unbox(elty, PointerType::get(elty,0), rhs);
else
rhs = boxed(rhs);
Expand Down Expand Up @@ -574,7 +578,7 @@ static Value *emit_arrayptr(Value *t)
return emit_nthptr(t, 1);
}

static Value *bitstype_pointer(Value *x)
static Value *data_pointer(Value *x)
{
return builder.CreateGEP(builder.CreateBitCast(x, jl_ppvalue_llvmt),
ConstantInt::get(T_size, 1));
Expand Down Expand Up @@ -638,7 +642,7 @@ static Value *tpropagate(Value *a, Value *b)
static Value *init_bits_value(Value *newv, Value *jt, Type *t, Value *v)
{
builder.CreateStore(jt, builder.CreateBitCast(newv, jl_ppvalue_llvmt));
builder.CreateStore(v , builder.CreateBitCast(bitstype_pointer(newv),
builder.CreateStore(v , builder.CreateBitCast(data_pointer(newv),
PointerType::get(t,0)));
return newv;
}
Expand All @@ -649,7 +653,7 @@ static Value *allocate_box_dynamic(Value *jlty, int nb, Value *v)
if (v->getType()->isPointerTy()) {
v = builder.CreatePtrToInt(v, T_size);
}
size_t sz = sizeof(void*) + (nb+7)/8;
size_t sz = sizeof(void*) + nb;
Value *newv = builder.CreateCall(jlallocobj_func,
ConstantInt::get(T_size, sz));
// TODO: make sure this is rooted. I think it is.
Expand Down Expand Up @@ -695,12 +699,11 @@ static Value *boxed(Value *v, jl_value_t *jt)
if (jb == jl_uint64_type) return builder.CreateCall(box_uint64_func, v);
if (jb == jl_char_type) return builder.CreateCall(box_char_func, v);
// TODO: skip the call for constant arguments
if (!jl_is_bitstype(jt)) {
if (!jl_isbits(jt)) {
assert("Don't know how to box this type" && false);
return NULL;
}
int nb = jl_datatype_size(jt)*8;
return allocate_box_dynamic(literal_pointer_val(jt), nb, v);
return allocate_box_dynamic(literal_pointer_val(jt),jl_datatype_size(jt),v);
}


Expand Down
114 changes: 75 additions & 39 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ static void max_arg_depth(jl_value_t *expr, int32_t *max, int32_t *sp,
esc = true;
jl_expr_t *e = (jl_expr_t*)expr;
size_t i;
if (e->head == call_sym || e->head == call1_sym) {
if (e->head == call_sym || e->head == call1_sym || e->head == new_sym) {
int alen = jl_array_dim0(e->args);
int lastsp = *sp;
jl_value_t *f = jl_exprarg(e,0);
Expand Down Expand Up @@ -807,14 +807,24 @@ static Value *emit_getfield(jl_value_t *expr, jl_sym_t *name, jl_codectx_t *ctx)
if (jl_is_structtype(sty) && sty != jl_module_type && sty->uid != 0) {
size_t idx = jl_field_index(sty, name, 0);
if (idx != (size_t)-1) {
Value *strct = emit_expr(expr, ctx);
Value *addr =
builder.CreateGEP(builder.CreateBitCast(strct, T_pint8),
ConstantInt::get(T_size,
sty->fields[idx].offset + sizeof(void*)));
jl_value_t *jfty = jl_tupleref(sty->types, idx);
JL_GC_POP();
return typed_load(addr, ConstantInt::get(T_size, 0), jfty, ctx);
Value *strct = emit_expr(expr, ctx);
if (strct->getType() == jl_pvalue_llvmt) {
Value *addr =
builder.CreateGEP(builder.CreateBitCast(strct, T_pint8),
ConstantInt::get(T_size,
sty->fields[idx].offset + sizeof(void*)));
JL_GC_POP();
return typed_load(addr, ConstantInt::get(T_size, 0), jfty, ctx);
}
else {
Value *fldv = builder.
CreateExtractElement(strct,ConstantInt::get(T_int32, idx));
if (jfty == (jl_value_t*)jl_bool_type) {
fldv = builder.CreateTrunc(fldv, T_int1);
}
return mark_julia_type(fldv, jfty);
}
}
}
// TODO: attempt better codegen for approximate types, if the types
Expand All @@ -835,9 +845,9 @@ static Value *emit_getfield(jl_value_t *expr, jl_sym_t *name, jl_codectx_t *ctx)
}

static void emit_setfield(jl_datatype_t *sty, Value *strct, size_t idx,
Value *rhs, jl_codectx_t *ctx)
Value *rhs, jl_codectx_t *ctx, bool checked=true)
{
if (sty->mutabl) {
if (sty->mutabl || !checked) {
Value *addr =
builder.CreateGEP(builder.CreateBitCast(strct, T_pint8),
ConstantInt::get(T_size, sty->fields[idx].offset + sizeof(void*)));
Expand Down Expand Up @@ -1193,7 +1203,8 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs,
size_t nd = jl_is_long(ndp) ? jl_unbox_long(ndp) : 1;
Value *idx = emit_array_nd_index(ary, nd, &args[3], nargs-2, ctx);
typed_store(emit_arrayptr(ary), idx,
emit_unboxed(args[2],ctx), ety, ctx);
ety==(jl_value_t*)jl_any_type ? emit_expr(args[2],ctx) : emit_unboxed(args[2],ctx),
ety, ctx);
JL_GC_POP();
return ary;
}
Expand Down Expand Up @@ -1256,6 +1267,32 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs,
return NULL;
}

static Value *emit_jlcall(Value *theFptr, Value *theF, jl_value_t **args,
size_t nargs, jl_codectx_t *ctx)
{
// emit arguments
int argStart = ctx->argDepth;
for(size_t i=0; i < nargs; i++) {
Value *anArg = emit_expr(args[i], ctx);
// put into argument space
make_gcroot(boxed(anArg), ctx);
}

// call
Value *myargs;
if (ctx->argTemp != NULL && nargs > 0) {
myargs = builder.CreateGEP(ctx->argTemp,
ConstantInt::get(T_size, argStart+ctx->argSpaceOffs));
}
else {
myargs = Constant::getNullValue(jl_ppvalue_llvmt);
}
Value *result = builder.CreateCall3(theFptr, theF, myargs,
ConstantInt::get(T_int32,nargs));
ctx->argDepth = argStart;
return result;
}

static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx,
jl_value_t *expr)
{
Expand Down Expand Up @@ -1335,25 +1372,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx,
}
}
else {
// emit arguments
int argStart = ctx->argDepth;
for(size_t i=0; i < nargs; i++) {
Value *anArg = emit_expr(args[i+1], ctx);
// put into argument space
make_gcroot(boxed(anArg), ctx);
}

// call
Value *myargs;
if (ctx->argTemp != NULL && nargs > 0) {
myargs = builder.CreateGEP(ctx->argTemp,
ConstantInt::get(T_size, argStart+ctx->argSpaceOffs));
}
else {
myargs = Constant::getNullValue(jl_ppvalue_llvmt);
}
result = builder.CreateCall3(theFptr, theF, myargs,
ConstantInt::get(T_int32,nargs));
result = emit_jlcall(theFptr, theF, &args[1], nargs, ctx);
}

ctx->argDepth = last_depth;
Expand Down Expand Up @@ -1693,13 +1712,25 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed,
}
else if (head == new_sym) {
jl_value_t *ty = expr_type(args[0], ctx);
size_t nargs = jl_array_len(ex->args);
if (jl_is_type_type(ty) &&
jl_is_datatype(jl_tparam0(ty)) &&
jl_is_leaf_type(jl_tparam0(ty))) {
ty = jl_tparam0(ty);
jl_datatype_t *sty = (jl_datatype_t*)ty;
size_t nf = jl_tuple_len(sty->names);
if (nf > 0) {
if (jl_isbits(sty)) {
Type *lt = julia_type_to_llvm(ty);
Value *strct = UndefValue::get(lt);
for(size_t i=0; i < nf; i++) {
unsigned idx = i;
Type *fty = julia_type_to_llvm(jl_tupleref(sty->types,i));
strct = builder.
CreateInsertValue(strct, emit_unbox(fty, PointerType::get(fty,0), emit_unboxed(args[i+1],ctx)), ArrayRef<unsigned>(&idx,1));
}
return strct;
}
Value *strct =
builder.CreateCall(jlallocobj_func,
ConstantInt::get(T_size,
Expand All @@ -1711,6 +1742,12 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed,
emit_setfield(sty, strct, i, V_null, ctx);
}
}
make_gcroot(strct, ctx);
for(size_t i=1; i < nargs; i++) {
emit_setfield(sty, strct, i-1, emit_expr(args[i],ctx), ctx,
false);
}
ctx->argDepth--;
return strct;
}
else {
Expand All @@ -1720,7 +1757,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed,
}
}
Value *typ = emit_expr(args[0], ctx);
return builder.CreateCall(jlnew_func, typ);
return emit_jlcall(jlnew_func, typ, &args[1], nargs-1, ctx);
}
else if (head == exc_sym) {
return builder.CreateLoad(jlexc_var, true);
Expand Down Expand Up @@ -1764,8 +1801,7 @@ static bool store_unboxed_p(char *name, jl_codectx_t *ctx)
jl_value_t *jt = (*ctx->declTypes)[name];
// only store a variable unboxed if type inference has run, which
// checks that the variable is not referenced undefined.
return (ctx->linfo->inferred && jl_is_bitstype(jt) &&
jl_is_leaf_type(jt) &&
return (ctx->linfo->inferred && jl_isbits(jt) &&
// don't unbox intrinsics, since inference depends on their having
// stable addresses for table lookup.
jt != (jl_value_t*)jl_intrinsic_type && !(*ctx->isCaptured)[name]);
Expand Down Expand Up @@ -1817,7 +1853,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f)
ConstantInt::get(T_size, i));
Value *theArg = builder.CreateLoad(argPtr, false);
jl_value_t *ty = jl_tupleref(lam->specTypes, i);
if (jl_is_leaf_type(ty) && jl_is_bitstype(ty)) {
if (jl_is_leaf_type(ty) && jl_isbits(ty)) {
Type *lty = julia_type_to_llvm(ty);
assert(lty != NULL);
theArg = emit_unbox(lty, PointerType::get(lty,0), theArg);
Expand Down Expand Up @@ -2001,6 +2037,8 @@ static Function *emit_function(jl_lambda_info_t *lam)
dbuilder->createSubroutineType(fil,EltTypeArray),
false, true,
0, true, f);
//ios_printf(ios_stderr, "\n*** compiling %s at %s:%d\n\n",
// lam->name->name, filename.c_str(), lno);

BasicBlock *b0 = BasicBlock::Create(jl_LLVMContext, "top", f);
builder.SetInsertPoint(b0);
Expand Down Expand Up @@ -2543,11 +2581,9 @@ static void init_julia_llvm_env(Module *m)
jlthrow_line_func->setDoesNotReturn();

jlnew_func =
Function::Create(FunctionType::get(jl_pvalue_llvmt, args1_, false),
Function::ExternalLinkage,
"jl_new_struct_uninit", jl_Module);
jl_ExecutionEngine->addGlobalMapping(jlnew_func,
(void*)&jl_new_struct_uninit);
Function::Create(jl_func_sig, Function::ExternalLinkage,
"jl_new_structv", jl_Module);
jl_ExecutionEngine->addGlobalMapping(jlnew_func, (void*)&jl_new_structv);

std::vector<Type*> args2(0);
args2.push_back(T_pint8);
Expand Down
Loading

0 comments on commit 03ace87

Please sign in to comment.