From 9f2002c9d230fe76d39bc6faa2f1977ebfac2024 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sun, 11 Aug 2013 03:35:44 -0400 Subject: [PATCH 01/53] Pass tuples unboxed if possible --- base/boot.jl | 2 +- src/ccall.cpp | 176 +++++++++++++++- src/cgutils.cpp | 198 ++++++++++++++++-- src/codegen.cpp | 485 ++++++++++++++++++++++++++++----------------- src/gc.c | 8 +- src/intrinsics.cpp | 51 ++++- src/julia.expmap | 1 + src/julia.h | 5 +- 8 files changed, 702 insertions(+), 224 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index ec11c1ee58347..61ca38de2073c 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -145,7 +145,7 @@ export JULIA_HOME, nothing, Main, # intrinsics module Intrinsics - #ccall, cglobal, abs_float, add_float, add_int, and_int, ashr_int, + #ccall, cglobal, llvmcall, abs_float, add_float, add_int, and_int, ashr_int, #box, bswap_int, checked_fptosi, checked_fptoui, checked_sadd, #checked_smul, checked_ssub, checked_uadd, checked_umul, checked_usub, #nan_dom_err, copysign_float, ctlz_int, ctpop_int, cttz_int, diff --git a/src/ccall.cpp b/src/ccall.cpp index f7047171606fb..c157ca0ffa043 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -243,7 +243,7 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, { Type *vt = jv->getType(); if (ty == jl_pvalue_llvmt) { - return boxed(jv); + return boxed(jv,ctx); } else if (ty == vt && !addressOf) { return jv; @@ -269,7 +269,7 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, } } // error. box for error handling. - jv = boxed(jv); + jv = boxed(jv,ctx); } else if (jl_is_cpointer_type(jt)) { assert(ty->isPointerTy()); @@ -353,7 +353,7 @@ static native_sym_arg_t interpret_symbol_arg(jl_value_t *arg, jl_codectx_t *ctx, "cglobal: first argument not a pointer or valid constant expression", ctx); } - jl_ptr = emit_unbox(T_size, T_psize, arg1); + jl_ptr = emit_unbox(T_size, T_psize, arg1, ptr_ty); } void *fptr=NULL; @@ -491,6 +491,163 @@ static Value *emit_cglobal(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) return mark_julia_type(res, rt); } +// llvmcall(ir, (rettypes...), (argtypes...), args...) +static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) +{ + JL_NARGSV(llvmcall, 3) + jl_value_t *rt = NULL, *at = NULL; + JL_GC_PUSH2(&rt, &at); + { + JL_TRY { + at = jl_interpret_toplevel_expr_in(ctx->module, args[3], + &jl_tupleref(ctx->sp,0), + jl_tuple_len(ctx->sp)/2); + } + JL_CATCH { + jl_rethrow_with_add("error interpreting llvmcall return type"); + } + } + { + JL_TRY { + rt = jl_interpret_toplevel_expr_in(ctx->module, args[2], + &jl_tupleref(ctx->sp,0), + jl_tuple_len(ctx->sp)/2); + } + JL_CATCH { + jl_rethrow_with_add("error interpreting ccall argument tuple"); + } + } + JL_TYPECHK(llvmcall, type, rt); + JL_TYPECHK(llvmcall, tuple, at); + JL_TYPECHK(llvmcall, type, at); + int i = 1; + // Make sure to find a unique name + std::string ir_name; + while(true) { + std::stringstream name; + name << (ctx->f->getName().str()) << i++; + ir_name = name.str(); + if(jl_Module->getFunction(ir_name) == NULL) + break; + } + jl_value_t *ir = static_eval(args[1], ctx, true); + if (!jl_is_byte_string(ir)) + { + jl_error("First argument to llvmcall must be a string"); + } + + std::stringstream ir_stream; + + // Generate arguments + std::string arguments; + llvm::raw_string_ostream argstream(arguments); + jl_tuple_t *tt = (jl_tuple_t*)at; + size_t nargt = jl_tuple_len(tt); + Value *argvals[nargt]; + /* + * Semantics for arguments are as follows: + * If the argument type is immutable (including bitstype), we pass the loaded llvm value + * type. Otherwise we pass a pointer to a jl_value_t. + */ + for (size_t i = 0; i < nargt; ++i) + { + jl_value_t *tti = jl_tupleref(tt,i); + Type *t = julia_struct_to_llvm(tti); + t->print(argstream); + argstream << " "; + jl_value_t *argi = args[4+2*i]; + Value *arg; + bool needroot = false; + if (t == jl_pvalue_llvmt || !jl_isbits(tti)) { + arg = emit_expr(argi, ctx, true); + if (t == jl_pvalue_llvmt && arg->getType() != jl_pvalue_llvmt) { + arg = boxed(arg, ctx); + needroot = true; + } + } + else { + arg = emit_unboxed(argi, ctx); + if (jl_is_bitstype(expr_type(argi, ctx))) { + arg = emit_unbox(t, PointerType::get(t,0), arg, tti); + } + } + +#ifdef JL_GC_MARKSWEEP + // make sure args are rooted + if (t == jl_pvalue_llvmt && (needroot || might_need_root(argi))) { + make_gcroot(arg, ctx); + } +#endif + /* + static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, + jl_value_t *argex, bool addressOf, + int argn, jl_codectx_t *ctx, + bool *mightNeedTempSpace) */ + bool mightNeedTempSpace = false; + argvals[i] = julia_to_native(t,tti,arg,argi,false,i,ctx,&mightNeedTempSpace); + if ((i+1) != nargt) + argstream << ","; + } + + Type *rettype; + std::string rstring; + llvm::raw_string_ostream rtypename(rstring); + // Construct return type + if (!jl_is_tuple(rt)) { + rettype = julia_struct_to_llvm(rt); + rettype->print(rtypename); + } else + { + size_t nret = jl_tuple_len(rt); + if (nret == 0) { + rettype = T_void; + rettype->print(rtypename); + } else { + Type *rettypes[nret]; + rtypename << "{"; + for (size_t i = 0; i < nret; ++i) { + rettypes[i] = julia_struct_to_llvm(jl_tupleref(rt,i)); + rettypes[i]->print(rtypename); + if ((i+1) != nret) + rtypename << ","; + } + rtypename << "}"; + rettype = StructType::get(jl_LLVMContext,ArrayRef(&rettypes[0],nret)); + } + } + + ir_stream << "; Number of arguments: " << nargt << "\n" + << "define "<getFunction(ir_name); + /* + * It might be tempting to just try to set the Always inline attribute on the function + * and hope for the best. However, this doesn't work since that would require an inlining + * pass (which is a Call Graph pass and cannot be managed by a FunctionPassManager). Instead + * We are sneaky and call the inliner directly. This also has the benefit of looking exactly + * like we cut/pasted it in in `code_llvm` + */ + f->setLinkage(GlobalValue::LinkOnceODRLinkage); + f->dump(); + // the actual call + CallInst *inst = builder.CreateCall(f,ArrayRef(&argvals[0],nargt)); + InlineFunctionInfo info; + if (!InlineFunction(inst,info)) + jl_error("Failed to insert LLVM IR into function"); + + return literal_pointer_val(jl_nothing); +} + // --- code generator for ccall itself --- // ccall(pointer, rettype, (argtypes...), args...) @@ -670,7 +827,7 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) addressOf = true; argi = jl_exprarg(argi,0); } - Value *ary = boxed(emit_expr(argi, ctx)); + Value *ary = boxed(emit_expr(argi, ctx),ctx); JL_GC_POP(); return mark_julia_type( builder.CreateBitCast(emit_nthptr_addr(ary, addressOf?1:0),lrt), @@ -790,15 +947,13 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) if (largty == jl_pvalue_llvmt || largty->isStructTy()) { arg = emit_expr(argi, ctx, true); if (largty == jl_pvalue_llvmt && arg->getType() != jl_pvalue_llvmt) { - arg = boxed(arg); + arg = boxed(arg,ctx); needroot = true; } - } + } else { arg = emit_unboxed(argi, ctx); if (jl_is_bitstype(expr_type(argi, ctx))) { - Type *totype = addressOf ? largty->getContainedType(0) : largty; - Type *ptype = addressOf ? largty : PointerType::get(largty,0); Type *at = arg->getType(); if (at != jl_pvalue_llvmt && at != totype && !(at->isPointerTy() && jargty==(jl_value_t*)jl_voidpointer_type)) { @@ -806,7 +961,10 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) arg = UndefValue::get(totype); } else { - arg = emit_unbox(totype, ptype, arg); + if (addressOf) + arg = emit_unbox(largty->getContainedType(0), largty, arg, jargty); + else + arg = emit_unbox(largty, PointerType::get(largty,0), arg, jargty); } } } diff --git a/src/cgutils.cpp b/src/cgutils.cpp index a268a504fadae..b938a51f53b45 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -66,6 +66,35 @@ static Type *julia_type_to_llvm(jl_value_t *jt) { if (jt == (jl_value_t*)jl_bool_type) return T_int1; if (jt == (jl_value_t*)jl_bottom_type) return T_void; + if (jl_is_tuple(jt)) { + // Represent tuples as anonymous structs + size_t ntypes = jl_tuple_len(jt); + if (ntypes == 0) + return T_void; + bool purebits = true; + bool isvector = true; + Type *type = NULL; + for (size_t i = 0; i < ntypes; ++i) { + jl_value_t *elt = jl_tupleref(jt,i); + purebits &= jl_isbits(elt); + Type *newtype = julia_struct_to_llvm(elt); + if (type != NULL && type != newtype) + isvector = false; + type = newtype; + if (!purebits && !isvector) + break; + } + if (purebits) { + if (isvector) { + return VectorType::get(type,ntypes); + } else { + Type *types[ntypes]; + for (size_t i = 0; i < ntypes; ++i) + types[i] = julia_struct_to_llvm(jl_tupleref(jt,i)); + return StructType::get(jl_LLVMContext,ArrayRef(&types[0],ntypes)); + } + } + } if (!jl_is_leaf_type(jt)) return jl_pvalue_llvmt; if (jl_is_cpointer_type(jt)) { @@ -114,10 +143,9 @@ static Type *julia_struct_to_llvm(jl_value_t *jt) if (jst->struct_decl == NULL) { size_t ntypes = jl_tuple_len(jst->types); if (ntypes == 0) - return NULL; + return T_void; StructType *structdecl = StructType::create(getGlobalContext(), jst->name->name->name); jst->struct_decl = structdecl; - std::vector latypes(0); size_t i; for(i = 0; i < ntypes; i++) { @@ -195,8 +223,9 @@ static jl_value_t *jl_typeid_to_type(int i) static bool has_julia_type(Value *v) { - return ((dyn_cast(v) != NULL) && - ((Instruction*)v)->getMetadata("julia_type")!=NULL); + Instruction *inst = (dyn_cast(v)); + return (inst != NULL) && + (inst->getMetadata("julia_type")!=NULL); } static jl_value_t *julia_type_of_without_metadata(Value *v, bool err=true) @@ -346,7 +375,7 @@ static void null_pointer_check(Value *v, jl_codectx_t *ctx) jlundeferr_var, ctx); } -static Value *boxed(Value *v, jl_value_t *jt=NULL); +static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt=NULL); static void emit_type_error(Value *x, jl_value_t *type, const std::string &msg, jl_codectx_t *ctx) @@ -359,7 +388,7 @@ static void emit_type_error(Value *x, jl_value_t *type, const std::string &msg, ArrayRef(zeros)); builder.CreateCall4(jltypeerror_func, fname_val, msg_val, - literal_pointer_val(type), boxed(x)); + literal_pointer_val(type), boxed(x,ctx)); } static void emit_typecheck(Value *x, jl_value_t *type, const std::string &msg, @@ -460,7 +489,7 @@ static Value *typed_load(Value *ptr, Value *idx_0based, jl_value_t *jltype, return mark_julia_type(elt, jltype); } -static Value *emit_unbox(Type *to, Type *pto, Value *x); +static Value *emit_unbox(Type *to, Type *pto, 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) @@ -469,9 +498,9 @@ static Value *typed_store(Value *ptr, Value *idx_0based, Value *rhs, assert(elty != NULL); if (elty==T_int1) { elty = T_int8; } if (jl_isbits(jltype) && ((jl_datatype_t*)jltype)->size > 0) - rhs = emit_unbox(elty, PointerType::get(elty,0), rhs); + rhs = emit_unbox(elty, PointerType::get(elty,0), rhs, jltype); else - rhs = boxed(rhs); + rhs = boxed(rhs,ctx); Value *data = builder.CreateBitCast(ptr, PointerType::get(elty, 0)); return builder.CreateStore(rhs, builder.CreateGEP(data, idx_0based)); } @@ -559,16 +588,107 @@ static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx) static Value *emit_tuplelen(Value *t) { + if (t == NULL) + return ConstantInt::get(T_size,0); + Type *ty = t->getType(); + if (ty == jl_pvalue_llvmt) //boxed + { + #ifdef OVERLAP_TUPLE_LEN + Value *lenbits = emit_nthptr(t, (size_t)0); + return builder.CreateLShr(builder.CreatePtrToInt(lenbits, T_int64), + ConstantInt::get(T_int32, 52)); + #else + Value *lenbits = emit_nthptr(t, 1); + return builder.CreatePtrToInt(lenbits, T_size); + #endif + } else { //unboxed + if (ty->isStructTy()) { + StructType *st = dyn_cast(ty); + return ConstantInt::get(T_size,st->getNumElements()); + } else { + assert(ty->isVectorTy()); + VectorType *vt = dyn_cast(ty); + return ConstantInt::get(T_size,vt->getNumElements()); + } + } +} + +static Value *emit_tupleset(Value *tuple, Value *i, Value *x) +{ +#ifdef OVERLAP_TUPLE_LENCreateS + Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), + i); +#else + Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), + builder.CreateAdd(ConstantInt::get(T_size,1),i)); +#endif + return builder.CreateStore(x,slot); +} + +// Julia semantics +static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t *ctx) +{ + if (tuple == NULL) { + // A typecheck must have caught this one + //builder.CreateUnreachable(); + return NULL; + } + Type *ty = tuple->getType(); + if (ty == jl_pvalue_llvmt) //boxed + { #ifdef OVERLAP_TUPLE_LEN - Value *lenbits = emit_nthptr(t, (size_t)0); - return builder.CreateLShr(builder.CreatePtrToInt(lenbits, T_int64), - ConstantInt::get(T_int32, 52)); + Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt),i); #else - Value *lenbits = emit_nthptr(t, 1); - return builder.CreatePtrToInt(lenbits, T_size); + Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), + builder.CreateAdd(ConstantInt::get(T_size,1),i)); #endif + return builder.CreateLoad(slot); + } else { + if (ty->isVectorTy()) { + Type *ity = i->getType(); + assert(ity->isIntegerTy()); + IntegerType *iity = dyn_cast(ity); + // ExtractElement needs i32 *sigh* + if(iity->getBitWidth() > 32) + i = builder.CreateTrunc(i,T_int32); + else if(iity->getBitWidth() < 32) + i = builder.CreateZExt(i,T_int32); + return builder.CreateExtractElement(tuple,builder.CreateSub(i,ConstantInt::get(T_int32,1))); + } + ConstantInt *idx = dyn_cast(i); + if (idx != 0) + return builder.CreateExtractValue(tuple,ArrayRef((unsigned)idx->getZExtValue()-1)); + else + { + assert(ty->isStructTy()); + StructType *st = dyn_cast(ty); + size_t n = st->getNumElements(); + Value *ret = builder.CreateAlloca(jl_ppvalue_llvmt); + BasicBlock *after = BasicBlock::Create(getGlobalContext(),"after_switch",ctx->f); + BasicBlock *deflt = BasicBlock::Create(getGlobalContext(),"default_case",ctx->f); + // Create the switch + builder.CreateSwitch(i,deflt,n); + // Anything else is a bounds error + builder.SetInsertPoint(deflt); + builder.CreateCall2(jlthrow_line_func, jlboundserr_var, + ConstantInt::get(T_int32, ctx->lineno)); + builder.CreateUnreachable(); + // Now for the cases + for (size_t i = 1; i <= n; ++i) { + BasicBlock *blk = BasicBlock::Create(getGlobalContext(),"case",ctx->f); + builder.SetInsertPoint(blk); + Value *val = boxed(builder.CreateExtractValue(tuple,ArrayRef(i-1)),ctx,jl_tupleref(jt,i)); + builder.CreateStore(val,ret); + builder.CreateBr(after); + } + builder.SetInsertPoint(after); + return builder.CreateLoad(ret); + } + } } + + // emit length of vararg tuple static Value *emit_n_varargs(jl_codectx_t *ctx) { @@ -706,7 +826,7 @@ static Value *emit_array_nd_index(Value *a, jl_value_t *ex, size_t nd, jl_value_ } #endif for(size_t k=0; k < nidxs; k++) { - Value *ii = emit_unbox(T_size, T_psize, emit_unboxed(args[k], ctx)); + Value *ii = emit_unbox(T_size, T_psize, emit_unboxed(args[k], ctx), NULL); ii = builder.CreateSub(ii, ConstantInt::get(T_size, 1)); i = builder.CreateAdd(i, builder.CreateMul(ii, stride)); if (k < nidxs-1) { @@ -776,19 +896,61 @@ static Value *allocate_box_dynamic(Value *jlty, int nb, Value *v) return init_bits_value(newv, jlty, v->getType(), v); } +bool isGhostType(jl_value_t*); + // 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. -static Value *boxed(Value *v, jl_value_t *jt) -{ +static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) +{ + if (v == NULL || dyn_cast(v) != 0) { + if (jl_is_datatype(jt)) { + jl_datatype_t *jb = (jl_datatype_t*)jb; + if (jb->instance == NULL) + jl_new_struct_uninit(jb); + assert(jb->instance != NULL); + return literal_pointer_val((jl_value_t*)jb->instance); + } + else if (jl_is_tuple(jt)) { + assert(jl_tuple_len(jt) == 0); + return literal_pointer_val((jl_value_t*)jl_null); + } + // Type information might not be good enough, + if (v == NULL) + return literal_pointer_val((jl_value_t*)jl_null); + else + jt = julia_type_of(v); + assert(jl_is_datatype(jt)); + assert(isGhostType(jt)); + return literal_pointer_val((jl_value_t*)((jl_datatype_t*)jt)->instance); + } Type *t = v->getType(); if (t == jl_pvalue_llvmt) return v; if (t == T_void) return literal_pointer_val((jl_value_t*)jl_nothing); if (t == T_int1) return julia_bool(v); - if (jt == NULL) + if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) jt = julia_type_of(v); + if jl_is_tuple(jt) { + size_t n = jl_tuple_len(jt); + Value *tpl = builder.CreateCall(jl_alloc_tuple_func,ConstantInt::get(T_size,n)); + make_gcroot(tpl,ctx); + for (size_t i = 0; i < n; ++i) + { + jl_value_t *jti = jl_tupleref(jt,i); + Value *vi; + if (v->getType()->isStructTy()) { + vi = builder.CreateExtractValue(v,ArrayRef((unsigned)i)); + } else { + assert(v->getType()->isVectorTy()); + vi = builder.CreateExtractElement(v,ConstantInt::get(T_int32,i)); + } + emit_tupleset(tpl,ConstantInt::get(T_size,i+1),boxed(vi,ctx,jti)); + } + ctx->argDepth--; + return tpl; + } jl_datatype_t *jb = (jl_datatype_t*)jt; assert(jl_is_datatype(jb)); if (jb == jl_int8_type) diff --git a/src/codegen.cpp b/src/codegen.cpp index 4f60f140c948f..5cf3df8edcb4e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -68,6 +68,9 @@ #include "llvm/Support/FormattedStream.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Assembly/Parser.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/Transforms/Utils/Cloning.h" #include #include @@ -112,6 +115,7 @@ static ExecutionEngine *jl_ExecutionEngine; static DIBuilder *dbuilder; static std::map argNumberStrings; static FunctionPassManager *FPM; +static PassManager *PM; // types static Type *jl_value_llvmt; @@ -181,8 +185,10 @@ static Function *jlenter_func; static Function *jlleave_func; static Function *jlegal_func; static Function *jlallocobj_func; +static Function *jlalloc1w_func; static Function *jlalloc2w_func; static Function *jlalloc3w_func; +static Function *jl_alloc_tuple_func; static Function *setjmp_func; static Function *box_int8_func; static Function *box_uint8_func; @@ -253,14 +259,14 @@ static Function *to_function(jl_lambda_info_t *li, bool cstyle) assert(f != NULL); nested_compile = last_n_c; //f->dump(); - //verifyFunction(*f); + verifyFunction(*f); FPM->run(*f); //n_compile++; // print out the function's LLVM code //ios_printf(ios_stderr, "%s:%d\n", // ((jl_sym_t*)li->file)->name, li->line); //f->dump(); - //verifyFunction(*f); + verifyFunction(*f); if (old != NULL) { builder.SetInsertPoint(old); builder.SetCurrentDebugLocation(olddl); @@ -414,6 +420,7 @@ struct jl_varinfo_t { bool isSA; bool isVolatile; bool isArgument; + bool isGhost; // Has size 0 and is thus never actually allocated bool hasGCRoot; bool escapes; bool usedUndef; @@ -423,8 +430,8 @@ struct jl_varinfo_t { jl_varinfo_t() : memvalue(NULL), SAvalue(NULL), passedAs(NULL), closureidx(-1), isAssigned(true), isCaptured(false), isSA(false), isVolatile(false), - isArgument(false), hasGCRoot(false), escapes(true), usedUndef(false), - used(false), + isArgument(false), isGhost(false), hasGCRoot(false), escapes(true), + usedUndef(false), used(false), declType((jl_value_t*)jl_any_type), initExpr(NULL) { } @@ -466,6 +473,14 @@ typedef struct { int nReqArgs; int lineno; std::vector boundsCheck; +#ifdef JL_GC_MARKSWEEP + Instruction *gcframe = NULL; + Instruction *argSpaceInits = NULL; + StoreInst *storeFrameSize = NULL; +#endif + BasicBlock::iterator first_gcframe_inst; + BasicBlock::iterator last_gcframe_inst; + std::vector gc_frame_pops; } jl_codectx_t; static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool boxed=true, @@ -926,7 +941,7 @@ static Value *emit_lambda_closure(jl_value_t *expr, jl_codectx_t *ctx) val = vari.passedAs; assert(val != NULL); if (val->getType() != jl_pvalue_llvmt) { - val = boxed(val); + val = boxed(val,ctx); make_gcroot(val, ctx); } } @@ -1023,7 +1038,7 @@ static Value *emit_getfield(jl_value_t *expr, jl_sym_t *name, jl_codectx_t *ctx) JL_GC_POP(); int argStart = ctx->argDepth; - Value *arg1 = boxed(emit_expr(expr, ctx)); + Value *arg1 = boxed(emit_expr(expr, ctx),ctx); // TODO: generic getfield func with more efficient calling convention make_gcroot(arg1, ctx); Value *arg2 = literal_pointer_val((jl_value_t*)name); @@ -1045,7 +1060,7 @@ static void emit_setfield(jl_datatype_t *sty, Value *strct, size_t idx, ConstantInt::get(T_size, sty->fields[idx].offset + sizeof(void*))); jl_value_t *jfty = jl_tupleref(sty->types, idx); if (sty->fields[idx].isptr) { - builder.CreateStore(boxed(rhs), + builder.CreateStore(boxed(rhs,ctx), builder.CreateBitCast(addr, jl_ppvalue_llvmt)); } else { @@ -1122,7 +1137,7 @@ static Value *emit_f_is(jl_value_t *rt1, jl_value_t *rt2, } } } - varg1 = boxed(varg1); varg2 = boxed(varg2); + varg1 = boxed(varg1,ctx); varg2 = boxed(varg2,ctx); if (ptr_comparable) answer = builder.CreateICmpEQ(varg1, varg2); else @@ -1189,7 +1204,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, JL_GC_POP(); return literal_pointer_val(aty); } - arg1 = boxed(arg1); + arg1 = boxed(arg1,ctx); JL_GC_POP(); return emit_typeof(arg1); } @@ -1231,13 +1246,13 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, Value *arg1 = emit_expr(args[1], ctx); int ldepth = ctx->argDepth; if (arg1->getType() != jl_pvalue_llvmt) { - arg1 = boxed(arg1); + arg1 = boxed(arg1,ctx); make_gcroot(arg1, ctx); } else if (might_need_root(args[1])) { make_gcroot(arg1, ctx); } - builder.CreateCall2(typeassert, arg1, boxed(emit_expr(args[2], ctx))); + builder.CreateCall2(typeassert, arg1, boxed(emit_expr(args[2], ctx),ctx)); ctx->argDepth = ldepth; JL_GC_POP(); return arg1; @@ -1303,7 +1318,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, if (ctx->vaStack && symbol_eq(args[1], ctx->vaName)) { Value *valen = emit_n_varargs(ctx); Value *idx = emit_unbox(T_size, T_psize, - emit_unboxed(args[2], ctx)); + emit_unboxed(args[2], ctx),ity); idx = emit_bounds_check(idx, valen, ctx); idx = builder.CreateAdd(idx, ConstantInt::get(T_size, ctx->nReqArgs)); JL_GC_POP(); @@ -1319,11 +1334,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, if (idx > 0 && (idx < tlen || (idx == tlen && !isseqt))) { // known to be in bounds JL_GC_POP(); -#ifdef OVERLAP_TUPLE_LEN - return emit_nthptr(arg1, idx); -#else - return emit_nthptr(arg1, idx+1); -#endif + return emit_tupleref(arg1,ConstantInt::get(T_size,idx),tty,ctx); } if (idx==0 || (!isseqt && idx > tlen)) { builder.CreateCall2(jlthrow_line_func, @@ -1335,15 +1346,10 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, } Value *tlen = emit_tuplelen(arg1); Value *idx = emit_unbox(T_size, T_psize, - emit_unboxed(args[2], ctx)); + emit_unboxed(args[2], ctx), ity); emit_bounds_check(idx, tlen, ctx); JL_GC_POP(); -#ifdef OVERLAP_TUPLE_LEN - return emit_nthptr(arg1, idx); -#else - return emit_nthptr(arg1, - builder.CreateAdd(idx, ConstantInt::get(T_size,1))); -#endif + return emit_tupleref(arg1,idx,tty,ctx); } } else if (f->fptr == &jl_f_tuple) { @@ -1372,7 +1378,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, int last_depth = ctx->argDepth; // eval the first argument first, then do hand-over-hand to track the tuple. Value *arg1val = emit_expr(args[1], ctx); - Value *arg1 = boxed(arg1val); + Value *arg1 = boxed(arg1val,ctx); if (arg1val->getType() != jl_pvalue_llvmt || might_need_root(args[1])) make_gcroot(arg1, ctx); bool rooted = false; @@ -1422,7 +1428,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, make_gcroot(tup, ctx); rooted = true; } - Value *argi = boxed(argval); + Value *argi = boxed(argval,ctx); builder.CreateStore(argi, emit_nthptr_addr(tup, i+offs)); } ctx->argDepth = last_depth; @@ -1430,7 +1436,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, return tup; } else if (f->fptr == &jl_f_throw && nargs==1) { - Value *arg1 = boxed(emit_expr(args[1], ctx)); + Value *arg1 = boxed(emit_expr(args[1], ctx), ctx); JL_GC_POP(); builder.CreateCall2(jlthrow_line_func, arg1, ConstantInt::get(T_int32, ctx->lineno)); @@ -1466,7 +1472,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, } else { Value *idx = emit_unbox(T_size, T_psize, - emit_unboxed(args[2], ctx)); + emit_unboxed(args[2], ctx), ity); error_unless(builder.CreateICmpSGT(idx, ConstantInt::get(T_size,0)), "arraysize: dimension out of range", ctx); @@ -1614,6 +1620,16 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, return NULL; } +bool isGhostType(jl_value_t *jt) +{ + if (jl_is_tuple(jt) && jl_tuple_len(jt) == 0) + return true; + else if (jl_is_datatype(jt) && !jl_is_abstracttype(jt) && (jl_datatype_t*)(jt) != jl_sym_type && + !jl_is_array_type(jt) && jl_datatype_size(jt) == 0 && jl_tuple_len(((jl_datatype_t*)(jt))->names) == 0) + return true; + return false; +} + static Value *emit_jlcall(Value *theFptr, Value *theF, jl_value_t **args, size_t nargs, jl_codectx_t *ctx) { @@ -1622,7 +1638,7 @@ static Value *emit_jlcall(Value *theFptr, Value *theF, jl_value_t **args, for(size_t i=0; i < nargs; i++) { Value *anArg = emit_expr(args[i], ctx); // put into argument space - make_gcroot(boxed(anArg), ctx); + make_gcroot(boxed(anArg, ctx, expr_type(args[i],ctx)), ctx); } // call @@ -1670,7 +1686,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, } #ifdef JL_GC_MARKSWEEP if (!headIsGlobal && (jl_is_expr(a0) || jl_is_lambda_info(a0))) { - make_gcroot(boxed(theFunc), ctx); + make_gcroot(boxed(theFunc,ctx), ctx); } #endif if (hdtype!=(jl_value_t*)jl_function_type && @@ -1691,23 +1707,33 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, Value *result; if (f!=NULL && specialized && f->linfo!=NULL && f->linfo->cFunctionObject!=NULL) { // emit specialized call site - Value *argvals[nargs]; Function *cf = (Function*)f->linfo->cFunctionObject; FunctionType *cft = cf->getFunctionType(); + size_t nfargs = cft->getNumParams(); + Value *argvals[nfargs]; + unsigned idx = 0; for(size_t i=0; i < nargs; i++) { - Type *at = cft->getParamType(i); + Type *at = cft->getParamType(idx); + Type *et = julia_type_to_llvm(expr_type(args[i+1],ctx)); + if(et == T_void) { + // Still emit the expression in case it has side effects + emit_expr(args[i+1], ctx); + continue; + } if (at == jl_pvalue_llvmt) { - argvals[i] = boxed(emit_expr(args[i+1], ctx)); + argvals[idx] = boxed(emit_expr(args[i+1], ctx),ctx); if (might_need_root(args[i+1])) { - make_gcroot(argvals[i], ctx); + make_gcroot(argvals[idx], ctx); } } else { - argvals[i] = emit_unbox(at, PointerType::get(at,0), - emit_unboxed(args[i+1], ctx)); + assert(at == et); + argvals[idx] = emit_unbox(at, PointerType::get(at,0), + emit_unboxed(args[i+1], ctx), NULL); } + idx++; } - result = builder.CreateCall(cf, ArrayRef(&argvals[0],nargs)); + result = builder.CreateCall(cf, ArrayRef(&argvals[0],nfargs)); if (result->getType() == T_void) { result = literal_pointer_val((jl_value_t*)jl_nothing); } @@ -1776,6 +1802,7 @@ static Value *var_binding_pointer(jl_sym_t *s, jl_binding_t **pbnd, jl_varinfo_t &vi = ctx->vars[s]; if (vi.closureidx != -1) { int idx = vi.closureidx; + assert(((Value*)ctx->envArg)->getType() == jl_pvalue_llvmt); if (isBoxed(s, ctx)) { #ifdef OVERLAP_TUPLE_LEN return emit_nthptr_addr(emit_nthptr((Value*)ctx->envArg, idx+1), 1); @@ -1815,6 +1842,15 @@ static Value *emit_checked_var(Value *bp, jl_sym_t *name, jl_codectx_t *ctx) return v; } +static Value *ghostValue(jl_value_t *ty) +{ + if (jl_is_datatype(ty)) + { + return UndefValue::get(julia_struct_to_llvm(ty)); + } else + return NULL; +} + static Value *emit_var(jl_sym_t *sym, jl_value_t *ty, jl_codectx_t *ctx, bool isboxed) { bool isglobal = is_global(sym, ctx); @@ -1828,6 +1864,8 @@ static Value *emit_var(jl_sym_t *sym, jl_value_t *ty, jl_codectx_t *ctx, bool is } jl_binding_t *jbp=NULL; Value *bp = var_binding_pointer(sym, &jbp, false, ctx); + if(bp == NULL) + return NULL; assert(jbp != NULL); if (jbp->value != NULL) { if (jbp->constp) { @@ -1856,6 +1894,10 @@ static Value *emit_var(jl_sym_t *sym, jl_value_t *ty, jl_codectx_t *ctx, bool is jl_binding_t *jbp=NULL; Value *bp = var_binding_pointer(sym, &jbp, false, ctx); + if (bp == NULL) { + assert(vi.isGhost); + return ghostValue(ty); + } assert(jbp == NULL); if (arg != NULL || // arguments are always defined (!is_var_closed(sym, ctx) && @@ -1878,7 +1920,7 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx) Value *bp = var_binding_pointer(s, &bnd, true, ctx); Value *rval; if (bnd) { - rval = boxed(emit_expr(r, ctx, true)); + rval = boxed(emit_expr(r, ctx, true),ctx); builder.CreateCall2(jlcheckassign_func, literal_pointer_val((void*)bnd), rval); @@ -1894,10 +1936,10 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx) if (bp != NULL) { Type *vt = bp->getType(); if (vt->isPointerTy() && vt->getContainedType(0)!=jl_pvalue_llvmt) { - rval = emit_unbox(vt->getContainedType(0), vt, emit_unboxed(r, ctx)); + rval = emit_unbox(vt->getContainedType(0), vt, emit_unboxed(r, ctx), rt); } else { - rval = boxed(emit_expr(r, ctx, true)); + rval = boxed(emit_expr(r, ctx, true),ctx); } if (builder.GetInsertBlock()->getTerminator() == NULL) { builder.CreateStore(rval, bp, vi.isVolatile); @@ -2121,9 +2163,9 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, bp = var_binding_pointer((jl_sym_t*)mn, &bnd, false, ctx); } } - Value *a1 = boxed(emit_expr(args[1], ctx)); + Value *a1 = boxed(emit_expr(args[1], ctx),ctx); make_gcroot(a1, ctx); - Value *a2 = boxed(emit_expr(args[2], ctx)); + Value *a2 = boxed(emit_expr(args[2], ctx),ctx); make_gcroot(a2, ctx); Value *mdargs[5] = { name, bp, literal_pointer_val((void*)bnd), a1, a2 }; ctx->argDepth = last_depth; @@ -2168,14 +2210,18 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, Type *lt = julia_type_to_llvm(ty); Value *strct = UndefValue::get(lt); size_t na = nargs-1 < nf ? nargs-1 : nf; + unsigned idx = 0; for(size_t i=0; i < na; i++) { - unsigned idx = i; - Type *fty = julia_type_to_llvm(jl_tupleref(sty->types,i)); - Value *fval = emit_unbox(fty, PointerType::get(fty,0), emit_unboxed(args[i+1],ctx)); + jl_value_t *jtype = jl_tupleref(sty->types,i); + Type *fty = julia_type_to_llvm(jtype); + if(fty == T_void) + continue; + Value *fval = emit_unbox(fty, PointerType::get(fty,0), emit_unboxed(args[i+1],ctx), jtype); if (fty == T_int1) fval = builder.CreateZExt(fval, T_int8); strct = builder. CreateInsertValue(strct, fval, ArrayRef(&idx,1)); + idx++; } return mark_julia_type(strct,ty); } @@ -2192,7 +2238,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, // the first field to NULL, and sometimes the GC root // for the new struct. Value *fval = emit_expr(args[1],ctx); - f1 = boxed(fval); + f1 = boxed(fval,ctx); j++; if (might_need_root(args[1]) || fval->getType() != jl_pvalue_llvmt) make_gcroot(f1, ctx); @@ -2355,18 +2401,25 @@ static bool store_unboxed_p(jl_sym_t *s, jl_codectx_t *ctx) jt != (jl_value_t*)jl_intrinsic_type && !vi.isCaptured); } -static AllocaInst *alloc_local(jl_sym_t *s, jl_codectx_t *ctx) +static Value *alloc_local(jl_sym_t *s, jl_codectx_t *ctx) { jl_varinfo_t &vi = ctx->vars[s]; jl_value_t *jt = vi.declType; + Value *lv = NULL; Type *vtype=NULL; if (store_unboxed_p(s, ctx)) vtype = julia_type_to_llvm(jt); - if (vtype == NULL) - vtype = jl_pvalue_llvmt; - AllocaInst *lv = builder.CreateAlloca(vtype, 0, s->name); - if (vtype != jl_pvalue_llvmt) - mark_julia_type(lv, jt); + if (vtype != T_void) + { + if (vtype == NULL) + vtype = jl_pvalue_llvmt; + lv = builder.CreateAlloca(vtype, 0, s->name); + if (vtype != jl_pvalue_llvmt) + mark_julia_type(lv, jt); + vi.isGhost = false; + assert(lv != NULL); + } else + vi.isGhost = true; vi.memvalue = lv; return lv; } @@ -2393,6 +2446,110 @@ static void maybe_alloc_arrayvar(jl_sym_t *s, jl_codectx_t *ctx) // --- generate function bodies --- +extern char *jl_stack_lo; + +extern "C" jl_tuple_t *jl_tuple_tvars_to_symbols(jl_tuple_t *t); + +// gc frame emission +static void allocate_gc_frame(size_t n_roots, jl_codectx_t *ctx) +{ + ctx->argSpaceOffs = n_roots; + ctx->argDepth = 0; + ctx->maxDepth = 0; + +#ifdef JL_GC_MARKSWEEP + // allocate gc frame + ctx->argTemp = builder.CreateAlloca(jl_pvalue_llvmt, + ConstantInt::get(T_int32,n_roots+2)); + ctx->gcframe = (Instruction*)ctx->argTemp; + ctx->first_gcframe_inst = BasicBlock::iterator(ctx->gcframe); + ctx->argTemp = (Instruction*)builder.CreateConstGEP1_32(ctx->argTemp, 2); + ctx->storeFrameSize = + builder.CreateStore(ConstantInt::get(T_size, n_roots<<1), + builder.CreateBitCast(builder.CreateConstGEP1_32(ctx->gcframe, 0), T_psize)); + builder.CreateStore(builder.CreateLoad(jlpgcstack_var, false), + builder.CreateBitCast(builder.CreateConstGEP1_32(ctx->gcframe, 1), PointerType::get(jl_ppvalue_llvmt,0))); + Instruction *linst = builder.CreateStore(ctx->gcframe, jlpgcstack_var, false); + ctx->last_gcframe_inst = BasicBlock::iterator(linst); + // initialize local variable stack roots to null + for(size_t i=0; i < (size_t)ctx->argSpaceOffs; i++) { + Value *varSlot = builder.CreateConstGEP1_32(ctx->argTemp,i); + builder.CreateStore(V_null, varSlot); + } +#else + ctx.argTemp = builder.CreateAlloca(jl_pvalue_llvmt, + ConstantInt::get(T_int32, n_roots)); +#endif + +} + +static void finalize_gc_frame(jl_codectx_t *ctx) +{ + if (ctx->argSpaceOffs + ctx->maxDepth == 0) { + // 0 roots; remove gc frame entirely + // replace instruction uses with Undef first to avoid LLVM assertion failures + BasicBlock::iterator bbi = ctx->first_gcframe_inst; + while (1) { + Instruction &iii = *bbi; + iii.replaceAllUsesWith(UndefValue::get(iii.getType())); + if (bbi == ctx->last_gcframe_inst) break; + bbi++; + } + for(size_t i=0; i < ctx->gc_frame_pops.size(); i++) { + Instruction *pop = ctx->gc_frame_pops[i]; + BasicBlock::iterator pi(pop); + for(size_t j=0; j < 4; j++) { + Instruction &iii = *pi; + iii.replaceAllUsesWith(UndefValue::get(iii.getType())); + pi++; + } + } + + BasicBlock::InstListType &il = ctx->gcframe->getParent()->getInstList(); + il.erase(ctx->first_gcframe_inst, ctx->last_gcframe_inst); + // erase() erases up *to* the end point; erase last inst too + il.erase(ctx->last_gcframe_inst); + for(size_t i=0; i < ctx->gc_frame_pops.size(); i++) { + Instruction *pop = ctx->gc_frame_pops[i]; + BasicBlock::InstListType &il2 = pop->getParent()->getInstList(); + BasicBlock::iterator pi(pop); + for(size_t j=0; j < 4; j++) { + pi = il2.erase(pi); + } + } + } + else { + //n_frames++; + BasicBlock::iterator bbi(ctx->gcframe); + AllocaInst *newgcframe = + new AllocaInst(jl_pvalue_llvmt, + ConstantInt::get(T_int32, (ctx->argSpaceOffs + + ctx->maxDepth + 2))); + ReplaceInstWithInst(ctx->argTemp->getParent()->getInstList(), bbi, + newgcframe); + + BasicBlock::iterator bbi2(ctx->storeFrameSize); + StoreInst *newFrameSize = + new StoreInst(ConstantInt::get(T_size, (ctx->argSpaceOffs + + ctx->maxDepth)<<1), + ctx->storeFrameSize->getPointerOperand()); + ReplaceInstWithInst(ctx->storeFrameSize->getParent()->getInstList(), bbi2, + newFrameSize); + + BasicBlock::InstListType &instList = ctx->argSpaceInits->getParent()->getInstList(); + Instruction *after = ctx->argSpaceInits; + + for(size_t i=0; i < (size_t)ctx->maxDepth; i++) { + Instruction *argTempi = + GetElementPtrInst::Create(newgcframe, + ConstantInt::get(T_int32, i+ctx->argSpaceOffs+2)); + instList.insertAfter(after, argTempi); + after = new StoreInst(V_null, argTempi); + instList.insertAfter(argTempi, after); + } + } +} + // generate a julia-callable function that calls f (AKA lam) static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) { @@ -2408,37 +2565,55 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) DebugLoc noDbg; builder.SetCurrentDebugLocation(noDbg); + jl_codectx_t ctx; + allocate_gc_frame(0,&ctx); + ctx.argSpaceInits = &b0->back(); + size_t nargs = jl_tuple_len(lam->specTypes); - Value *args[nargs]; + size_t nfargs = f->getFunctionType()->getNumParams(); + Value *args[nfargs]; + unsigned argIdx = 0; + unsigned idx = 0; for(size_t i=0; i < nargs; i++) { + jl_value_t *ty = jl_tupleref(lam->specTypes, i); Value *argPtr = builder.CreateGEP(argArray, - ConstantInt::get(T_size, i)); + ConstantInt::get(T_size, argIdx)); Value *theArg = builder.CreateLoad(argPtr, false); - jl_value_t *ty = jl_tupleref(lam->specTypes, i); - if (jl_is_leaf_type(ty) && jl_isbits(ty) && - ((jl_datatype_t*)ty)->size > 0) { - Type *lty = julia_type_to_llvm(ty); + argIdx++; + if ((jl_is_leaf_type(ty) && jl_isbits(ty) && + ((jl_datatype_t*)ty)->size > 0)) { + Type *lty = julia_struct_to_llvm(ty); assert(lty != NULL); - theArg = emit_unbox(lty, PointerType::get(lty,0), theArg); + if (lty == T_void) + continue; + theArg = emit_unbox(lty, PointerType::get(lty,0), theArg, ty); + } else if(jl_is_tuple(ty)) + { + Type *lty = julia_struct_to_llvm(ty); + if (lty != jl_pvalue_llvmt) + { + if (lty == T_void) + continue; + theArg = emit_unbox(lty, PointerType::get(lty,0), theArg, ty); + } } - args[i] = theArg; + args[idx] = theArg; + idx++; } // TODO: consider pulling the function pointer out of fArg so these // wrappers can be reused for different functions of the same type. - Value *r = builder.CreateCall(f, ArrayRef(&args[0], nargs)); + Value *r = builder.CreateCall(f, ArrayRef(&args[0], nfargs)); if (r->getType() != jl_pvalue_llvmt) { - r = boxed(r, jl_ast_rettype(lam, lam->ast)); + r = boxed(r, &ctx, jl_ast_rettype(lam, lam->ast)); } + finalize_gc_frame(&ctx); builder.CreateRet(r); - return w; -} -extern char *jl_stack_lo; - -extern "C" jl_tuple_t *jl_tuple_tvars_to_symbols(jl_tuple_t *t); + //w->dump(); + verifyFunction(*w); -//static int total_roots=0; -//static int n_frames=0; + return w; +} // cstyle = compile with c-callable signature, not jlcall static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) @@ -2583,7 +2758,12 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) if (specsig) { std::vector fsig(0); for(size_t i=0; i < jl_tuple_len(lam->specTypes); i++) { - fsig.push_back(julia_type_to_llvm(jl_tupleref(lam->specTypes,i))); + Type *ty = julia_type_to_llvm(jl_tupleref(lam->specTypes,i)); + if (ty != T_void) + fsig.push_back(ty); + else { + ctx.vars[jl_decl_var(jl_cellref(largs,i))].isGhost = true; + } } Type *rt = (jlrettype == (jl_value_t*)jl_nothing->type ? T_void : julia_type_to_llvm(jlrettype)); f = Function::Create(FunctionType::get(rt, fsig, false), @@ -2747,41 +2927,8 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) } // step 8. set up GC frame - ctx.argSpaceOffs = n_roots; - ctx.argDepth = 0; - ctx.maxDepth = 0; -#ifdef JL_GC_MARKSWEEP - Instruction *gcframe = NULL; - Instruction *argSpaceInits = NULL; - StoreInst *storeFrameSize = NULL; -#endif - BasicBlock::iterator first_gcframe_inst; - BasicBlock::iterator last_gcframe_inst; - -#ifdef JL_GC_MARKSWEEP - // allocate gc frame - ctx.argTemp = builder.CreateAlloca(jl_pvalue_llvmt, - ConstantInt::get(T_int32,n_roots+2)); - gcframe = (Instruction*)ctx.argTemp; - first_gcframe_inst = BasicBlock::iterator(gcframe); - ctx.argTemp = (Instruction*)builder.CreateConstGEP1_32(ctx.argTemp, 2); - storeFrameSize = - builder.CreateStore(ConstantInt::get(T_size, n_roots<<1), - builder.CreateBitCast(builder.CreateConstGEP1_32(gcframe, 0), T_psize)); - builder.CreateStore(builder.CreateLoad(jlpgcstack_var, false), - builder.CreateBitCast(builder.CreateConstGEP1_32(gcframe, 1), PointerType::get(jl_ppvalue_llvmt,0))); - Instruction *linst = builder.CreateStore(gcframe, jlpgcstack_var, false); - last_gcframe_inst = BasicBlock::iterator(linst); - // initialize local variable stack roots to null - for(i=0; i < (size_t)ctx.argSpaceOffs; i++) { - Value *varSlot = builder.CreateConstGEP1_32(ctx.argTemp,i); - builder.CreateStore(V_null, varSlot); - } - argSpaceInits = &b0->back(); -#else - ctx.argTemp = builder.CreateAlloca(jl_pvalue_llvmt, - ConstantInt::get(T_int32, n_roots)); -#endif + allocate_gc_frame(n_roots, &ctx); + ctx.argSpaceInits = &b0->back(); // get pointers for locals stored in the gc frame array (argTemp) int varnum = 0; @@ -2836,7 +2983,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) // step 11. check arg count if (ctx.linfo->specTypes == NULL) { - if (va) { + if (va) { Value *enough = builder.CreateICmpUGE(argCount, ConstantInt::get(T_int32, nreq)); @@ -2870,44 +3017,56 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) // step 12. move args into local variables Function::arg_iterator AI = f->arg_begin(); + unsigned argIdx = 0; for(i=0; i < nreq; i++) { jl_sym_t *s = jl_decl_var(jl_cellref(largs,i)); - Value *argPtr; + Value *argPtr = NULL; if (specsig) { - argPtr = AI++; - argPtr = mark_julia_type(argPtr, jl_tupleref(lam->specTypes,i)); + if (!ctx.vars[s].isGhost) { + argPtr = AI++; + argPtr = mark_julia_type(argPtr, jl_tupleref(lam->specTypes,i)); + } } else { - argPtr = builder.CreateGEP(argArray, ConstantInt::get(T_size, i)); + argPtr = builder.CreateGEP(argArray, ConstantInt::get(T_size, argIdx)); + argIdx++; } - Value *theArg; + Value *theArg = NULL; if (specsig) theArg = argPtr; - else + else { + assert(argPtr != NULL); theArg = builder.CreateLoad(argPtr, false); + } + Value *lv = ctx.vars[s].memvalue; if (lv == NULL) { - // if this argument hasn't been given space yet, we've decided - // to leave it in the input argument array. - ctx.vars[s].passedAs = theArg; + if (ctx.vars[s].isGhost) { + ctx.vars[s].passedAs = NULL; + } else { + // if this argument hasn't been given space yet, we've decided + // to leave it in the input argument array. + ctx.vars[s].passedAs = theArg; + } } else { // keep track of original (boxed) value to avoid re-boxing ctx.vars[s].passedAs = theArg; if (isBoxed(s, &ctx)) { if (specsig) { - theArg = boxed(theArg); + theArg = boxed(theArg,&ctx); builder.CreateStore(theArg, lv); // temporarily root } builder.CreateStore(builder.CreateCall(jlbox_func, theArg), lv); } else if (dyn_cast(lv) != NULL) - builder.CreateStore(boxed(theArg), lv); + builder.CreateStore(boxed(theArg,&ctx), lv); else builder.CreateStore(emit_unbox(dyn_cast(lv)->getAllocatedType(), lv->getType(), - theArg), + theArg, + jl_tupleref(lam->specTypes,i)), lv); } // get arrayvar data if applicable @@ -2961,7 +3120,6 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) } // step 15. compile body statements - std::vector gc_frame_pops; bool prevlabel = false; for(i=0; i < stmtslen; i++) { jl_value_t *stmt = jl_cellref(stmts,i); @@ -2989,18 +3147,18 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) Value *retval; Type *retty = f->getReturnType(); if (retty == jl_pvalue_llvmt) { - retval = boxed(emit_expr(jl_exprarg(ex,0), &ctx, true)); + retval = boxed(emit_expr(jl_exprarg(ex,0), &ctx, true),&ctx); } else if (retty != T_void) { retval = emit_unbox(retty, PointerType::get(retty,0), - emit_unboxed(jl_exprarg(ex,0), &ctx)); + emit_unboxed(jl_exprarg(ex,0), &ctx), jlrettype); } else { retval = emit_expr(jl_exprarg(ex,0), &ctx, false); } #ifdef JL_GC_MARKSWEEP - Instruction *gcpop = (Instruction*)builder.CreateConstGEP1_32(gcframe, 1); - gc_frame_pops.push_back(gcpop); + Instruction *gcpop = (Instruction*)builder.CreateConstGEP1_32(ctx.gcframe, 1); + ctx.gc_frame_pops.push_back(gcpop); builder.CreateStore(builder.CreateBitCast(builder.CreateLoad(gcpop, false), jl_ppvalue_llvmt), jlpgcstack_var); #endif @@ -3027,69 +3185,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) // step 16. fix up size of stack root list //total_roots += (ctx.argSpaceOffs + ctx.maxDepth); - if (ctx.argSpaceOffs + ctx.maxDepth == 0) { - // 0 roots; remove gc frame entirely - // replace instruction uses with Undef first to avoid LLVM assertion failures - BasicBlock::iterator bbi = first_gcframe_inst; - while (1) { - Instruction &iii = *bbi; - iii.replaceAllUsesWith(UndefValue::get(iii.getType())); - if (bbi == last_gcframe_inst) break; - bbi++; - } - for(size_t i=0; i < gc_frame_pops.size(); i++) { - Instruction *pop = gc_frame_pops[i]; - BasicBlock::iterator pi(pop); - for(size_t j=0; j < 4; j++) { - Instruction &iii = *pi; - iii.replaceAllUsesWith(UndefValue::get(iii.getType())); - pi++; - } - } - - BasicBlock::InstListType &il = gcframe->getParent()->getInstList(); - il.erase(first_gcframe_inst, last_gcframe_inst); - // erase() erases up *to* the end point; erase last inst too - il.erase(last_gcframe_inst); - for(size_t i=0; i < gc_frame_pops.size(); i++) { - Instruction *pop = gc_frame_pops[i]; - BasicBlock::InstListType &il2 = pop->getParent()->getInstList(); - BasicBlock::iterator pi(pop); - for(size_t j=0; j < 4; j++) { - pi = il2.erase(pi); - } - } - } - else { - //n_frames++; - BasicBlock::iterator bbi(gcframe); - AllocaInst *newgcframe = - new AllocaInst(jl_pvalue_llvmt, - ConstantInt::get(T_int32, (ctx.argSpaceOffs + - ctx.maxDepth + 2))); - ReplaceInstWithInst(ctx.argTemp->getParent()->getInstList(), bbi, - newgcframe); - - BasicBlock::iterator bbi2(storeFrameSize); - StoreInst *newFrameSize = - new StoreInst(ConstantInt::get(T_size, (ctx.argSpaceOffs + - ctx.maxDepth)<<1), - storeFrameSize->getPointerOperand()); - ReplaceInstWithInst(storeFrameSize->getParent()->getInstList(), bbi2, - newFrameSize); - - BasicBlock::InstListType &instList = argSpaceInits->getParent()->getInstList(); - Instruction *after = argSpaceInits; - - for(i=0; i < (size_t)ctx.maxDepth; i++) { - Instruction *argTempi = - GetElementPtrInst::Create(newgcframe, - ConstantInt::get(T_int32, i+ctx.argSpaceOffs+2)); - instList.insertAfter(after, argTempi); - after = new StoreInst(V_null, argTempi); - instList.insertAfter(argTempi, after); - } - } + finalize_gc_frame(&ctx); JL_GC_POP(); return f; @@ -3388,6 +3484,12 @@ static void init_julia_llvm_env(Module *m) jl_ExecutionEngine->addGlobalMapping(jlallocobj_func, (void*)&allocobj); std::vector empty_args(0); + jlalloc1w_func = + Function::Create(FunctionType::get(jl_pvalue_llvmt, empty_args, false), + Function::ExternalLinkage, + "alloc_1w", jl_Module); + jl_ExecutionEngine->addGlobalMapping(jlalloc1w_func, (void*)&alloc_1w); + jlalloc2w_func = Function::Create(FunctionType::get(jl_pvalue_llvmt, empty_args, false), Function::ExternalLinkage, @@ -3400,6 +3502,14 @@ static void init_julia_llvm_env(Module *m) "alloc_3w", jl_Module); jl_ExecutionEngine->addGlobalMapping(jlalloc3w_func, (void*)&alloc_3w); + std::vector atargs(0); + atargs.push_back(T_size); + jl_alloc_tuple_func = + Function::Create(FunctionType::get(jl_pvalue_llvmt, atargs, false), + Function::ExternalLinkage, + "jl_alloc_tuple", jl_Module); + jl_ExecutionEngine->addGlobalMapping(jl_alloc_tuple_func, (void*)&jl_alloc_tuple); + std::vector puts_args(0); puts_args.push_back(T_pint8); puts_args.push_back(T_pint8); @@ -3411,11 +3521,14 @@ static void init_julia_llvm_env(Module *m) // set up optimization passes FPM = new FunctionPassManager(jl_Module); + PM = new PassManager(); + #ifdef LLVM32 FPM->add(new DataLayout(*jl_ExecutionEngine->getDataLayout())); #else FPM->add(new TargetData(*jl_ExecutionEngine->getTargetData())); #endif + // list of passes from vmkit FPM->add(createCFGSimplificationPass()); // Clean up disgusting code FPM->add(createPromoteMemoryToRegisterPass());// Kill useless allocas diff --git a/src/gc.c b/src/gc.c index ba6554914b0a2..1d587053a414b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -10,7 +10,7 @@ // with MEMDEBUG, every object is allocated explicitly with malloc, and // filled with 0xbb before being freed. -//#define MEMDEBUG +#define MEMDEBUG // MEMPROFILE prints pool summary statistics after every GC //#define MEMPROFILE @@ -991,6 +991,12 @@ void *allocobj(size_t sz) return pool_alloc(&pools[szclass(sz)]); } +void *alloc_1w(void) +{ + // For now + return allocobj(1); +} + void *alloc_2w(void) { #ifdef MEMDEBUG diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index a52354fc94226..b00596d6dc8c3 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -37,7 +37,7 @@ namespace JL_I { // pointer access pointerref, pointerset, pointertoref, // c interface - ccall, cglobal, jl_alloca + ccall, cglobal, jl_alloca, llvmcall }; }; @@ -163,7 +163,7 @@ static Value *emit_unboxed(jl_value_t *e, jl_codectx_t *ctx) } // emit code to unpack a raw value from a box -static Value *emit_unbox(Type *to, Type *pto, Value *x) +static Value *emit_unbox(Type *to, Type *pto, Value *x, jl_value_t *jt) { Type *ty = x->getType(); if (ty != jl_pvalue_llvmt) { @@ -185,6 +185,38 @@ static Value *emit_unbox(Type *to, Type *pto, Value *x) } return x; } + if (jt != NULL && jl_is_tuple(jt)) + { + if (to->isStructTy()) + { + StructType *st = dyn_cast(to); + // This is a tuple type + size_t n = st->getNumElements(); + assert(n == jl_tuple_len(jt)); + Value *tpl = UndefValue::get(to); + for(size_t i = 0; i < n; ++i) { + Type *ety = st->getElementType(i); + Value *elt = emit_unbox(ety,PointerType::get(ety,0), + emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL),jl_tupleref(jt,i)); + tpl = builder.CreateInsertValue(tpl,elt,ArrayRef(i)); + } + return tpl; + } else { + assert(to->isVectorTy()); + VectorType *vt = dyn_cast(to); + // This is a tuple type + size_t n = vt->getNumElements(); + assert(n == jl_tuple_len(jt)); + Value *tpl = UndefValue::get(to); + Type *ety = vt->getElementType(); + for (size_t i = 0; i < n; ++i) { + Value *elt = emit_unbox(ety,PointerType::get(ety,0), + emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL),jl_tupleref(jt,i)); + tpl = builder.CreateInsertElement(tpl,elt,ConstantInt::get(T_int32,i)); + } + return tpl; + } + } Value *p = data_pointer(x); if (to == T_int1) { // bools stored as int8, so an extra Trunc is needed to get an int1 @@ -225,7 +257,10 @@ static Value *auto_unbox(jl_value_t *x, jl_codectx_t *ctx) unsigned int nb = jl_datatype_size(bt)*8; to = IntegerType::get(jl_LLVMContext, nb); } - return emit_unbox(to, PointerType::get(to, 0), v); + if (to == T_void) { + return NULL; + } + return emit_unbox(to, PointerType::get(to, 0), v, bt); } // figure out how many bits a bitstype has at compile time, or -1 @@ -255,7 +290,7 @@ static Value *generic_unbox(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx) jl_value_t *p = jl_tparam0(et); if (jl_is_leaf_type(p)) { Type *to = julia_type_to_llvm(p); - return emit_unbox(to, PointerType::get(to,0), emit_unboxed(x,ctx)); + return emit_unbox(to, PointerType::get(to,0), emit_unboxed(x,ctx), p); } } int nb = try_to_determine_bitstype_nbits(targ, ctx); @@ -273,7 +308,7 @@ static Value *generic_unbox(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx) nb = (bt==(jl_value_t*)jl_bool_type) ? 1 : jl_datatype_size(bt)*8; } Type *to = IntegerType::get(jl_LLVMContext, nb); - return emit_unbox(to, PointerType::get(to, 0), emit_unboxed(x, ctx)); + return emit_unbox(to, PointerType::get(to, 0), emit_unboxed(x, ctx), et); } static Value *generic_box(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx) @@ -544,7 +579,7 @@ static Value *emit_pointerref(jl_value_t *e, jl_value_t *i, jl_codectx_t *ctx) jl_error("pointerref: invalid index type"); } Value *thePtr = auto_unbox(e,ctx); - Value *idx = emit_unbox(T_size, T_psize, emit_unboxed(i, ctx)); + Value *idx = emit_unbox(T_size, T_psize, emit_unboxed(i, ctx), (jl_value_t*)jl_long_type); Value *im1 = builder.CreateSub(idx, ConstantInt::get(T_size, 1)); if (!jl_isbits(ety)) { if (ety == (jl_value_t*)jl_any_type) @@ -585,7 +620,7 @@ static Value *emit_pointerset(jl_value_t *e, jl_value_t *x, jl_value_t *i, jl_co } if ((jl_datatype_t*)expr_type(i, ctx) != jl_long_type) jl_error("pointerset: invalid index type"); - Value *idx = emit_unbox(T_size, T_psize, emit_unboxed(i, ctx)); + Value *idx = emit_unbox(T_size, T_psize, emit_unboxed(i, ctx),(jl_value_t*)jl_long_type); Value *im1 = builder.CreateSub(idx, ConstantInt::get(T_size, 1)); Value *thePtr = auto_unbox(e,ctx); if (!jl_isbits(ety) && ety != (jl_value_t*)jl_any_type) { @@ -614,6 +649,7 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, switch (f) { case ccall: return emit_ccall(args, nargs, ctx); case cglobal: return emit_cglobal(args, nargs, ctx); + case llvmcall: return emit_llvmcall(args, nargs, ctx); HANDLE(box,2) return generic_box(args[1], args[2], ctx); HANDLE(unbox,2) return generic_unbox(args[1], args[2], ctx); @@ -1161,4 +1197,5 @@ extern "C" void jl_init_intrinsic_functions(void) ADD_I(nan_dom_err); ADD_I(ccall); ADD_I(cglobal); ADD_I(jl_alloca); + ADD_I(llvmcall); } diff --git a/src/julia.expmap b/src/julia.expmap index e1352c991ff17..114102a39ae21 100644 --- a/src/julia.expmap +++ b/src/julia.expmap @@ -50,6 +50,7 @@ jl_alloc_array_2d; jl_alloc_array_3d; jl_alloc_cell_1d; + jl_alloc_tuple; jl_cell_1d_push; jl_cell_1d_push2; jl_apply_generic; diff --git a/src/julia.h b/src/julia.h index b78d39f667d76..9414d707bf302 100644 --- a/src/julia.h +++ b/src/julia.h @@ -113,7 +113,7 @@ typedef struct { */ unsigned short how:2; unsigned short isshared:1; // data is shared by multiple Arrays - unsigned short isaligned:1; // data allocated with memalign + unsigned short isaligned:1; // data allocated with mem uint16_t elsize; uint32_t offset; // for 1-d only. does not need to get big. @@ -707,7 +707,7 @@ DLLEXPORT jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_tuple_t *spar jl_tuple_t *jl_tuple(size_t n, ...); jl_tuple_t *jl_tuple1(void *a); jl_tuple_t *jl_tuple2(void *a, void *b); -jl_tuple_t *jl_alloc_tuple(size_t n); +DLLEXPORT jl_tuple_t *jl_alloc_tuple(size_t n); jl_tuple_t *jl_alloc_tuple_uninit(size_t n); jl_tuple_t *jl_tuple_append(jl_tuple_t *a, jl_tuple_t *b); jl_tuple_t *jl_tuple_fill(size_t n, jl_value_t *v); @@ -1127,6 +1127,7 @@ void *jl_gc_managed_realloc(void *d, size_t sz, size_t oldsz, int isaligned); void jl_gc_free_array(jl_array_t *a); void jl_gc_track_malloced_array(jl_array_t *a); void jl_gc_run_all_finalizers(); +void *alloc_1w(void); void *alloc_2w(void); void *alloc_3w(void); void *alloc_4w(void); From 793562bd9608093bc329d135240ed2f9626ef6ea Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 12 Aug 2013 15:28:54 -0400 Subject: [PATCH 02/53] All tests pass --- base/fftw.jl | 2 +- src/cgutils.cpp | 125 +++++++++++++++++++++++++++++++++++++++------ src/codegen.cpp | 55 +++++++++++++++++--- src/intrinsics.cpp | 61 ++++++++++++---------- 4 files changed, 189 insertions(+), 54 deletions(-) diff --git a/base/fftw.jl b/base/fftw.jl index 5c7af7b648a46..d3aac272f9ac5 100644 --- a/base/fftw.jl +++ b/base/fftw.jl @@ -233,7 +233,7 @@ Plan{T<:fftwNumber}(plan::Ptr{Void}, X::StridedArray{T}) = Plan{T}(plan, size(X) # throw an informative error if not: function assert_applicable{T<:fftwNumber}(p::Plan{T}, X::StridedArray{T}) if size(X) != p.sz - throw(ArgumentError("FFTW plan applied to wrong-size array")) + throw(ArgumentError("FFTW plan applied to wrong-size array (expected $(p.sz), got $(size(X))")) elseif strides(X) != p.istride throw(ArgumentError("FFTW plan applied to wrong-strides array")) elseif alignment_of(X) != p.ialign diff --git a/src/cgutils.cpp b/src/cgutils.cpp index b938a51f53b45..25d715011ebd8 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -86,7 +86,12 @@ static Type *julia_type_to_llvm(jl_value_t *jt) } if (purebits) { if (isvector) { - return VectorType::get(type,ntypes); + Type *ret = NULL; + if (type->isSingleValueType()) + ret = VectorType::get(type,ntypes); + else + ret = ArrayType::get(type,ntypes); + return ret; } else { Type *types[ntypes]; for (size_t i = 0; i < ntypes; ++i) @@ -601,10 +606,13 @@ static Value *emit_tuplelen(Value *t) Value *lenbits = emit_nthptr(t, 1); return builder.CreatePtrToInt(lenbits, T_size); #endif - } else { //unboxed + } else { //unboxedAg if (ty->isStructTy()) { StructType *st = dyn_cast(ty); return ConstantInt::get(T_size,st->getNumElements()); + } else if (ty->isArrayTy()) { + ArrayType *at = dyn_cast(ty); + return ConstantInt::get(T_size,at->getNumElements()); } else { assert(ty->isVectorTy()); VectorType *vt = dyn_cast(ty); @@ -613,16 +621,83 @@ static Value *emit_tuplelen(Value *t) } } -static Value *emit_tupleset(Value *tuple, Value *i, Value *x) +static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl_codectx_t *ctx) { -#ifdef OVERLAP_TUPLE_LENCreateS - Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), - i); -#else - Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), - builder.CreateAdd(ConstantInt::get(T_size,1),i)); -#endif - return builder.CreateStore(x,slot); + if (tuple == NULL) { + // A typecheck must have caught this one + //builder.CreateUnreachable(); + return NULL; + } + Type *ty = tuple->getType(); + if (ty == jl_pvalue_llvmt) //boxed + { + #ifdef OVERLAP_TUPLE_LENCreateS + Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), + i); + #else + Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), + builder.CreateAdd(ConstantInt::get(T_size,1),i)); + #endif + builder.CreateStore(x,slot); + return tuple; + } else { + Value *ret = NULL; + if (ty->isVectorTy()) { + Type *ity = i->getType(); + assert(ity->isIntegerTy()); + IntegerType *iity = dyn_cast(ity); + // ExtractElement needs i32 *sigh* + if(iity->getBitWidth() > 32) + i = builder.CreateTrunc(i,T_int32); + 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 { + ConstantInt *idx = dyn_cast(i); + if (idx != 0) { + unsigned ci = (unsigned)idx->getZExtValue()-1; + ret = builder.CreateInsertValue(tuple,x,ArrayRef(ci)); + } + else if (ty->isArrayTy()) + { + ArrayType *at = dyn_cast(ty); + Value *tempSpace = builder.CreateAlloca(at); + builder.CreateStore(tuple,tempSpace); + Value *idxs[2]; + idxs[0] = ConstantInt::get(T_size,0); + idxs[1] = i; + builder.CreateStore(x,builder.CreateGEP(tempSpace,ArrayRef(&idxs[0],2))); + ret = builder.CreateLoad(tempSpace); + } + else + { + assert(ty->isStructTy()); + StructType *st = dyn_cast(ty); + size_t n = st->getNumElements(); + Value *ret = builder.CreateAlloca(st); + BasicBlock *after = BasicBlock::Create(getGlobalContext(),"after_switch",ctx->f); + BasicBlock *deflt = BasicBlock::Create(getGlobalContext(),"default_case",ctx->f); + // Create the switch + builder.CreateSwitch(i,deflt,n); + // Anything else is a bounds error + builder.SetInsertPoint(deflt); + builder.CreateCall2(jlthrow_line_func, jlboundserr_var, + ConstantInt::get(T_int32, ctx->lineno)); + builder.CreateUnreachable(); + // Now for the cases + for (size_t i = 1; i <= n; ++i) { + BasicBlock *blk = BasicBlock::Create(getGlobalContext(),"case",ctx->f); + builder.SetInsertPoint(blk); + Value *newAgg = builder.CreateInsertValue(tuple,x,ArrayRef(i-1)); + builder.CreateStore(newAgg,ret); + builder.CreateBr(after); + } + builder.SetInsertPoint(after); + ret = builder.CreateLoad(ret); + } + } + return mark_julia_type(ret,jt); + } } // Julia semantics @@ -656,8 +731,20 @@ static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t return builder.CreateExtractElement(tuple,builder.CreateSub(i,ConstantInt::get(T_int32,1))); } ConstantInt *idx = dyn_cast(i); - if (idx != 0) - return builder.CreateExtractValue(tuple,ArrayRef((unsigned)idx->getZExtValue()-1)); + if (idx != 0) { + unsigned ci = (unsigned)idx->getZExtValue()-1; + return mark_julia_type(builder.CreateExtractValue(tuple,ArrayRef(ci)),jl_tupleref(jt,ci)); + } + else if (ty->isArrayTy()) + { + ArrayType *at = dyn_cast(ty); + Value *tempSpace = builder.CreateAlloca(at); + builder.CreateStore(tuple,tempSpace); + Value *idxs[2]; + idxs[0] = ConstantInt::get(T_size,0); + idxs[1] = i; + return builder.CreateLoad(builder.CreateGEP(tempSpace,ArrayRef(&idxs[0],2))); + } else { assert(ty->isStructTy()); @@ -927,8 +1014,12 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) Type *t = v->getType(); if (t == jl_pvalue_llvmt) return v; - if (t == T_void) - return literal_pointer_val((jl_value_t*)jl_nothing); + if (t == T_void) { + if (jl_is_tuple(jt)) + return literal_pointer_val((jl_value_t*)jl_null); + else + return literal_pointer_val((jl_value_t*)jl_nothing); + } if (t == T_int1) return julia_bool(v); if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) jt = julia_type_of(v); @@ -940,13 +1031,13 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) { jl_value_t *jti = jl_tupleref(jt,i); Value *vi; - if (v->getType()->isStructTy()) { + if (v->getType()->isStructTy() || v->getType()->isArrayTy()) { vi = builder.CreateExtractValue(v,ArrayRef((unsigned)i)); } else { assert(v->getType()->isVectorTy()); vi = builder.CreateExtractElement(v,ConstantInt::get(T_int32,i)); } - emit_tupleset(tpl,ConstantInt::get(T_size,i+1),boxed(vi,ctx,jti)); + emit_tupleset(tpl,ConstantInt::get(T_size,i+1),boxed(vi,ctx,jti),jt,ctx); } ctx->argDepth--; return tpl; diff --git a/src/codegen.cpp b/src/codegen.cpp index 5cf3df8edcb4e..8510a10c97026 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -117,6 +117,12 @@ static std::map argNumberStrings; static FunctionPassManager *FPM; static PassManager *PM; +#ifdef LLVM32 +static DataLayout *jl_data_layout; +#else +static TargetData *jl_data_layout; +#endif + // types static Type *jl_value_llvmt; static Type *jl_pvalue_llvmt; @@ -1358,6 +1364,28 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, return literal_pointer_val((jl_value_t*)jl_null); } size_t i; + for(i=0; i < nargs; i++) { + jl_value_t *it = (jl_value_t*)expr_type(args[i+1],ctx); + if (!jl_isbits(it)) + break; + } + if (i >= nargs) { + // all arguments immutable; can be statically evaluated + jl_value_t *tt = (jl_value_t*)jl_alloc_tuple_uninit(nargs); + for(i=0; i < nargs; i++) { + jl_tupleset(tt, i, expr_type(args[i+1],ctx)); + } + Value *tpl = UndefValue::get(julia_type_to_llvm(tt)); + for (size_t i = 0; i < nargs; ++i) { + Type *ety = jl_llvmtuple_eltype(tpl->getType(),i); + Value *elt = emit_unbox(ety,PointerType::get(ety,0), + emit_expr(args[i+1],ctx,false),jl_tupleref(tt,i)); + tpl = emit_tupleset(tpl,ConstantInt::get(T_size,i+1),elt,tt,ctx); + } + JL_GC_POP(); + return tpl; + } + for(i=0; i < nargs; i++) { jl_value_t *it = (jl_value_t*)jl_typeof(args[i+1]); if (!(jl_is_immutable_datatype(it) && @@ -1365,7 +1393,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, break; } if (i >= nargs) { - // all arguments immutable; can be statically evaluated + // all arguments constant; can be statically evaluated rt1 = (jl_value_t*)jl_alloc_tuple_uninit(nargs); for(i=0; i < nargs; i++) { jl_tupleset(rt1, i, args[i+1]); @@ -1714,7 +1742,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, unsigned idx = 0; for(size_t i=0; i < nargs; i++) { Type *at = cft->getParamType(idx); - Type *et = julia_type_to_llvm(expr_type(args[i+1],ctx)); + Type *et = julia_type_to_llvm(jl_tupleref(f->linfo->specTypes,i)); if(et == T_void) { // Still emit the expression in case it has side effects emit_expr(args[i+1], ctx); @@ -1729,10 +1757,11 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, else { assert(at == et); argvals[idx] = emit_unbox(at, PointerType::get(at,0), - emit_unboxed(args[i+1], ctx), NULL); + emit_unboxed(args[i+1], ctx), expr_type(args[i+1],ctx)); } idx++; } + assert(idx == nfargs); result = builder.CreateCall(cf, ArrayRef(&argvals[0],nfargs)); if (result->getType() == T_void) { result = literal_pointer_val((jl_value_t*)jl_nothing); @@ -1939,7 +1968,7 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx) rval = emit_unbox(vt->getContainedType(0), vt, emit_unboxed(r, ctx), rt); } else { - rval = boxed(emit_expr(r, ctx, true),ctx); + rval = boxed(emit_expr(r, ctx, true),ctx,rt); } if (builder.GetInsertBlock()->getTerminator() == NULL) { builder.CreateStore(rval, bp, vi.isVolatile); @@ -2606,10 +2635,17 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) if (r->getType() != jl_pvalue_llvmt) { r = boxed(r, &ctx, jl_ast_rettype(lam, lam->ast)); } + + // gc pop. Usually this is done when we encounter the return statement + // but here we have to do it manually + Instruction *gcpop = (Instruction*)builder.CreateConstGEP1_32(ctx.gcframe, 1); + ctx.gc_frame_pops.push_back(gcpop); + builder.CreateStore(builder.CreateBitCast(builder.CreateLoad(gcpop, false), jl_ppvalue_llvmt), + jlpgcstack_var); + finalize_gc_frame(&ctx); builder.CreateRet(r); - //w->dump(); verifyFunction(*w); return w; @@ -3066,6 +3102,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) builder.CreateStore(emit_unbox(dyn_cast(lv)->getAllocatedType(), lv->getType(), theArg, + lam->specTypes == NULL ? NULL : jl_tupleref(lam->specTypes,i)), lv); } @@ -3147,7 +3184,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) Value *retval; Type *retty = f->getReturnType(); if (retty == jl_pvalue_llvmt) { - retval = boxed(emit_expr(jl_exprarg(ex,0), &ctx, true),&ctx); + retval = boxed(emit_expr(jl_exprarg(ex,0), &ctx, true),&ctx,expr_type(stmt,&ctx)); } else if (retty != T_void) { retval = emit_unbox(retty, PointerType::get(retty,0), @@ -3523,11 +3560,13 @@ static void init_julia_llvm_env(Module *m) FPM = new FunctionPassManager(jl_Module); PM = new PassManager(); + #ifdef LLVM32 - FPM->add(new DataLayout(*jl_ExecutionEngine->getDataLayout())); + jl_data_layout = new DataLayout(*jl_ExecutionEngine->getDataLayout()); #else - FPM->add(new TargetData(*jl_ExecutionEngine->getTargetData())); + jl_data_layout = new TargetData(*jl_ExecutionEngine->getTargetData()); #endif + FPM->add(jl_data_layout); // list of passes from vmkit FPM->add(createCFGSimplificationPass()); // Clean up disgusting code diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index b00596d6dc8c3..dbcd6acbf7148 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -162,6 +162,19 @@ static Value *emit_unboxed(jl_value_t *e, jl_codectx_t *ctx) return emit_expr(e, ctx, false); } +static Type *jl_llvmtuple_eltype(Type *tuple, size_t i) +{ + Type *ety = NULL; + if (tuple->isStructTy()) + ety = dyn_cast(tuple)->getElementType(i); + else if(tuple->isArrayTy()) + ety = dyn_cast(tuple)->getElementType(); + else if(tuple->isVectorTy()) + ety = dyn_cast(tuple)->getElementType(); + else + assert(false); + return ety; +} // emit code to unpack a raw value from a box static Value *emit_unbox(Type *to, Type *pto, Value *x, jl_value_t *jt) { @@ -185,37 +198,29 @@ static Value *emit_unbox(Type *to, Type *pto, Value *x, jl_value_t *jt) } return x; } - if (jt != NULL && jl_is_tuple(jt)) + if ( (jt != NULL && jl_is_tuple(jt)) || to->isVectorTy() || to->isArrayTy() || + (to->isStructTy() && dyn_cast(to)->isLiteral()) ) { + assert(jt != 0); + assert(jl_is_tuple(jt)); + Value *tpl = UndefValue::get(to); + size_t n; if (to->isStructTy()) - { - StructType *st = dyn_cast(to); - // This is a tuple type - size_t n = st->getNumElements(); - assert(n == jl_tuple_len(jt)); - Value *tpl = UndefValue::get(to); - for(size_t i = 0; i < n; ++i) { - Type *ety = st->getElementType(i); - Value *elt = emit_unbox(ety,PointerType::get(ety,0), - emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL),jl_tupleref(jt,i)); - tpl = builder.CreateInsertValue(tpl,elt,ArrayRef(i)); - } - return tpl; - } else { - assert(to->isVectorTy()); - VectorType *vt = dyn_cast(to); - // This is a tuple type - size_t n = vt->getNumElements(); - assert(n == jl_tuple_len(jt)); - Value *tpl = UndefValue::get(to); - Type *ety = vt->getElementType(); - for (size_t i = 0; i < n; ++i) { - Value *elt = emit_unbox(ety,PointerType::get(ety,0), - emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL),jl_tupleref(jt,i)); - tpl = builder.CreateInsertElement(tpl,elt,ConstantInt::get(T_int32,i)); - } - return tpl; + n = dyn_cast(to)->getNumElements(); + else if(to->isArrayTy()) + n = dyn_cast(to)->getNumElements(); + else if(to->isVectorTy()) + n = dyn_cast(to)->getNumElements(); + else + assert(false); + assert(n == jl_tuple_len(jt)); + for (size_t i = 0; i < n; ++i) { + Type *ety = jl_llvmtuple_eltype(to,i); + Value *elt = emit_unbox(ety,PointerType::get(ety,0), + emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL),jl_tupleref(jt,i)); + tpl = emit_tupleset(tpl,ConstantInt::get(T_size,i+1),elt,jt,NULL); } + return tpl; } Value *p = data_pointer(x); if (to == T_int1) { From 9bfd041690649f7171ae6176774f8de3d8ad3780 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 12 Aug 2013 15:59:58 -0400 Subject: [PATCH 03/53] Specialize more functions --- src/cgutils.cpp | 1 + src/codegen.cpp | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 25d715011ebd8..1b885d68c8a13 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -757,6 +757,7 @@ static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t builder.CreateSwitch(i,deflt,n); // Anything else is a bounds error builder.SetInsertPoint(deflt); + jlthrow_line_func->dump(); builder.CreateCall2(jlthrow_line_func, jlboundserr_var, ConstantInt::get(T_int32, ctx->lineno)); builder.CreateUnreachable(); diff --git a/src/codegen.cpp b/src/codegen.cpp index 8510a10c97026..9ec4b2c2168b5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1379,7 +1379,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, for (size_t i = 0; i < nargs; ++i) { Type *ety = jl_llvmtuple_eltype(tpl->getType(),i); Value *elt = emit_unbox(ety,PointerType::get(ety,0), - emit_expr(args[i+1],ctx,false),jl_tupleref(tt,i)); + emit_unboxed(args[i+1],ctx),jl_tupleref(tt,i)); tpl = emit_tupleset(tpl,ConstantInt::get(T_size,i+1),elt,tt,ctx); } JL_GC_POP(); @@ -2579,6 +2579,17 @@ static void finalize_gc_frame(jl_codectx_t *ctx) } } +static bool jltupleisbits(jl_value_t *jt) +{ + if (!jl_is_tuple(jt)) + return jl_isbits(jt); + size_t ntypes = jl_tuple_len(jt); + for (size_t i = 0; i < ntypes; ++i) + if (!jltupleisbits(jl_tupleref(jt,i))) + return false; + return true; +} + // generate a julia-callable function that calls f (AKA lam) static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) { @@ -2775,14 +2786,14 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) // no captured vars and not vararg // consider specialized signature for(size_t i=0; i < jl_tuple_len(lam->specTypes); i++) { - if (jl_isbits(jl_tupleref(lam->specTypes, i))) { + if (jltupleisbits(jl_tupleref(lam->specTypes, i))) { specsig = true; break; } } if (jl_tuple_len(lam->specTypes) == 0) specsig = true; - if (jl_isbits(jlrettype)) + if (jltupleisbits(jlrettype)) specsig = true; } } From 491731270ac22168498cb094552f57a378f54455 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 12 Aug 2013 23:42:27 -0400 Subject: [PATCH 04/53] bugfixes --- src/cgutils.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 1b885d68c8a13..1808eccd0edbd 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -665,7 +665,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl builder.CreateStore(tuple,tempSpace); Value *idxs[2]; idxs[0] = ConstantInt::get(T_size,0); - idxs[1] = i; + idxs[1] = builder.CreateSub(i,ConstantInt::get(T_size,1)); builder.CreateStore(x,builder.CreateGEP(tempSpace,ArrayRef(&idxs[0],2))); ret = builder.CreateLoad(tempSpace); } @@ -678,10 +678,10 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl BasicBlock *after = BasicBlock::Create(getGlobalContext(),"after_switch",ctx->f); BasicBlock *deflt = BasicBlock::Create(getGlobalContext(),"default_case",ctx->f); // Create the switch - builder.CreateSwitch(i,deflt,n); + SwitchInst *sw = builder.CreateSwitch(i,deflt,n); // Anything else is a bounds error builder.SetInsertPoint(deflt); - builder.CreateCall2(jlthrow_line_func, jlboundserr_var, + builder.CreateCall2(jlthrow_line_func, builder.CreateLoad(jlboundserr_var), ConstantInt::get(T_int32, ctx->lineno)); builder.CreateUnreachable(); // Now for the cases @@ -691,6 +691,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl Value *newAgg = builder.CreateInsertValue(tuple,x,ArrayRef(i-1)); builder.CreateStore(newAgg,ret); builder.CreateBr(after); + sw->addCase(ConstantInt::get((IntegerType*)T_size,i),blk); } builder.SetInsertPoint(after); ret = builder.CreateLoad(ret); @@ -742,7 +743,7 @@ static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t builder.CreateStore(tuple,tempSpace); Value *idxs[2]; idxs[0] = ConstantInt::get(T_size,0); - idxs[1] = i; + idxs[1] = builder.CreateSub(i,ConstantInt::get(T_size,1)); return builder.CreateLoad(builder.CreateGEP(tempSpace,ArrayRef(&idxs[0],2))); } else @@ -750,22 +751,22 @@ static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t assert(ty->isStructTy()); StructType *st = dyn_cast(ty); size_t n = st->getNumElements(); - Value *ret = builder.CreateAlloca(jl_ppvalue_llvmt); + 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 - builder.CreateSwitch(i,deflt,n); + SwitchInst *sw = builder.CreateSwitch(i,deflt,n); // Anything else is a bounds error builder.SetInsertPoint(deflt); - jlthrow_line_func->dump(); - builder.CreateCall2(jlthrow_line_func, jlboundserr_var, + 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 = 1; i <= n; ++i) { BasicBlock *blk = BasicBlock::Create(getGlobalContext(),"case",ctx->f); + sw->addCase(ConstantInt::get((IntegerType*)T_size,i),blk); builder.SetInsertPoint(blk); - Value *val = boxed(builder.CreateExtractValue(tuple,ArrayRef(i-1)),ctx,jl_tupleref(jt,i)); + Value *val = boxed(builder.CreateExtractValue(tuple,ArrayRef(i-1)),ctx,jl_tupleref(jt,i-1)); builder.CreateStore(val,ret); builder.CreateBr(after); } From 2ffa794fa3d11100a810db39a6c4727571e3cbc9 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 13 Aug 2013 00:02:03 -0400 Subject: [PATCH 05/53] Remove unnessecary pto argument from emit_unbox --- src/ccall.cpp | 8 ++++---- src/cgutils.cpp | 6 +++--- src/codegen.cpp | 21 ++++++++++----------- src/intrinsics.cpp | 16 ++++++++-------- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index c157ca0ffa043..2003f7a989c5b 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -353,7 +353,7 @@ static native_sym_arg_t interpret_symbol_arg(jl_value_t *arg, jl_codectx_t *ctx, "cglobal: first argument not a pointer or valid constant expression", ctx); } - jl_ptr = emit_unbox(T_size, T_psize, arg1, ptr_ty); + jl_ptr = emit_unbox(T_size, arg1, ptr_ty); } void *fptr=NULL; @@ -568,7 +568,7 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) else { arg = emit_unboxed(argi, ctx); if (jl_is_bitstype(expr_type(argi, ctx))) { - arg = emit_unbox(t, PointerType::get(t,0), arg, tti); + arg = emit_unbox(t, arg, tti); } } @@ -962,9 +962,9 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) } else { if (addressOf) - arg = emit_unbox(largty->getContainedType(0), largty, arg, jargty); + arg = emit_unbox(largty->getContainedType(0), arg, jargty); else - arg = emit_unbox(largty, PointerType::get(largty,0), arg, jargty); + arg = emit_unbox(largty, arg, jargty); } } } diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 1808eccd0edbd..c138c4d9f51b7 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -494,7 +494,7 @@ static Value *typed_load(Value *ptr, Value *idx_0based, jl_value_t *jltype, return mark_julia_type(elt, jltype); } -static Value *emit_unbox(Type *to, Type *pto, Value *x, jl_value_t *jt); +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) @@ -503,7 +503,7 @@ static Value *typed_store(Value *ptr, Value *idx_0based, Value *rhs, assert(elty != NULL); if (elty==T_int1) { elty = T_int8; } if (jl_isbits(jltype) && ((jl_datatype_t*)jltype)->size > 0) - rhs = emit_unbox(elty, PointerType::get(elty,0), rhs, jltype); + rhs = emit_unbox(elty, rhs, jltype); else rhs = boxed(rhs,ctx); Value *data = builder.CreateBitCast(ptr, PointerType::get(elty, 0)); @@ -915,7 +915,7 @@ static Value *emit_array_nd_index(Value *a, jl_value_t *ex, size_t nd, jl_value_ } #endif for(size_t k=0; k < nidxs; k++) { - Value *ii = emit_unbox(T_size, T_psize, emit_unboxed(args[k], ctx), NULL); + Value *ii = emit_unbox(T_size, emit_unboxed(args[k], ctx), NULL); ii = builder.CreateSub(ii, ConstantInt::get(T_size, 1)); i = builder.CreateAdd(i, builder.CreateMul(ii, stride)); if (k < nidxs-1) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 9ec4b2c2168b5..b1fb6047f72a6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1323,7 +1323,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, if (jl_is_tuple(tty) && ity==(jl_value_t*)jl_long_type) { if (ctx->vaStack && symbol_eq(args[1], ctx->vaName)) { Value *valen = emit_n_varargs(ctx); - Value *idx = emit_unbox(T_size, T_psize, + Value *idx = emit_unbox(T_size, emit_unboxed(args[2], ctx),ity); idx = emit_bounds_check(idx, valen, ctx); idx = builder.CreateAdd(idx, ConstantInt::get(T_size, ctx->nReqArgs)); @@ -1351,7 +1351,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, } } Value *tlen = emit_tuplelen(arg1); - Value *idx = emit_unbox(T_size, T_psize, + Value *idx = emit_unbox(T_size, emit_unboxed(args[2], ctx), ity); emit_bounds_check(idx, tlen, ctx); JL_GC_POP(); @@ -1378,7 +1378,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, Value *tpl = UndefValue::get(julia_type_to_llvm(tt)); for (size_t i = 0; i < nargs; ++i) { Type *ety = jl_llvmtuple_eltype(tpl->getType(),i); - Value *elt = emit_unbox(ety,PointerType::get(ety,0), + Value *elt = emit_unbox(ety, emit_unboxed(args[i+1],ctx),jl_tupleref(tt,i)); tpl = emit_tupleset(tpl,ConstantInt::get(T_size,i+1),elt,tt,ctx); } @@ -1499,7 +1499,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, } } else { - Value *idx = emit_unbox(T_size, T_psize, + Value *idx = emit_unbox(T_size, emit_unboxed(args[2], ctx), ity); error_unless(builder.CreateICmpSGT(idx, ConstantInt::get(T_size,0)), @@ -1756,7 +1756,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, } else { assert(at == et); - argvals[idx] = emit_unbox(at, PointerType::get(at,0), + argvals[idx] = emit_unbox(at, emit_unboxed(args[i+1], ctx), expr_type(args[i+1],ctx)); } idx++; @@ -1965,7 +1965,7 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx) if (bp != NULL) { Type *vt = bp->getType(); if (vt->isPointerTy() && vt->getContainedType(0)!=jl_pvalue_llvmt) { - rval = emit_unbox(vt->getContainedType(0), vt, emit_unboxed(r, ctx), rt); + rval = emit_unbox(vt->getContainedType(0), emit_unboxed(r, ctx), rt); } else { rval = boxed(emit_expr(r, ctx, true),ctx,rt); @@ -2245,7 +2245,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, Type *fty = julia_type_to_llvm(jtype); if(fty == T_void) continue; - Value *fval = emit_unbox(fty, PointerType::get(fty,0), emit_unboxed(args[i+1],ctx), jtype); + Value *fval = emit_unbox(fty, emit_unboxed(args[i+1],ctx), jtype); if (fty == T_int1) fval = builder.CreateZExt(fval, T_int8); strct = builder. @@ -2626,7 +2626,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) assert(lty != NULL); if (lty == T_void) continue; - theArg = emit_unbox(lty, PointerType::get(lty,0), theArg, ty); + theArg = emit_unbox(lty, theArg, ty); } else if(jl_is_tuple(ty)) { Type *lty = julia_struct_to_llvm(ty); @@ -2634,7 +2634,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) { if (lty == T_void) continue; - theArg = emit_unbox(lty, PointerType::get(lty,0), theArg, ty); + theArg = emit_unbox(lty, theArg, ty); } } args[idx] = theArg; @@ -3111,7 +3111,6 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) builder.CreateStore(boxed(theArg,&ctx), lv); else builder.CreateStore(emit_unbox(dyn_cast(lv)->getAllocatedType(), - lv->getType(), theArg, lam->specTypes == NULL ? NULL : jl_tupleref(lam->specTypes,i)), @@ -3198,7 +3197,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) retval = boxed(emit_expr(jl_exprarg(ex,0), &ctx, true),&ctx,expr_type(stmt,&ctx)); } else if (retty != T_void) { - retval = emit_unbox(retty, PointerType::get(retty,0), + retval = emit_unbox(retty, emit_unboxed(jl_exprarg(ex,0), &ctx), jlrettype); } else { diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index dbcd6acbf7148..a1065132c6886 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -176,7 +176,7 @@ static Type *jl_llvmtuple_eltype(Type *tuple, size_t i) return ety; } // emit code to unpack a raw value from a box -static Value *emit_unbox(Type *to, Type *pto, Value *x, jl_value_t *jt) +static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt) { Type *ty = x->getType(); if (ty != jl_pvalue_llvmt) { @@ -216,7 +216,7 @@ static Value *emit_unbox(Type *to, Type *pto, Value *x, jl_value_t *jt) assert(n == jl_tuple_len(jt)); for (size_t i = 0; i < n; ++i) { Type *ety = jl_llvmtuple_eltype(to,i); - Value *elt = emit_unbox(ety,PointerType::get(ety,0), + Value *elt = emit_unbox(ety, emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL),jl_tupleref(jt,i)); tpl = emit_tupleset(tpl,ConstantInt::get(T_size,i+1),elt,jt,NULL); } @@ -234,7 +234,7 @@ static Value *emit_unbox(Type *to, Type *pto, Value *x, jl_value_t *jt) // empty struct - TODO - is this a good way to represent it? return UndefValue::get(to); } - return builder.CreateLoad(builder.CreateBitCast(p, pto), false); + return builder.CreateLoad(builder.CreateBitCast(p, to->getPointerTo()), false); } // unbox trying to determine type automatically @@ -265,7 +265,7 @@ static Value *auto_unbox(jl_value_t *x, jl_codectx_t *ctx) if (to == T_void) { return NULL; } - return emit_unbox(to, PointerType::get(to, 0), v, bt); + return emit_unbox(to, v, bt); } // figure out how many bits a bitstype has at compile time, or -1 @@ -295,7 +295,7 @@ static Value *generic_unbox(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx) jl_value_t *p = jl_tparam0(et); if (jl_is_leaf_type(p)) { Type *to = julia_type_to_llvm(p); - return emit_unbox(to, PointerType::get(to,0), emit_unboxed(x,ctx), p); + return emit_unbox(to, emit_unboxed(x,ctx), p); } } int nb = try_to_determine_bitstype_nbits(targ, ctx); @@ -313,7 +313,7 @@ static Value *generic_unbox(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx) nb = (bt==(jl_value_t*)jl_bool_type) ? 1 : jl_datatype_size(bt)*8; } Type *to = IntegerType::get(jl_LLVMContext, nb); - return emit_unbox(to, PointerType::get(to, 0), emit_unboxed(x, ctx), et); + return emit_unbox(to, emit_unboxed(x, ctx), et); } static Value *generic_box(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx) @@ -584,7 +584,7 @@ static Value *emit_pointerref(jl_value_t *e, jl_value_t *i, jl_codectx_t *ctx) jl_error("pointerref: invalid index type"); } Value *thePtr = auto_unbox(e,ctx); - Value *idx = emit_unbox(T_size, T_psize, emit_unboxed(i, ctx), (jl_value_t*)jl_long_type); + Value *idx = emit_unbox(T_size, emit_unboxed(i, ctx), (jl_value_t*)jl_long_type); Value *im1 = builder.CreateSub(idx, ConstantInt::get(T_size, 1)); if (!jl_isbits(ety)) { if (ety == (jl_value_t*)jl_any_type) @@ -625,7 +625,7 @@ static Value *emit_pointerset(jl_value_t *e, jl_value_t *x, jl_value_t *i, jl_co } if ((jl_datatype_t*)expr_type(i, ctx) != jl_long_type) jl_error("pointerset: invalid index type"); - Value *idx = emit_unbox(T_size, T_psize, emit_unboxed(i, ctx),(jl_value_t*)jl_long_type); + Value *idx = emit_unbox(T_size, emit_unboxed(i, ctx),(jl_value_t*)jl_long_type); Value *im1 = builder.CreateSub(idx, ConstantInt::get(T_size, 1)); Value *thePtr = auto_unbox(e,ctx); if (!jl_isbits(ety) && ety != (jl_value_t*)jl_any_type) { From c802070e7b20c343325a8ec91369214fec29d4c2 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 13 Aug 2013 01:43:22 -0400 Subject: [PATCH 06/53] Adjust llvmcall for new tuple infrastructure --- base/inference.jl | 4 ++++ src/ccall.cpp | 35 +++++++---------------------------- src/codegen.cpp | 14 +++++++++++--- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 432f1ac25ab74..84c4b4de77a70 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -114,6 +114,10 @@ t_func[nan_dom_err] = (2, 2, (a, b)->a) t_func[eval(Core.Intrinsics,:ccall)] = (3, Inf, (fptr, rt, at, a...)->(is(rt,Type{Void}) ? Nothing : isType(rt) ? rt.parameters[1] : Any)) +t_func[eval(Core.Intrinsics,:llvmcall)] = + (3, Inf, (fptr, rt, at, a...)->(is(rt,Type{Void}) ? Nothing : + isType(rt) ? rt.parameters[1] : + isa(rt,Tuple) ? map(x->x.parameters[1],rt) : Any)) t_func[eval(Core.Intrinsics,:cglobal)] = (1, 2, (fptr, t...)->(isempty(t) ? Ptr{Void} : isType(t[1]) ? Ptr{t[1].parameters[1]} : Ptr)) diff --git a/src/ccall.cpp b/src/ccall.cpp index 2003f7a989c5b..4f164c2ace49a 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -593,28 +593,8 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) std::string rstring; llvm::raw_string_ostream rtypename(rstring); // Construct return type - if (!jl_is_tuple(rt)) { - rettype = julia_struct_to_llvm(rt); - rettype->print(rtypename); - } else - { - size_t nret = jl_tuple_len(rt); - if (nret == 0) { - rettype = T_void; - rettype->print(rtypename); - } else { - Type *rettypes[nret]; - rtypename << "{"; - for (size_t i = 0; i < nret; ++i) { - rettypes[i] = julia_struct_to_llvm(jl_tupleref(rt,i)); - rettypes[i]->print(rtypename); - if ((i+1) != nret) - rtypename << ","; - } - rtypename << "}"; - rettype = StructType::get(jl_LLVMContext,ArrayRef(&rettypes[0],nret)); - } - } + rettype = julia_struct_to_llvm(rt); + rettype->print(rtypename); ir_stream << "; Number of arguments: " << nargt << "\n" << "define "<setLinkage(GlobalValue::LinkOnceODRLinkage); f->dump(); // the actual call CallInst *inst = builder.CreateCall(f,ArrayRef(&argvals[0],nargt)); - InlineFunctionInfo info; - if (!InlineFunction(inst,info)) - jl_error("Failed to insert LLVM IR into function"); + ctx->to_inline.push_back(inst); - return literal_pointer_val(jl_nothing); + return mark_julia_type(inst,rt); } // --- code generator for ccall itself --- diff --git a/src/codegen.cpp b/src/codegen.cpp index b1fb6047f72a6..d8462d26460dd 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -480,13 +480,14 @@ typedef struct { int lineno; std::vector boundsCheck; #ifdef JL_GC_MARKSWEEP - Instruction *gcframe = NULL; - Instruction *argSpaceInits = NULL; - StoreInst *storeFrameSize = NULL; + Instruction *gcframe ; + Instruction *argSpaceInits; + StoreInst *storeFrameSize; #endif BasicBlock::iterator first_gcframe_inst; BasicBlock::iterator last_gcframe_inst; std::vector gc_frame_pops; + std::vector to_inline; } jl_codectx_t; static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool boxed=true, @@ -3234,6 +3235,13 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) //total_roots += (ctx.argSpaceOffs + ctx.maxDepth); finalize_gc_frame(&ctx); + // step 17, Apply LLVM level inlining + for(std::vector::iterator it = ctx.to_inline.begin(); it != ctx.to_inline.end(); ++it) { + InlineFunctionInfo info; + if (!InlineFunction(*it,info)) + jl_error("Inlining Pass failed"); + } + JL_GC_POP(); return f; } From 91f8ae7974c017f76f317d94c8eeb8fceabc0f85 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 13 Aug 2013 02:23:22 -0400 Subject: [PATCH 07/53] Some llvmcall bugfixes --- src/ccall.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 4f164c2ace49a..6fafe043695d4 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -314,6 +314,8 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, // //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); + } else if (jl_is_tuple(jt)) { + return emit_unbox(ty,jv,jt); } // TODO: error for & with non-pointer argument type assert(jl_is_bitstype(jt)); @@ -552,10 +554,10 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) for (size_t i = 0; i < nargt; ++i) { jl_value_t *tti = jl_tupleref(tt,i); - Type *t = julia_struct_to_llvm(tti); + Type *t = julia_type_to_llvm(tti); t->print(argstream); argstream << " "; - jl_value_t *argi = args[4+2*i]; + jl_value_t *argi = args[4+i]; Value *arg; bool needroot = false; if (t == jl_pvalue_llvmt || !jl_isbits(tti)) { @@ -593,7 +595,7 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) std::string rstring; llvm::raw_string_ostream rtypename(rstring); // Construct return type - rettype = julia_struct_to_llvm(rt); + rettype = julia_type_to_llvm(rt); rettype->print(rtypename); ir_stream << "; Number of arguments: " << nargt << "\n" From c343b5afc1d5fc3a95020351c3b0eda8dc359572 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 13 Aug 2013 03:00:22 -0400 Subject: [PATCH 08/53] Address compiler warnings Also remove unused PassManager reference --- src/ast.c | 2 +- src/cgutils.cpp | 2 +- src/codegen.cpp | 1 - src/intrinsics.cpp | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ast.c b/src/ast.c index e2f40207c6db9..b045bc5691e2f 100644 --- a/src/ast.c +++ b/src/ast.c @@ -57,7 +57,7 @@ value_t fl_invoke_julia_macro(value_t *args, uint32_t nargs) int i; for(i=0; i < nargs; i++) margs[i] = NULL; for(i=1; i < nargs; i++) margs[i] = scm_to_julia(args[i], 1); - jl_value_t *result=NULL; + jl_value_t *result = NULL; JL_TRY { margs[0] = scm_to_julia(args[0], 1); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index c138c4d9f51b7..86faaa12d55ef 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -994,7 +994,7 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) { if (v == NULL || dyn_cast(v) != 0) { if (jl_is_datatype(jt)) { - jl_datatype_t *jb = (jl_datatype_t*)jb; + jl_datatype_t *jb = (jl_datatype_t*)jt; if (jb->instance == NULL) jl_new_struct_uninit(jb); assert(jb->instance != NULL); diff --git a/src/codegen.cpp b/src/codegen.cpp index d8462d26460dd..379508335cd45 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -115,7 +115,6 @@ static ExecutionEngine *jl_ExecutionEngine; static DIBuilder *dbuilder; static std::map argNumberStrings; static FunctionPassManager *FPM; -static PassManager *PM; #ifdef LLVM32 static DataLayout *jl_data_layout; diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index a1065132c6886..a4000f776231e 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -204,7 +204,7 @@ static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt) assert(jt != 0); assert(jl_is_tuple(jt)); Value *tpl = UndefValue::get(to); - size_t n; + size_t n = 0; if (to->isStructTy()) n = dyn_cast(to)->getNumElements(); else if(to->isArrayTy()) From 49217ff64c1d2ecaa16aceab927548980d3db1e6 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 13 Aug 2013 03:24:52 -0400 Subject: [PATCH 09/53] Also remove PM initialization --- src/codegen.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 379508335cd45..b97a6f3d5118e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3575,7 +3575,6 @@ static void init_julia_llvm_env(Module *m) // set up optimization passes FPM = new FunctionPassManager(jl_Module); - PM = new PassManager(); #ifdef LLVM32 From 9cc281932e183720687afd687655a598de3d7f95 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 13 Aug 2013 19:00:19 -0400 Subject: [PATCH 10/53] Handle nothingness correctly --- src/cgutils.cpp | 65 ++++++++++++++++++++++++++++++---------------- src/codegen.cpp | 50 ++++++++++++++++++----------------- src/intrinsics.cpp | 6 +++++ 3 files changed, 75 insertions(+), 46 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 86faaa12d55ef..4378f4d974434 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -87,6 +87,8 @@ static Type *julia_type_to_llvm(jl_value_t *jt) if (purebits) { if (isvector) { Type *ret = NULL; + if(type == T_void) + return T_void; if (type->isSingleValueType()) ret = VectorType::get(type,ntypes); else @@ -987,40 +989,59 @@ static Value *allocate_box_dynamic(Value *jlty, int nb, Value *v) bool isGhostType(jl_value_t*); +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); + assert(jb->instance != NULL); + return (jl_value_t*)jb->instance; + } else if (jt == jl_typeof(jl_nothing)) + { + return (jl_value_t*)jl_nothing; + } + assert(jl_is_tuple(jt)); + if (jl_tuple_len(jt) == 0) + return (jl_value_t*)jl_null; + size_t nargs = jl_tuple_len(jt); + jl_value_t *tpl = (jl_value_t*)jl_alloc_tuple_uninit(nargs); + JL_GC_PUSH(tpl); + for(size_t i=0; i < nargs; i++) { + jl_tupleset(tpl, i, static_void_instance(jl_tupleref(jt,i))); + } + JL_GC_POP(); + return tpl; +} + + +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. static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) { if (v == NULL || dyn_cast(v) != 0) { - if (jl_is_datatype(jt)) { - jl_datatype_t *jb = (jl_datatype_t*)jt; - if (jb->instance == NULL) - jl_new_struct_uninit(jb); - assert(jb->instance != NULL); - return literal_pointer_val((jl_value_t*)jb->instance); - } - else if (jl_is_tuple(jt)) { - assert(jl_tuple_len(jt) == 0); - return literal_pointer_val((jl_value_t*)jl_null); - } - // Type information might not be good enough, - if (v == NULL) - return literal_pointer_val((jl_value_t*)jl_null); - else + if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) jt = julia_type_of(v); - assert(jl_is_datatype(jt)); - assert(isGhostType(jt)); - return literal_pointer_val((jl_value_t*)((jl_datatype_t*)jt)->instance); + jl_value_t *s = static_void_instance(jt); + if(jl_is_tuple(jt) && jl_tuple_len(jt) > 0) + jl_add_linfo_root(ctx->linfo, s); + return literal_pointer_val(s); } Type *t = v->getType(); if (t == jl_pvalue_llvmt) return v; if (t == T_void) { - if (jl_is_tuple(jt)) - return literal_pointer_val((jl_value_t*)jl_null); - else - return literal_pointer_val((jl_value_t*)jl_nothing); + if (jl_is_tuple(jt)) { + jl_value_t *s = static_void_instance(jt); + if(jl_is_tuple(jt) && jl_tuple_len(jt) > 0) + jl_add_linfo_root(ctx->linfo, s); + return literal_pointer_val(s); + } else { + return literal_pointer_val(jl_nothing); + } } if (t == T_int1) return julia_bool(v); if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) diff --git a/src/codegen.cpp b/src/codegen.cpp index b97a6f3d5118e..c7ddd850ecdfa 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1375,9 +1375,20 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, for(i=0; i < nargs; i++) { jl_tupleset(tt, i, expr_type(args[i+1],ctx)); } - Value *tpl = UndefValue::get(julia_type_to_llvm(tt)); + Type *ty = julia_type_to_llvm(tt); + Value *tpl = NULL; + if (ty != T_void) + tpl = UndefValue::get(ty); for (size_t i = 0; i < nargs; ++i) { - Type *ety = jl_llvmtuple_eltype(tpl->getType(),i); + Type *ety = NULL; + if (tpl != NULL) + ety = jl_llvmtuple_eltype(tpl->getType(),i); + if(tpl == NULL || ety == T_void) + { + emit_expr(args[i+1],ctx); //for side effects (if any) + continue; + } + assert(tpl != NULL); Value *elt = emit_unbox(ety, emit_unboxed(args[i+1],ctx),jl_tupleref(tt,i)); tpl = emit_tupleset(tpl,ConstantInt::get(T_size,i+1),elt,tt,ctx); @@ -1386,23 +1397,6 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, return tpl; } - for(i=0; i < nargs; i++) { - jl_value_t *it = (jl_value_t*)jl_typeof(args[i+1]); - if (!(jl_is_immutable_datatype(it) && - it!=(jl_value_t*)jl_quotenode_type && it!=(jl_value_t*)jl_topnode_type)) - break; - } - if (i >= nargs) { - // all arguments constant; can be statically evaluated - rt1 = (jl_value_t*)jl_alloc_tuple_uninit(nargs); - for(i=0; i < nargs; i++) { - jl_tupleset(rt1, i, args[i+1]); - } - jl_add_linfo_root(ctx->linfo, rt1); - JL_GC_POP(); - return literal_pointer_val(rt1); - } - int last_depth = ctx->argDepth; // eval the first argument first, then do hand-over-hand to track the tuple. Value *arg1val = emit_expr(args[1], ctx); @@ -1749,7 +1743,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, continue; } if (at == jl_pvalue_llvmt) { - argvals[idx] = boxed(emit_expr(args[i+1], ctx),ctx); + argvals[idx] = boxed(emit_expr(args[i+1], ctx),ctx,expr_type(args[i+1],ctx)); if (might_need_root(args[i+1])) { make_gcroot(argvals[idx], ctx); } @@ -1757,7 +1751,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, else { assert(at == et); argvals[idx] = emit_unbox(at, - emit_unboxed(args[i+1], ctx), expr_type(args[i+1],ctx)); + emit_unboxed(args[i+1], ctx),jl_tupleref(f->linfo->specTypes,i)); } idx++; } @@ -1875,7 +1869,9 @@ static Value *ghostValue(jl_value_t *ty) { if (jl_is_datatype(ty)) { - return UndefValue::get(julia_struct_to_llvm(ty)); + Type *llvmty = julia_struct_to_llvm(ty); + assert(llvmty != T_void); + return UndefValue::get(llvmty); } else return NULL; } @@ -2237,6 +2233,7 @@ 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); Value *strct = UndefValue::get(lt); size_t na = nargs-1 < nf ? nargs-1 : nf; unsigned idx = 0; @@ -2520,7 +2517,9 @@ static void finalize_gc_frame(jl_codectx_t *ctx) BasicBlock::iterator bbi = ctx->first_gcframe_inst; while (1) { Instruction &iii = *bbi; - iii.replaceAllUsesWith(UndefValue::get(iii.getType())); + Type *ty = iii.getType(); + if (ty != T_void) + iii.replaceAllUsesWith(UndefValue::get(ty)); if (bbi == ctx->last_gcframe_inst) break; bbi++; } @@ -2529,7 +2528,9 @@ static void finalize_gc_frame(jl_codectx_t *ctx) BasicBlock::iterator pi(pop); for(size_t j=0; j < 4; j++) { Instruction &iii = *pi; - iii.replaceAllUsesWith(UndefValue::get(iii.getType())); + Type *ty = iii.getType(); + if (ty != T_void) + iii.replaceAllUsesWith(UndefValue::get(ty)); pi++; } } @@ -2606,6 +2607,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) builder.SetCurrentDebugLocation(noDbg); jl_codectx_t ctx; + ctx.linfo = lam; allocate_gc_frame(0,&ctx); ctx.argSpaceInits = &b0->back(); diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index a4000f776231e..85a53f054442d 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -171,6 +171,8 @@ static Type *jl_llvmtuple_eltype(Type *tuple, size_t i) ety = dyn_cast(tuple)->getElementType(); else if(tuple->isVectorTy()) ety = dyn_cast(tuple)->getElementType(); + else if(tuple == T_void) + ety = T_void; else assert(false); return ety; @@ -203,6 +205,7 @@ static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt) { assert(jt != 0); assert(jl_is_tuple(jt)); + assert(to != T_void); Value *tpl = UndefValue::get(to); size_t n = 0; if (to->isStructTy()) @@ -216,6 +219,8 @@ static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt) assert(n == jl_tuple_len(jt)); for (size_t i = 0; i < n; ++i) { Type *ety = jl_llvmtuple_eltype(to,i); + if(ety == T_void) + continue; Value *elt = emit_unbox(ety, emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL),jl_tupleref(jt,i)); tpl = emit_tupleset(tpl,ConstantInt::get(T_size,i+1),elt,jt,NULL); @@ -232,6 +237,7 @@ static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt) } if (to->isStructTy() && !to->isSized()) { // empty struct - TODO - is this a good way to represent it? + assert(to != T_void); return UndefValue::get(to); } return builder.CreateLoad(builder.CreateBitCast(p, to->getPointerTo()), false); From aec2612c072618a833a9c282934164b8b8da1abb Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 14 Aug 2013 14:31:54 -0400 Subject: [PATCH 11/53] Fix a performance regression We used to statically evaluate immutable tuples, but now these get picked up to create unboxed constants. This change allows static insertion of any unboxed constants to boxed constants. Fixes a performance regression in parseint. --- src/cgutils.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 4378f4d974434..bc1e9027ab6db 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1014,6 +1014,56 @@ static jl_value_t *static_void_instance(jl_value_t *jt) return tpl; } +static jl_value_t *static_constant_instance(Constant *constant, jl_value_t *jt) +{ + assert(constant != NULL); + + ConstantInt *cint = dyn_cast(constant); + if (cint != NULL) { + assert(jl_is_datatype(jt)); + return jl_new_bits((jl_datatype_t*)jt, + const_cast(cint->getValue().getRawData())); + } + + ConstantFP *cfp = dyn_cast(constant); + if (cfp != NULL) { + assert(jl_is_datatype(jt)); + return jl_new_bits((jl_datatype_t*)jt, + const_cast(cfp->getValueAPF().bitcastToAPInt().getRawData())); + } + + ConstantPointerNull *cpn = dyn_cast(constant); + if (cpn != NULL) { + assert(jl_is_cpointer_type(jt)); + uint64_t val = 0; + return jl_new_bits((jl_datatype_t*)jt,&val); + } + + assert(jl_is_tuple(jt)); + + size_t nargs = 0; + ConstantArray *carr = NULL; + ConstantStruct *cst = NULL; + ConstantVector *cvec = NULL; + if ((carr = dyn_cast(constant)) != NULL) + nargs = carr->getType()->getNumElements(); + else if((cst = dyn_cast(constant)) != NULL) + nargs = cst->getType()->getNumElements(); + else if((cvec = dyn_cast(constant)) != NULL) + nargs = cvec->getType()->getNumElements(); + else + assert(false && "Cannot process this type of constant"); + + jl_value_t *tpl = (jl_value_t*)jl_alloc_tuple_uninit(nargs); + JL_GC_PUSH(tpl); + for(size_t i=0; i < nargs; i++) { + jl_tupleset(tpl, i, static_constant_instance( + constant->getAggregateElement(i),jl_tupleref(jt,i))); + } + JL_GC_POP(); + return tpl; +} + static void jl_add_linfo_root(jl_lambda_info_t *li, jl_value_t *val); @@ -1046,6 +1096,12 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) if (t == T_int1) return julia_bool(v); if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) jt = julia_type_of(v); + Constant *c = NULL; + if((c = dyn_cast(v)) != NULL) { + jl_value_t *s = static_constant_instance(c,jt); + jl_add_linfo_root(ctx->linfo, s); + return literal_pointer_val(s); + } if jl_is_tuple(jt) { size_t n = jl_tuple_len(jt); Value *tpl = builder.CreateCall(jl_alloc_tuple_func,ConstantInt::get(T_size,n)); @@ -1091,7 +1147,6 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) if (jb == jl_uint32_type) return builder.CreateCall(box_uint32_func, v); 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_isbits(jt)) { assert("Don't know how to box this type" && false); return NULL; From 6b567e1153b5b9856f5cb5deee1f51ad03005fde Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 15 Aug 2013 03:52:37 -0400 Subject: [PATCH 12/53] tpl -> &tpl and don't use return value from unreachable --- src/cgutils.cpp | 9 ++++----- src/codegen.cpp | 4 ++-- src/gc.c | 2 +- src/intrinsics.cpp | 14 ++++++++++---- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index bc1e9027ab6db..935cc886f0ada 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -324,13 +324,12 @@ static void just_emit_error(const std::string &txt, jl_codectx_t *ctx) ArrayRef(zeros))); } -static Value *emit_error(const std::string &txt, jl_codectx_t *ctx) +static void emit_error(const std::string &txt, jl_codectx_t *ctx) { just_emit_error(txt, ctx); - Value *v = builder.CreateUnreachable(); + builder.CreateUnreachable(); BasicBlock *cont = BasicBlock::Create(getGlobalContext(),"after_error",ctx->f); builder.SetInsertPoint(cont); - return v; } static void error_unless(Value *cond, const std::string &msg, jl_codectx_t *ctx) @@ -1006,7 +1005,7 @@ static jl_value_t *static_void_instance(jl_value_t *jt) return (jl_value_t*)jl_null; size_t nargs = jl_tuple_len(jt); jl_value_t *tpl = (jl_value_t*)jl_alloc_tuple_uninit(nargs); - JL_GC_PUSH(tpl); + JL_GC_PUSH1(&tpl); for(size_t i=0; i < nargs; i++) { jl_tupleset(tpl, i, static_void_instance(jl_tupleref(jt,i))); } @@ -1055,7 +1054,7 @@ static jl_value_t *static_constant_instance(Constant *constant, jl_value_t *jt) assert(false && "Cannot process this type of constant"); jl_value_t *tpl = (jl_value_t*)jl_alloc_tuple_uninit(nargs); - JL_GC_PUSH(tpl); + JL_GC_PUSH1(&tpl); for(size_t i=0; i < nargs; i++) { jl_tupleset(tpl, i, static_constant_instance( constant->getAggregateElement(i),jl_tupleref(jt,i))); diff --git a/src/codegen.cpp b/src/codegen.cpp index c7ddd850ecdfa..0421cdbffc79a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1232,9 +1232,9 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, } if (tp0 == jl_bottom_type) { emit_expr(args[1], ctx); - Value *v = emit_error("reached code declared unreachable", ctx); + emit_error("reached code declared unreachable", ctx); JL_GC_POP(); - return v; + return NULL; } if (!jl_is_tuple(tp0) && jl_is_leaf_type(tp0)) { Value *arg1 = emit_expr(args[1], ctx); diff --git a/src/gc.c b/src/gc.c index 1d587053a414b..524630fb77807 100644 --- a/src/gc.c +++ b/src/gc.c @@ -10,7 +10,7 @@ // with MEMDEBUG, every object is allocated explicitly with malloc, and // filled with 0xbb before being freed. -#define MEMDEBUG +//#define MEMDEBUG // MEMPROFILE prints pool summary statistics after every GC //#define MEMPROFILE diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 85a53f054442d..c5238616a4812 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -260,7 +260,10 @@ static Value *auto_unbox(jl_value_t *x, jl_codectx_t *ctx) if (bt == NULL || !jl_is_bitstype(bt)) { // TODO: make sure this code is valid; hopefully it is // unreachable but it should still be well-formed. - return emit_error("auto_unbox: unable to determine argument type", ctx); + emit_error("auto_unbox: unable to determine argument type", ctx); + // This isn't correct but probably most likely to cause + // the least amount of trouble + return UndefValue::get(T_int64); } } Type *to = julia_type_to_llvm(bt); @@ -598,7 +601,8 @@ static Value *emit_pointerref(jl_value_t *e, jl_value_t *i, jl_codectx_t *ctx) builder.CreateBitCast(thePtr, jl_ppvalue_llvmt), im1)); if (!jl_is_structtype(ety) || jl_is_array_type(ety) || !jl_is_leaf_type(ety)) { - return emit_error("pointerref: invalid pointer type", ctx); + emit_error("pointerref: invalid pointer type", ctx); + return NULL; } uint64_t size = ((jl_datatype_t*)ety)->size; Value *strct = @@ -627,7 +631,8 @@ static Value *emit_pointerset(jl_value_t *e, jl_value_t *x, jl_value_t *i, jl_co jl_error("pointerset: invalid pointer"); jl_value_t *xty = expr_type(x, ctx); if (!jl_subtype(xty, ety, 0)) { - return emit_error("pointerset: type mismatch in assign", ctx); + emit_error("pointerset: type mismatch in assign", ctx); + return NULL; } if ((jl_datatype_t*)expr_type(i, ctx) != jl_long_type) jl_error("pointerset: invalid index type"); @@ -636,7 +641,8 @@ static Value *emit_pointerset(jl_value_t *e, jl_value_t *x, jl_value_t *i, jl_co Value *thePtr = auto_unbox(e,ctx); if (!jl_isbits(ety) && ety != (jl_value_t*)jl_any_type) { if (!jl_is_structtype(ety) || jl_is_array_type(ety) || !jl_is_leaf_type(ety)) { - return emit_error("pointerset: invalid pointer type", ctx); + emit_error("pointerset: invalid pointer type", ctx); + return NULL; } Value *val = emit_expr(x,ctx,true,true); assert(val->getType() == jl_pvalue_llvmt); //Boxed From 1933ea7ecb07817c4c7b929db0b74f58792fcc71 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 15 Aug 2013 03:58:11 -0400 Subject: [PATCH 13/53] Allow unboxed storing tupl purebits tuples --- base/inference.jl | 2 +- src/codegen.cpp | 63 ++++++++++++++++++++++++++++------------------ src/intrinsics.cpp | 25 ++++++++++++++++++ 3 files changed, 64 insertions(+), 26 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 84c4b4de77a70..4f948e4c5c871 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -2070,7 +2070,7 @@ function inlining_pass(e::Expr, sv, ast) end function add_variable(ast, name, typ) - vinf = {name,typ,2} + vinf = {name,typ,18} locllist = ast.args[2][1]::Array{Any,1} vinflist = ast.args[2][2]::Array{Any,1} push!(locllist, name) diff --git a/src/codegen.cpp b/src/codegen.cpp index 0421cdbffc79a..2da246f932a7a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2414,13 +2414,28 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, // --- allocating local variables --- +static bool jltupleisbits(jl_value_t *jt, bool allow_unsized = true) +{ + if (!jl_is_tuple(jt)) + return jl_isbits(jt) && (allow_unsized || + ((jl_is_bitstype(jt) && jl_datatype_size(jt) > 0) || + (jl_is_datatype(jt) && jl_tuple_len(((jl_datatype_t*)jt)->names)>0))); + size_t ntypes = jl_tuple_len(jt); + if (ntypes == 0) + return allow_unsized; + for (size_t i = 0; i < ntypes; ++i) + if (!jltupleisbits(jl_tupleref(jt,i),allow_unsized)) + return false; + return true; +} + static bool store_unboxed_p(jl_sym_t *s, jl_codectx_t *ctx) { jl_varinfo_t &vi = ctx->vars[s]; jl_value_t *jt = vi.declType; // only store a variable unboxed if type inference has run, which // checks that the variable is not referenced undefined. - return (ctx->linfo->inferred && jl_isbits(jt) && + return (ctx->linfo->inferred && jltupleisbits(jt,false) && ((jl_datatype_t*)jt)->size > 0 && // don't unbox intrinsics, since inference depends on their having // stable addresses for table lookup. @@ -2432,8 +2447,8 @@ static Value *alloc_local(jl_sym_t *s, jl_codectx_t *ctx) jl_varinfo_t &vi = ctx->vars[s]; jl_value_t *jt = vi.declType; Value *lv = NULL; - Type *vtype=NULL; - if (store_unboxed_p(s, ctx)) + Type *vtype = NULL; + if(store_unboxed_p(s,ctx) && s != ctx->vaName) vtype = julia_type_to_llvm(jt); if (vtype != T_void) { @@ -2580,17 +2595,6 @@ static void finalize_gc_frame(jl_codectx_t *ctx) } } -static bool jltupleisbits(jl_value_t *jt) -{ - if (!jl_is_tuple(jt)) - return jl_isbits(jt); - size_t ntypes = jl_tuple_len(jt); - for (size_t i = 0; i < ntypes; ++i) - if (!jltupleisbits(jl_tupleref(jt,i))) - return false; - return true; -} - // generate a julia-callable function that calls f (AKA lam) static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) { @@ -3111,6 +3115,8 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) } else if (dyn_cast(lv) != NULL) builder.CreateStore(boxed(theArg,&ctx), lv); + else if (dyn_cast(lv)->getAllocatedType() == jl_pvalue_llvmt) + builder.CreateStore(theArg,lv); else builder.CreateStore(emit_unbox(dyn_cast(lv)->getAllocatedType(), theArg, @@ -3132,19 +3138,26 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) if (!vi.escapes && !vi.isAssigned) { ctx.vaStack = true; } - else { + else if(!vi.isGhost) { // restarg = jl_f_tuple(NULL, &args[nreq], nargs-nreq) - Value *restTuple = - builder.CreateCall3(jltuple_func, V_null, - builder.CreateGEP(argArray, - ConstantInt::get(T_size,nreq)), - builder.CreateSub(argCount, - ConstantInt::get(T_int32,nreq))); Value *lv = vi.memvalue; - if (isBoxed(argname, &ctx)) - builder.CreateStore(builder.CreateCall(jlbox_func, restTuple), lv); - else - builder.CreateStore(restTuple, lv); + if (dyn_cast(lv) != NULL || dyn_cast(lv)->getAllocatedType() == jl_pvalue_llvmt) + { + Value *restTuple = + builder.CreateCall3(jltuple_func, V_null, + builder.CreateGEP(argArray, + ConstantInt::get(T_size,nreq)), + builder.CreateSub(argCount, + ConstantInt::get(T_int32,nreq))); + if (isBoxed(argname, &ctx)) + builder.CreateStore(builder.CreateCall(jlbox_func, restTuple), lv); + else + builder.CreateStore(restTuple, lv); + } else { + // TODO: Perhaps allow this in the future, but for now sice varargs are always unspecialized + // we don't + assert(false); + } } } diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index c5238616a4812..0284d258ed31d 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -177,9 +177,34 @@ static Type *jl_llvmtuple_eltype(Type *tuple, size_t i) assert(false); return ety; } + +static size_t jl_llvmtuple_nargs(Type *tuple) +{ + size_t n = 0; + if (tuple->isStructTy()) + n = dyn_cast(tuple)->getNumElements(); + else if(tuple->isArrayTy()) + n = dyn_cast(tuple)->getNumElements(); + else if(tuple->isVectorTy()) + n = dyn_cast(tuple)->getNumElements(); + else + assert(false); + return n; +} + +static Value *ghostValue(jl_value_t *ty); + // emit code to unpack a raw value from a box static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt) { + if (x == NULL) { + if (to == T_void) { + if (jt != NULL) + return ghostValue(jt); + return NULL; + } + return UndefValue::get(to); + } Type *ty = x->getType(); if (ty != jl_pvalue_llvmt) { // bools are stored internally as int8 (for now) From c58e1ff2235ce635306be039c79395c6b6c8f732 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 16 Aug 2013 00:48:09 -0400 Subject: [PATCH 14/53] remove invalid check from store_unboxed_p --- src/codegen.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 2da246f932a7a..2fc731c415c6c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2436,7 +2436,6 @@ static bool store_unboxed_p(jl_sym_t *s, jl_codectx_t *ctx) // only store a variable unboxed if type inference has run, which // checks that the variable is not referenced undefined. return (ctx->linfo->inferred && jltupleisbits(jt,false) && - ((jl_datatype_t*)jt)->size > 0 && // don't unbox intrinsics, since inference depends on their having // stable addresses for table lookup. jt != (jl_value_t*)jl_intrinsic_type && !vi.isCaptured); From 17690a0627181af192825735a51c74ac2900f2c8 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 16 Aug 2013 15:50:33 -0400 Subject: [PATCH 15/53] is_stable_expr for tuples --- src/codegen.cpp | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 2fc731c415c6c..8271f63595e37 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -840,6 +840,30 @@ static bool is_getfield_nonallocating(jl_datatype_t *ty, jl_value_t *fld) return true; } +static bool jltupleisbits(jl_value_t *jt, bool allow_unsized = true) +{ + if (!jl_is_tuple(jt)) + return jl_isbits(jt) && (allow_unsized || + ((jl_is_bitstype(jt) && jl_datatype_size(jt) > 0) || + (jl_is_datatype(jt) && jl_tuple_len(((jl_datatype_t*)jt)->names)>0))); + size_t ntypes = jl_tuple_len(jt); + if (ntypes == 0) + return allow_unsized; + for (size_t i = 0; i < ntypes; ++i) + if (!jltupleisbits(jl_tupleref(jt,i),allow_unsized)) + return false; + return true; +} + +static bool jl_tupleref_nonallocating(jl_value_t *ty, jl_value_t *idx) +{ + if (!jl_is_tuple(ty)) + return false; + if (jltupleisbits(ty)) + return false; + return true; +} + // does "ex" compute something that doesn't need a root over the whole function? static bool is_stable_expr(jl_value_t *ex, jl_codectx_t *ctx) { @@ -866,7 +890,7 @@ static bool is_stable_expr(jl_value_t *ex, jl_codectx_t *ctx) jl_value_t *ty = expr_type(jl_exprarg(e,1), ctx); if ((fptr == &jl_f_get_field && jl_is_immutable_datatype(ty) && is_getfield_nonallocating((jl_datatype_t*)ty, jl_exprarg(e,2))) || - fptr == &jl_f_tupleref) { + (fptr == &jl_f_tupleref && jl_tupleref_nonallocating(ty, jl_exprarg(e,2)))) { if (is_stable_expr(jl_exprarg(e,1), ctx)) return true; } @@ -2414,21 +2438,6 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, // --- allocating local variables --- -static bool jltupleisbits(jl_value_t *jt, bool allow_unsized = true) -{ - if (!jl_is_tuple(jt)) - return jl_isbits(jt) && (allow_unsized || - ((jl_is_bitstype(jt) && jl_datatype_size(jt) > 0) || - (jl_is_datatype(jt) && jl_tuple_len(((jl_datatype_t*)jt)->names)>0))); - size_t ntypes = jl_tuple_len(jt); - if (ntypes == 0) - return allow_unsized; - for (size_t i = 0; i < ntypes; ++i) - if (!jltupleisbits(jl_tupleref(jt,i),allow_unsized)) - return false; - return true; -} - static bool store_unboxed_p(jl_sym_t *s, jl_codectx_t *ctx) { jl_varinfo_t &vi = ctx->vars[s]; From 10330fa6298915b7799c41281792ef98bf3c461c Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 2 Oct 2013 16:50:27 -0400 Subject: [PATCH 16/53] Fix tuples branch for some changes since it was introduced --- src/cgutils.cpp | 14 +++++--------- src/codegen.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 935cc886f0ada..2c5a5d942f3c2 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -996,7 +996,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)) + } else if (jt == jl_typeof(jl_nothing) || jt == jl_bottom_type) { return (jl_value_t*)jl_nothing; } @@ -1083,14 +1083,10 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) if (t == jl_pvalue_llvmt) return v; if (t == T_void) { - if (jl_is_tuple(jt)) { - jl_value_t *s = static_void_instance(jt); - if(jl_is_tuple(jt) && jl_tuple_len(jt) > 0) - jl_add_linfo_root(ctx->linfo, s); - return literal_pointer_val(s); - } else { - return literal_pointer_val(jl_nothing); - } + jl_value_t *s = static_void_instance(jt); + if(jl_is_tuple(jt) && jl_tuple_len(jt) > 0) + jl_add_linfo_root(ctx->linfo, s); + return literal_pointer_val(s); } if (t == T_int1) return julia_bool(v); if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) diff --git a/src/codegen.cpp b/src/codegen.cpp index 8271f63595e37..a2c3805ac3215 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1068,7 +1068,7 @@ static Value *emit_getfield(jl_value_t *expr, jl_sym_t *name, jl_codectx_t *ctx) JL_GC_POP(); int argStart = ctx->argDepth; - Value *arg1 = boxed(emit_expr(expr, ctx),ctx); + Value *arg1 = boxed(emit_expr(expr, ctx),ctx,expr_type(expr,ctx)); // TODO: generic getfield func with more efficient calling convention make_gcroot(arg1, ctx); Value *arg2 = literal_pointer_val((jl_value_t*)name); @@ -2604,7 +2604,7 @@ static void finalize_gc_frame(jl_codectx_t *ctx) } // generate a julia-callable function that calls f (AKA lam) -static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) +static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Function *f) { Function *w = Function::Create(jl_func_sig, Function::ExternalLinkage, f->getName(), jl_Module); @@ -2658,7 +2658,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, Function *f) // wrappers can be reused for different functions of the same type. Value *r = builder.CreateCall(f, ArrayRef(&args[0], nfargs)); if (r->getType() != jl_pvalue_llvmt) { - r = boxed(r, &ctx, jl_ast_rettype(lam, lam->ast)); + r = boxed(r, &ctx, jl_ast_rettype(lam, (jl_value_t*)ast)); } // gc pop. Usually this is done when we encounter the return statement @@ -2833,7 +2833,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) lam->cFunctionObject = (void*)f; } if (lam->functionObject == NULL) { - lam->functionObject = (void*)gen_jlcall_wrapper(lam, f); + lam->functionObject = (void*)gen_jlcall_wrapper(lam, ast, f); } } else { From a93b4424d6990d39a8461f2f1eca433834d498b2 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 4 Oct 2013 21:26:26 -0400 Subject: [PATCH 17/53] Tuples branch bug-fixes --- base/reflection.jl | 8 ++-- src/cgutils.cpp | 103 ++++++++++++++++++++++++++++++--------------- src/codegen.cpp | 89 ++++++++++++++++++++++++--------------- src/intrinsics.cpp | 47 ++++++--------------- 4 files changed, 140 insertions(+), 107 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index a2f4c5ebe7fa9..15642fbb4b58b 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -128,16 +128,16 @@ done(mt::MethodTable, i::()) = true uncompressed_ast(l::LambdaStaticData) = isa(l.ast,Expr) ? l.ast : ccall(:jl_uncompress_ast, Any, (Any,Any), l, l.ast) -function _dump_function(f, t::ANY, native) - str = ccall(:jl_dump_function, Any, (Any,Any,Bool), f, t, native)::ByteString +function _dump_function(f, t::ANY, native, wrapper) + str = ccall(:jl_dump_function, Any, (Any,Any,Bool,Bool), f, t, native, wrapper)::ByteString if str == "" error("no method found for the specified argument types") end str end -code_llvm (f::Callable, types::Tuple) = print(_dump_function(f, types, false)) -code_native(f::Callable, types::Tuple) = print(_dump_function(f, types, true)) +code_llvm (f::Callable, types::Tuple) = print(_dump_function(f, types, false, false)) +code_native(f::Callable, types::Tuple) = print(_dump_function(f, types, true, false)) function functionlocs(f::Function, types=(Any...)) locs = Any[] diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 2c5a5d942f3c2..bf992aa6c24a7 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -96,9 +96,14 @@ static Type *julia_type_to_llvm(jl_value_t *jt) return ret; } else { Type *types[ntypes]; - for (size_t i = 0; i < ntypes; ++i) - types[i] = julia_struct_to_llvm(jl_tupleref(jt,i)); - return StructType::get(jl_LLVMContext,ArrayRef(&types[0],ntypes)); + size_t j = 0; + for (size_t i = 0; i < ntypes; ++i) { + Type *ty = julia_struct_to_llvm(jl_tupleref(jt,i)); + if (ty == T_void) + continue; + types[j++] = ty; + } + return StructType::get(jl_LLVMContext,ArrayRef(&types[0],j)); } } } @@ -592,7 +597,7 @@ static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx) // --- accessing the representations of built-in data types --- -static Value *emit_tuplelen(Value *t) +static Value *emit_tuplelen(Value *t,jl_value_t *jt) { if (t == NULL) return ConstantInt::get(T_size,0); @@ -608,17 +613,7 @@ static Value *emit_tuplelen(Value *t) return builder.CreatePtrToInt(lenbits, T_size); #endif } else { //unboxedAg - if (ty->isStructTy()) { - StructType *st = dyn_cast(ty); - return ConstantInt::get(T_size,st->getNumElements()); - } else if (ty->isArrayTy()) { - ArrayType *at = dyn_cast(ty); - return ConstantInt::get(T_size,at->getNumElements()); - } else { - assert(ty->isVectorTy()); - VectorType *vt = dyn_cast(ty); - return ConstantInt::get(T_size,vt->getNumElements()); - } + return ConstantInt::get(T_size,jl_tuple_len(jt)); } } @@ -657,7 +652,20 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl ConstantInt *idx = dyn_cast(i); if (idx != 0) { unsigned ci = (unsigned)idx->getZExtValue()-1; - ret = builder.CreateInsertValue(tuple,x,ArrayRef(ci)); + size_t n = jl_tuple_len(jt); + for (size_t i=0,j = 0; i(j)); + } + if(ty != T_void) + ++j; + } } else if (ty->isArrayTy()) { @@ -686,11 +694,19 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl ConstantInt::get(T_int32, ctx->lineno)); builder.CreateUnreachable(); // Now for the cases - for (size_t i = 1; i <= n; ++i) { + for (size_t i = 1,j = 0; i <= n; ++i) { BasicBlock *blk = BasicBlock::Create(getGlobalContext(),"case",ctx->f); builder.SetInsertPoint(blk); - Value *newAgg = builder.CreateInsertValue(tuple,x,ArrayRef(i-1)); - builder.CreateStore(newAgg,ret); + jl_value_t *jltype = jl_tupleref(jt,i-1); + Type *ty = julia_struct_to_llvm(jltype); + if (ty != T_void) + { + Value *newAgg = builder.CreateInsertValue(tuple,x,ArrayRef(j)); + builder.CreateStore(newAgg,ret); + j++; + } else { + builder.CreateStore(tuple,ret); + } builder.CreateBr(after); sw->addCase(ConstantInt::get((IntegerType*)T_size,i),blk); } @@ -735,7 +751,22 @@ static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t ConstantInt *idx = dyn_cast(i); if (idx != 0) { unsigned ci = (unsigned)idx->getZExtValue()-1; - return mark_julia_type(builder.CreateExtractValue(tuple,ArrayRef(ci)),jl_tupleref(jt,ci)); + size_t n = jl_tuple_len(jt); + for (size_t i = 0,j = 0; i(j)),jl_tupleref(jt,i)); + } + if(ty != T_void) + ++j; + } + assert("Out of bounds!"); + return NULL; } else if (ty->isArrayTy()) { @@ -763,13 +794,23 @@ static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t ConstantInt::get(T_int32, ctx->lineno)); builder.CreateUnreachable(); // Now for the cases - for (size_t i = 1; i <= n; ++i) { + for (size_t i = 1, j = 0; i <= n; ++i) { BasicBlock *blk = BasicBlock::Create(getGlobalContext(),"case",ctx->f); sw->addCase(ConstantInt::get((IntegerType*)T_size,i),blk); builder.SetInsertPoint(blk); - Value *val = boxed(builder.CreateExtractValue(tuple,ArrayRef(i-1)),ctx,jl_tupleref(jt,i-1)); + jl_value_t *jltype = jl_tupleref(jt,i-1); + Type *ty = julia_struct_to_llvm(jltype); + Value *val; + if (ty != T_void) + { + val = boxed(builder.CreateExtractValue(tuple,ArrayRef(j)),ctx,jltype); + j++; + } else { + val = boxed(NULL,ctx,jltype); + } builder.CreateStore(val,ret); builder.CreateBr(after); + } builder.SetInsertPoint(after); return builder.CreateLoad(ret); @@ -1071,7 +1112,8 @@ static void jl_add_linfo_root(jl_lambda_info_t *li, jl_value_t *val); // if it's already a pointer it's left alone. static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) { - if (v == NULL || dyn_cast(v) != 0) { + Type *t = (v == NULL) ? NULL : v->getType(); + if (v == NULL || dyn_cast(v) != 0 || t == NoopType) { if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) jt = julia_type_of(v); jl_value_t *s = static_void_instance(jt); @@ -1079,18 +1121,17 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) jl_add_linfo_root(ctx->linfo, s); return literal_pointer_val(s); } - Type *t = v->getType(); if (t == jl_pvalue_llvmt) return v; + if (t == T_int1) return julia_bool(v); + if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) + jt = julia_type_of(v); if (t == T_void) { jl_value_t *s = static_void_instance(jt); if(jl_is_tuple(jt) && jl_tuple_len(jt) > 0) jl_add_linfo_root(ctx->linfo, s); return literal_pointer_val(s); } - if (t == T_int1) return julia_bool(v); - if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) - jt = julia_type_of(v); Constant *c = NULL; if((c = dyn_cast(v)) != NULL) { jl_value_t *s = static_constant_instance(c,jt); @@ -1104,13 +1145,7 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) for (size_t i = 0; i < n; ++i) { jl_value_t *jti = jl_tupleref(jt,i); - Value *vi; - if (v->getType()->isStructTy() || v->getType()->isArrayTy()) { - vi = builder.CreateExtractValue(v,ArrayRef((unsigned)i)); - } else { - assert(v->getType()->isVectorTy()); - vi = builder.CreateExtractElement(v,ConstantInt::get(T_int32,i)); - } + Value *vi = emit_tupleref(v,ConstantInt::get(T_size,i+1),jt,ctx); emit_tupleset(tpl,ConstantInt::get(T_size,i+1),boxed(vi,ctx,jti),jt,ctx); } ctx->argDepth--; diff --git a/src/codegen.cpp b/src/codegen.cpp index a2c3805ac3215..0df2a0c6f2559 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -215,6 +215,9 @@ static Function *jlputs_func; static Function *resetstkoflw_func; #endif +// NoopType +static Type *NoopType; + static void jl_rethrow_with_add(const char *fmt, ...) { if (jl_typeis(jl_exception_in_transit, jl_errorexception_type)) { @@ -294,9 +297,9 @@ extern "C" void jl_generate_fptr(jl_function_t *f) if (li->cFunctionObject != NULL) (void)jl_ExecutionEngine->getPointerToFunction((Function*)li->cFunctionObject); JL_SIGATOMIC_END(); - llvmf->deleteBody(); - if (li->cFunctionObject != NULL) - ((Function*)li->cFunctionObject)->deleteBody(); + //llvmf->deleteBody(); + //if (li->cFunctionObject != NULL) + //((Function*)li->cFunctionObject)->deleteBody(); } f->fptr = li->fptr; } @@ -365,12 +368,39 @@ void *jl_function_ptr(jl_function_t *f, jl_value_t *rt, jl_value_t *argt) #include "debuginfo.cpp" #include "disasm.cpp" +const jl_value_t *jl_dump_llvmf(void *f, bool dumpasm) +{ + std::string code; + llvm::raw_string_ostream stream(code); + llvm::formatted_raw_ostream fstream(stream); + Function *llvmf = (Function*)f; + if (dumpasm == false) { + llvmf->print(stream); + } + else { + size_t fptr = (size_t)jl_ExecutionEngine->getPointerToFunction(llvmf); + std::map &fmap = jl_jit_events->getMap(); + std::map::iterator fit = fmap.find(fptr); + + if (fit == fmap.end()) { + JL_PRINTF(JL_STDERR, "Warning: Unable to find function pointer\n"); + return jl_cstr_to_string(const_cast("")); + } + jl_dump_function_asm((void*)fptr, fit->second.lengthAdr, fit->second.lines, fstream); + fstream.flush(); + } + return jl_cstr_to_string(const_cast(stream.str().c_str())); +} + extern "C" DLLEXPORT -const jl_value_t *jl_dump_function(jl_function_t *f, jl_tuple_t *types, bool dumpasm) +const jl_value_t *jl_dump_function(jl_function_t *f, jl_tuple_t *types, bool dumpasm, bool dumpwrapper) { - if (!jl_is_function(f) || !jl_is_gf(f)) - return jl_cstr_to_string(const_cast("")); - jl_function_t *sf = jl_get_specialization(f, types); + jl_function_t *sf = f; + if (types != NULL) { + if (!jl_is_function(f) || !jl_is_gf(f)) + return jl_cstr_to_string(const_cast("")); + sf = jl_get_specialization(f, types); + } if (sf == NULL || sf->linfo == NULL) { sf = jl_method_lookup_by_type(jl_gf_mtable(f), types, 0, 0); if (sf == jl_bottom_func) @@ -378,15 +408,12 @@ const jl_value_t *jl_dump_function(jl_function_t *f, jl_tuple_t *types, bool dum JL_PRINTF(JL_STDERR, "Warning: Returned code may not match what actually runs.\n"); } - std::string code; - llvm::raw_string_ostream stream(code); - llvm::formatted_raw_ostream fstream(stream); Function *llvmf; if (sf->linfo->functionObject == NULL) { jl_compile(sf); } if (sf->fptr == &jl_trampoline) { - if (sf->linfo->cFunctionObject != NULL) + if (!dumpwrapper && sf->linfo->cFunctionObject != NULL) llvmf = (Function*)sf->linfo->cFunctionObject; else llvmf = (Function*)sf->linfo->functionObject; @@ -394,24 +421,10 @@ const jl_value_t *jl_dump_function(jl_function_t *f, jl_tuple_t *types, bool dum else { llvmf = to_function(sf->linfo, false); } - if (dumpasm == false) { - llvmf->print(stream); - } - else { - size_t fptr = (size_t)jl_ExecutionEngine->getPointerToFunction(llvmf); - std::map &fmap = jl_jit_events->getMap(); - std::map::iterator fit = fmap.find(fptr); - - if (fit == fmap.end()) { - JL_PRINTF(JL_STDERR, "Warning: Unable to find function pointer\n"); - return jl_cstr_to_string(const_cast("")); - } - jl_dump_function_asm((void*)fptr, fit->second.lengthAdr, fit->second.lines, fstream); - fstream.flush(); - } - return jl_cstr_to_string(const_cast(stream.str().c_str())); + return jl_dump_llvmf(llvmf,dumpasm); } + // --- code generation --- // per-local-variable information @@ -1321,7 +1334,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, else { Value *arg1 = emit_expr(args[1], ctx); JL_GC_POP(); - return emit_tuplelen(arg1); + return emit_tuplelen(arg1,aty); } } } @@ -1374,7 +1387,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, return V_null; } } - Value *tlen = emit_tuplelen(arg1); + Value *tlen = emit_tuplelen(arg1,tty); Value *idx = emit_unbox(T_size, emit_unboxed(args[2], ctx), ity); emit_bounds_check(idx, tlen, ctx); @@ -1406,7 +1419,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, for (size_t i = 0; i < nargs; ++i) { Type *ety = NULL; if (tpl != NULL) - ety = jl_llvmtuple_eltype(tpl->getType(),i); + ety = jl_llvmtuple_eltype(tpl->getType(),tt,i); if(tpl == NULL || ety == T_void) { emit_expr(args[i+1],ctx); //for side effects (if any) @@ -1768,6 +1781,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, } if (at == jl_pvalue_llvmt) { argvals[idx] = boxed(emit_expr(args[i+1], ctx),ctx,expr_type(args[i+1],ctx)); + assert(dyn_cast(argvals[idx]) == 0); if (might_need_root(args[i+1])) { make_gcroot(argvals[idx], ctx); } @@ -1776,6 +1790,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, assert(at == et); argvals[idx] = emit_unbox(at, emit_unboxed(args[i+1], ctx),jl_tupleref(f->linfo->specTypes,i)); + assert(dyn_cast(argvals[idx]) == 0); } idx++; } @@ -1897,7 +1912,7 @@ static Value *ghostValue(jl_value_t *ty) assert(llvmty != T_void); return UndefValue::get(llvmty); } else - return NULL; + return mark_julia_type(UndefValue::get(NoopType),ty); } static Value *emit_var(jl_sym_t *sym, jl_value_t *ty, jl_codectx_t *ctx, bool isboxed) @@ -2633,6 +2648,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct Value *argPtr = builder.CreateGEP(argArray, ConstantInt::get(T_size, argIdx)); 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)) { @@ -2640,7 +2656,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct assert(lty != NULL); if (lty == T_void) continue; - theArg = emit_unbox(lty, theArg, ty); + theNewArg = emit_unbox(lty, theArg, ty); } else if(jl_is_tuple(ty)) { Type *lty = julia_struct_to_llvm(ty); @@ -2648,10 +2664,11 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct { if (lty == T_void) continue; - theArg = emit_unbox(lty, theArg, ty); + theNewArg = emit_unbox(lty, theArg, ty); } } - args[idx] = theArg; + assert(dyn_cast(theNewArg) == NULL); + args[idx] = theNewArg; idx++; } // TODO: consider pulling the function pointer out of fArg so these @@ -3326,6 +3343,10 @@ static void init_julia_llvm_env(Module *m) T_pfloat64 = PointerType::get(T_float64, 0); T_void = Type::getVoidTy(jl_LLVMContext); + // This type is used to create undef Values which carry + // metadata. + NoopType = StructType::create("NOOP",T_int1,NULL); + // add needed base definitions to our LLVM environment StructType *valueSt = StructType::create(getGlobalContext(), "jl_value_t"); Type *valueStructElts[1] = { PointerType::getUnqual(valueSt) }; diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 0284d258ed31d..dc39036f5deb3 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -162,50 +162,37 @@ static Value *emit_unboxed(jl_value_t *e, jl_codectx_t *ctx) return emit_expr(e, ctx, false); } -static Type *jl_llvmtuple_eltype(Type *tuple, size_t i) +static Type *jl_llvmtuple_eltype(Type *tuple, jl_value_t *jt, size_t i) { Type *ety = NULL; - if (tuple->isStructTy()) - ety = dyn_cast(tuple)->getElementType(i); - else if(tuple->isArrayTy()) + if(tuple->isArrayTy()) ety = dyn_cast(tuple)->getElementType(); else if(tuple->isVectorTy()) ety = dyn_cast(tuple)->getElementType(); else if(tuple == T_void) ety = T_void; + else if (tuple->isStructTy()) { + ety = julia_type_to_llvm(jl_tupleref((jl_tuple_t*)jt,i)); + } else assert(false); return ety; } -static size_t jl_llvmtuple_nargs(Type *tuple) -{ - size_t n = 0; - if (tuple->isStructTy()) - n = dyn_cast(tuple)->getNumElements(); - else if(tuple->isArrayTy()) - n = dyn_cast(tuple)->getNumElements(); - else if(tuple->isVectorTy()) - n = dyn_cast(tuple)->getNumElements(); - else - assert(false); - return n; -} - static Value *ghostValue(jl_value_t *ty); // emit code to unpack a raw value from a box static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt) { - if (x == NULL) { + Type *ty = (x == NULL) ? NULL : x->getType(); + if (x == NULL || ty == NoopType) { if (to == T_void) { if (jt != NULL) - return ghostValue(jt); + return (ty == NoopType && julia_type_of(x) == jt) ? x : ghostValue(jt); return NULL; } return UndefValue::get(to); } - Type *ty = x->getType(); if (ty != jl_pvalue_llvmt) { // bools are stored internally as int8 (for now) if (ty == T_int1 && to == T_int8) @@ -232,22 +219,12 @@ static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt) assert(jl_is_tuple(jt)); assert(to != T_void); Value *tpl = UndefValue::get(to); - size_t n = 0; - if (to->isStructTy()) - n = dyn_cast(to)->getNumElements(); - else if(to->isArrayTy()) - n = dyn_cast(to)->getNumElements(); - else if(to->isVectorTy()) - n = dyn_cast(to)->getNumElements(); - else - assert(false); - assert(n == jl_tuple_len(jt)); - for (size_t i = 0; i < n; ++i) { - Type *ety = jl_llvmtuple_eltype(to,i); + for (size_t i = 0; i < jl_tuple_len(jt); ++i) { + Type *ety = jl_llvmtuple_eltype(to,jt,i); if(ety == T_void) continue; - Value *elt = emit_unbox(ety, - emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL),jl_tupleref(jt,i)); + Value *ref = emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL); + Value *elt = emit_unbox(ety,ref,julia_type_of(ref)); tpl = emit_tupleset(tpl,ConstantInt::get(T_size,i+1),elt,jt,NULL); } return tpl; From 0e2c3e6cce8c1bb6dfdcbe506ba7f617ec1ad5eb Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 25 Oct 2013 15:28:25 -0400 Subject: [PATCH 18/53] Fix a missing JL_GC_POP --- src/ccall.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ccall.cpp b/src/ccall.cpp index 6fafe043695d4..c11579faadc5a 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -626,6 +626,8 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) CallInst *inst = builder.CreateCall(f,ArrayRef(&argvals[0],nargt)); ctx->to_inline.push_back(inst); + JL_GC_POP(); + return mark_julia_type(inst,rt); } From f8b79c45f611863a626a379ac1f691c6dd0989a8 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 26 Oct 2013 19:02:12 -0400 Subject: [PATCH 19/53] Fix ifelse on the tuple branch --- src/intrinsics.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index dc39036f5deb3..07aefcd207e24 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -386,7 +386,8 @@ static Value *generic_box(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx) } else { if (vxt->getPrimitiveSizeInBits() != llvmt->getPrimitiveSizeInBits()) { - return emit_error("box: argument is of incorrect size", ctx); + emit_error("box: argument is of incorrect size", ctx); + return vx; } vx = builder.CreateBitCast(vx, llvmt); } @@ -725,8 +726,8 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, } else { return builder.CreateSelect(isfalse, - boxed(emit_expr(args[3], ctx, false)), - boxed(emit_expr(args[2], ctx, false))); + boxed(emit_expr(args[3], ctx, false),ctx,expr_type(args[3],ctx)), + boxed(emit_expr(args[2], ctx, false),ctx,expr_type(args[2],ctx))); } } default: ; From 8217d70305d191b3227d1863de63ebba5d716771 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 16 Nov 2013 17:29:52 -0500 Subject: [PATCH 20/53] Merge some bugfixes from MCJIT branch --- src/cgutils.cpp | 36 +++++++++++++++++++----------------- src/codegen.cpp | 6 +++++- src/julia.h | 2 +- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index bf992aa6c24a7..23280ea331604 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -85,7 +85,9 @@ static Type *julia_type_to_llvm(jl_value_t *jt) break; } if (purebits) { - if (isvector) { + // Can't be bool due to + // http://llvm.org/bugs/show_bug.cgi?id=12618 + if (isvector && type != T_int1) { Type *ret = NULL; if(type == T_void) return T_void; @@ -694,10 +696,10 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl ConstantInt::get(T_int32, ctx->lineno)); builder.CreateUnreachable(); // Now for the cases - for (size_t i = 1,j = 0; i <= n; ++i) { + for (size_t i = 0,j = 0; i < jl_tuple_len(jt); ++i) { BasicBlock *blk = BasicBlock::Create(getGlobalContext(),"case",ctx->f); builder.SetInsertPoint(blk); - jl_value_t *jltype = jl_tupleref(jt,i-1); + jl_value_t *jltype = jl_tupleref(jt,i); Type *ty = julia_struct_to_llvm(jltype); if (ty != T_void) { @@ -708,7 +710,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl builder.CreateStore(tuple,ret); } builder.CreateBr(after); - sw->addCase(ConstantInt::get((IntegerType*)T_size,i),blk); + sw->addCase(ConstantInt::get((IntegerType*)T_size,i+1),blk); } builder.SetInsertPoint(after); ret = builder.CreateLoad(ret); @@ -719,7 +721,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl } // Julia semantics -static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t *ctx) +static Value *emit_tupleref(Value *tuple, Value *ival, jl_value_t *jt, jl_codectx_t *ctx) { if (tuple == NULL) { // A typecheck must have caught this one @@ -730,25 +732,25 @@ static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t if (ty == jl_pvalue_llvmt) //boxed { #ifdef OVERLAP_TUPLE_LEN - Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt),i); + Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt),ival); #else Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), - builder.CreateAdd(ConstantInt::get(T_size,1),i)); + builder.CreateAdd(ConstantInt::get(T_size,1),ival)); #endif return builder.CreateLoad(slot); } else { if (ty->isVectorTy()) { - Type *ity = i->getType(); + Type *ity = ival->getType(); assert(ity->isIntegerTy()); IntegerType *iity = dyn_cast(ity); // ExtractElement needs i32 *sigh* if(iity->getBitWidth() > 32) - i = builder.CreateTrunc(i,T_int32); + ival = builder.CreateTrunc(ival,T_int32); else if(iity->getBitWidth() < 32) - i = builder.CreateZExt(i,T_int32); - return builder.CreateExtractElement(tuple,builder.CreateSub(i,ConstantInt::get(T_int32,1))); + ival = builder.CreateZExt(ival,T_int32); + return builder.CreateExtractElement(tuple,builder.CreateSub(ival,ConstantInt::get(T_int32,1))); } - ConstantInt *idx = dyn_cast(i); + ConstantInt *idx = dyn_cast(ival); if (idx != 0) { unsigned ci = (unsigned)idx->getZExtValue()-1; size_t n = jl_tuple_len(jt); @@ -775,7 +777,7 @@ static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t builder.CreateStore(tuple,tempSpace); Value *idxs[2]; idxs[0] = ConstantInt::get(T_size,0); - idxs[1] = builder.CreateSub(i,ConstantInt::get(T_size,1)); + idxs[1] = builder.CreateSub(ival,ConstantInt::get(T_size,1)); return builder.CreateLoad(builder.CreateGEP(tempSpace,ArrayRef(&idxs[0],2))); } else @@ -787,18 +789,18 @@ static Value *emit_tupleref(Value *tuple, Value *i, jl_value_t *jt, jl_codectx_t 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(i,deflt,n); + 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 = 1, j = 0; i <= n; ++i) { + 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),blk); + sw->addCase(ConstantInt::get((IntegerType*)T_size,i+1),blk); builder.SetInsertPoint(blk); - jl_value_t *jltype = jl_tupleref(jt,i-1); + jl_value_t *jltype = jl_tupleref(jt,i); Type *ty = julia_struct_to_llvm(jltype); Value *val; if (ty != T_void) diff --git a/src/codegen.cpp b/src/codegen.cpp index 0df2a0c6f2559..081c6f1caddba 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2000,7 +2000,11 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx) if (bp != NULL) { Type *vt = bp->getType(); if (vt->isPointerTy() && vt->getContainedType(0)!=jl_pvalue_llvmt) { - rval = emit_unbox(vt->getContainedType(0), emit_unboxed(r, ctx), rt); + // TODO: `rt` is techincally correct here, but sometimes we're not propagating type information + // properly, so `rt` is a union type, while LLVM know that it's not. However, in order for this to + // happen, we need to already be sure somewhere that we have the right type, so vi.declType is fine + // even if not techincally correct. + rval = emit_unbox(vt->getContainedType(0), emit_unboxed(r, ctx), vi.declType); } else { rval = boxed(emit_expr(r, ctx, true),ctx,rt); diff --git a/src/julia.h b/src/julia.h index 9414d707bf302..3174e9930bf43 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1094,7 +1094,7 @@ extern DLLEXPORT jl_gcframe_t *jl_pgcstack; jl_pgcstack = (jl_gcframe_t*)__gc_stkf; #define JL_GC_PUSHARGS(rts_var,n) \ - rts_var = ((jl_value_t**)alloca(((n)+2)*sizeof(jl_value_t*)))+2; \ + rts_var = ((jl_value_t**)__builtin_alloca(((n)+2)*sizeof(jl_value_t*)))+2; \ ((void**)rts_var)[-2] = (void*)(((size_t)n)<<1); \ ((void**)rts_var)[-1] = jl_pgcstack; \ jl_pgcstack = (jl_gcframe_t*)&(((void**)rts_var)[-2]) From 71a5def65e5279de63a71cd049b75bbe601532e9 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 16 Nov 2013 19:44:43 -0500 Subject: [PATCH 21/53] Fix build failure after merge --- src/ccall.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index c11579faadc5a..e75c706a49add 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -580,13 +580,8 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) make_gcroot(arg, ctx); } #endif - /* - static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, - jl_value_t *argex, bool addressOf, - int argn, jl_codectx_t *ctx, - bool *mightNeedTempSpace) */ bool mightNeedTempSpace = false; - argvals[i] = julia_to_native(t,tti,arg,argi,false,i,ctx,&mightNeedTempSpace); + argvals[i] = julia_to_native(t,tti,arg,argi,false,i,ctx,&mightNeedTempSpace,&mightNeedTempSpace); if ((i+1) != nargt) argstream << ","; } From 665ffe5ed021f574e16ebbab479c3bf0398b5775 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 19 Nov 2013 01:35:14 -0500 Subject: [PATCH 22/53] Cleanup --- base/fftw.jl | 2 +- src/ccall.cpp | 5 ++-- src/cgutils.cpp | 68 ++++++++++++++++++++++--------------------------- src/codegen.cpp | 59 +++++++++++++++++------------------------- src/gc.c | 6 ----- src/julia.h | 3 +-- 6 files changed, 57 insertions(+), 86 deletions(-) diff --git a/base/fftw.jl b/base/fftw.jl index d3aac272f9ac5..5c7af7b648a46 100644 --- a/base/fftw.jl +++ b/base/fftw.jl @@ -233,7 +233,7 @@ Plan{T<:fftwNumber}(plan::Ptr{Void}, X::StridedArray{T}) = Plan{T}(plan, size(X) # throw an informative error if not: function assert_applicable{T<:fftwNumber}(p::Plan{T}, X::StridedArray{T}) if size(X) != p.sz - throw(ArgumentError("FFTW plan applied to wrong-size array (expected $(p.sz), got $(size(X))")) + throw(ArgumentError("FFTW plan applied to wrong-size array")) elseif strides(X) != p.istride throw(ArgumentError("FFTW plan applied to wrong-strides array")) elseif alignment_of(X) != p.ialign diff --git a/src/ccall.cpp b/src/ccall.cpp index e75c706a49add..81c2179bcb3ac 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -598,7 +598,6 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) << jl_string_data(ir) << "\n}"; SMDiagnostic Err = SMDiagnostic(); std::string ir_string = ir_stream.str(); - JL_PUTS((char*)ir_string.data(),JL_STDERR); Module *m = ParseAssemblyString(ir_string.data(),jl_Module,Err,jl_LLVMContext); if (m == NULL) { std::string message = "Failed to parse LLVM Assembly: \n"; @@ -616,8 +615,8 @@ static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) * function. This also has the benefit of looking exactly like we cut/pasted it in in `code_llvm`. */ f->setLinkage(GlobalValue::LinkOnceODRLinkage); - f->dump(); - // the actual call + + // the actual call CallInst *inst = builder.CreateCall(f,ArrayRef(&argvals[0],nargt)); ctx->to_inline.push_back(inst); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 23280ea331604..2437537f51907 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -96,7 +96,8 @@ static Type *julia_type_to_llvm(jl_value_t *jt) else ret = ArrayType::get(type,ntypes); return ret; - } else { + } + else { Type *types[ntypes]; size_t j = 0; for (size_t i = 0; i < ntypes; ++i) { @@ -604,8 +605,7 @@ static Value *emit_tuplelen(Value *t,jl_value_t *jt) if (t == NULL) return ConstantInt::get(T_size,0); Type *ty = t->getType(); - if (ty == jl_pvalue_llvmt) //boxed - { + if (ty == jl_pvalue_llvmt) { //boxed #ifdef OVERLAP_TUPLE_LEN Value *lenbits = emit_nthptr(t, (size_t)0); return builder.CreateLShr(builder.CreatePtrToInt(lenbits, T_int64), @@ -614,7 +614,8 @@ static Value *emit_tuplelen(Value *t,jl_value_t *jt) Value *lenbits = emit_nthptr(t, 1); return builder.CreatePtrToInt(lenbits, T_size); #endif - } else { //unboxedAg + } + else { //unboxed return ConstantInt::get(T_size,jl_tuple_len(jt)); } } @@ -627,8 +628,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl return NULL; } Type *ty = tuple->getType(); - if (ty == jl_pvalue_llvmt) //boxed - { + if (ty == jl_pvalue_llvmt) { //boxed #ifdef OVERLAP_TUPLE_LENCreateS Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), i); @@ -638,7 +638,8 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl #endif builder.CreateStore(x,slot); return tuple; - } else { + } + else { Value *ret = NULL; if (ty->isVectorTy()) { Type *ity = i->getType(); @@ -650,16 +651,15 @@ 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 { + } + else { ConstantInt *idx = dyn_cast(i); if (idx != 0) { unsigned ci = (unsigned)idx->getZExtValue()-1; size_t n = jl_tuple_len(jt); - for (size_t i=0,j = 0; iisArrayTy()) - { + else if (ty->isArrayTy()) { ArrayType *at = dyn_cast(ty); Value *tempSpace = builder.CreateAlloca(at); builder.CreateStore(tuple,tempSpace); @@ -680,8 +679,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl builder.CreateStore(x,builder.CreateGEP(tempSpace,ArrayRef(&idxs[0],2))); ret = builder.CreateLoad(tempSpace); } - else - { + else { assert(ty->isStructTy()); StructType *st = dyn_cast(ty); size_t n = st->getNumElements(); @@ -701,12 +699,12 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl builder.SetInsertPoint(blk); jl_value_t *jltype = jl_tupleref(jt,i); Type *ty = julia_struct_to_llvm(jltype); - if (ty != T_void) - { + if (ty != T_void) { Value *newAgg = builder.CreateInsertValue(tuple,x,ArrayRef(j)); builder.CreateStore(newAgg,ret); j++; - } else { + } + else { builder.CreateStore(tuple,ret); } builder.CreateBr(after); @@ -729,8 +727,7 @@ static Value *emit_tupleref(Value *tuple, Value *ival, jl_value_t *jt, jl_codect return NULL; } Type *ty = tuple->getType(); - if (ty == jl_pvalue_llvmt) //boxed - { + if (ty == jl_pvalue_llvmt) { //boxed #ifdef OVERLAP_TUPLE_LEN Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt),ival); #else @@ -738,7 +735,8 @@ 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 { + } + else { if (ty->isVectorTy()) { Type *ity = ival->getType(); assert(ity->isIntegerTy()); @@ -754,11 +752,9 @@ static Value *emit_tupleref(Value *tuple, Value *ival, jl_value_t *jt, jl_codect if (idx != 0) { unsigned ci = (unsigned)idx->getZExtValue()-1; size_t n = jl_tuple_len(jt); - for (size_t i = 0,j = 0; iisArrayTy()) - { + else if (ty->isArrayTy()) { ArrayType *at = dyn_cast(ty); Value *tempSpace = builder.CreateAlloca(at); builder.CreateStore(tuple,tempSpace); @@ -780,8 +775,7 @@ static Value *emit_tupleref(Value *tuple, Value *ival, jl_value_t *jt, jl_codect idxs[1] = builder.CreateSub(ival,ConstantInt::get(T_size,1)); return builder.CreateLoad(builder.CreateGEP(tempSpace,ArrayRef(&idxs[0],2))); } - else - { + else { assert(ty->isStructTy()); StructType *st = dyn_cast(ty); size_t n = st->getNumElements(); @@ -803,11 +797,11 @@ static Value *emit_tupleref(Value *tuple, Value *ival, jl_value_t *jt, jl_codect jl_value_t *jltype = jl_tupleref(jt,i); Type *ty = julia_struct_to_llvm(jltype); Value *val; - if (ty != T_void) - { + if (ty != T_void) { val = boxed(builder.CreateExtractValue(tuple,ArrayRef(j)),ctx,jltype); j++; - } else { + } + else { val = boxed(NULL,ctx,jltype); } builder.CreateStore(val,ret); @@ -1029,8 +1023,6 @@ static Value *allocate_box_dynamic(Value *jlty, int nb, Value *v) return init_bits_value(newv, jlty, v->getType(), v); } -bool isGhostType(jl_value_t*); - static jl_value_t *static_void_instance(jl_value_t *jt) { if (jl_is_datatype(jt)) { @@ -1039,8 +1031,8 @@ 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) - { + } + else if (jt == jl_typeof(jl_nothing) || jt == jl_bottom_type) { return (jl_value_t*)jl_nothing; } assert(jl_is_tuple(jt)); @@ -1140,7 +1132,7 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) jl_add_linfo_root(ctx->linfo, s); return literal_pointer_val(s); } - if jl_is_tuple(jt) { + if (jl_is_tuple(jt)) { size_t n = jl_tuple_len(jt); Value *tpl = builder.CreateCall(jl_alloc_tuple_func,ConstantInt::get(T_size,n)); make_gcroot(tpl,ctx); diff --git a/src/codegen.cpp b/src/codegen.cpp index 081c6f1caddba..88cdbe35d1058 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -190,7 +190,6 @@ static Function *jlenter_func; static Function *jlleave_func; static Function *jlegal_func; static Function *jlallocobj_func; -static Function *jlalloc1w_func; static Function *jlalloc2w_func; static Function *jlalloc3w_func; static Function *jl_alloc_tuple_func; @@ -267,14 +266,14 @@ static Function *to_function(jl_lambda_info_t *li, bool cstyle) assert(f != NULL); nested_compile = last_n_c; //f->dump(); - verifyFunction(*f); + //verifyFunction(*f); FPM->run(*f); //n_compile++; // print out the function's LLVM code //ios_printf(ios_stderr, "%s:%d\n", // ((jl_sym_t*)li->file)->name, li->line); //f->dump(); - verifyFunction(*f); + //verifyFunction(*f); if (old != NULL) { builder.SetInsertPoint(old); builder.SetCurrentDebugLocation(olddl); @@ -297,9 +296,9 @@ extern "C" void jl_generate_fptr(jl_function_t *f) if (li->cFunctionObject != NULL) (void)jl_ExecutionEngine->getPointerToFunction((Function*)li->cFunctionObject); JL_SIGATOMIC_END(); - //llvmf->deleteBody(); - //if (li->cFunctionObject != NULL) - //((Function*)li->cFunctionObject)->deleteBody(); + llvmf->deleteBody(); + if (li->cFunctionObject != NULL) + ((Function*)li->cFunctionObject)->deleteBody(); } f->fptr = li->fptr; } @@ -1679,16 +1678,6 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, return NULL; } -bool isGhostType(jl_value_t *jt) -{ - if (jl_is_tuple(jt) && jl_tuple_len(jt) == 0) - return true; - else if (jl_is_datatype(jt) && !jl_is_abstracttype(jt) && (jl_datatype_t*)(jt) != jl_sym_type && - !jl_is_array_type(jt) && jl_datatype_size(jt) == 0 && jl_tuple_len(((jl_datatype_t*)(jt))->names) == 0) - return true; - return false; -} - static Value *emit_jlcall(Value *theFptr, Value *theF, jl_value_t **args, size_t nargs, jl_codectx_t *ctx) { @@ -1906,13 +1895,14 @@ static Value *emit_checked_var(Value *bp, jl_sym_t *name, jl_codectx_t *ctx) static Value *ghostValue(jl_value_t *ty) { - if (jl_is_datatype(ty)) - { + if (jl_is_datatype(ty)) { Type *llvmty = julia_struct_to_llvm(ty); assert(llvmty != T_void); return UndefValue::get(llvmty); - } else + } + else { return mark_julia_type(UndefValue::get(NoopType),ty); + } } static Value *emit_var(jl_sym_t *sym, jl_value_t *ty, jl_codectx_t *ctx, bool isboxed) @@ -2477,8 +2467,7 @@ static Value *alloc_local(jl_sym_t *s, jl_codectx_t *ctx) Type *vtype = NULL; if(store_unboxed_p(s,ctx) && s != ctx->vaName) vtype = julia_type_to_llvm(jt); - if (vtype != T_void) - { + if (vtype != T_void) { if (vtype == NULL) vtype = jl_pvalue_llvmt; lv = builder.CreateAlloca(vtype, 0, s->name); @@ -2486,8 +2475,10 @@ static Value *alloc_local(jl_sym_t *s, jl_codectx_t *ctx) mark_julia_type(lv, jt); vi.isGhost = false; assert(lv != NULL); - } else + } + else { vi.isGhost = true; + } vi.memvalue = lv; return lv; } @@ -2553,7 +2544,7 @@ static void allocate_gc_frame(size_t n_roots, jl_codectx_t *ctx) static void finalize_gc_frame(jl_codectx_t *ctx) { - if (ctx->argSpaceOffs + ctx->maxDepth == 0) { + if (ctx->argSpaceOffs + ctx->maxDepth == 0) { // 0 roots; remove gc frame entirely // replace instruction uses with Undef first to avoid LLVM assertion failures BasicBlock::iterator bbi = ctx->first_gcframe_inst; @@ -2661,11 +2652,10 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct if (lty == T_void) continue; theNewArg = emit_unbox(lty, theArg, ty); - } else if(jl_is_tuple(ty)) - { + } + else if(jl_is_tuple(ty)) { Type *lty = julia_struct_to_llvm(ty); - if (lty != jl_pvalue_llvmt) - { + if (lty != jl_pvalue_llvmt) { if (lty == T_void) continue; theNewArg = emit_unbox(lty, theArg, ty); @@ -2841,8 +2831,9 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) std::vector fsig(0); for(size_t i=0; i < jl_tuple_len(lam->specTypes); i++) { Type *ty = julia_type_to_llvm(jl_tupleref(lam->specTypes,i)); - if (ty != T_void) + if (ty != T_void) { fsig.push_back(ty); + } else { ctx.vars[jl_decl_var(jl_cellref(largs,i))].isGhost = true; } @@ -3126,7 +3117,8 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) if (lv == NULL) { if (ctx.vars[s].isGhost) { ctx.vars[s].passedAs = NULL; - } else { + } + else { // if this argument hasn't been given space yet, we've decided // to leave it in the input argument array. ctx.vars[s].passedAs = theArg; @@ -3182,7 +3174,8 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) builder.CreateStore(builder.CreateCall(jlbox_func, restTuple), lv); else builder.CreateStore(restTuple, lv); - } else { + } + else { // TODO: Perhaps allow this in the future, but for now sice varargs are always unspecialized // we don't assert(false); @@ -3586,12 +3579,6 @@ static void init_julia_llvm_env(Module *m) jl_ExecutionEngine->addGlobalMapping(jlallocobj_func, (void*)&allocobj); std::vector empty_args(0); - jlalloc1w_func = - Function::Create(FunctionType::get(jl_pvalue_llvmt, empty_args, false), - Function::ExternalLinkage, - "alloc_1w", jl_Module); - jl_ExecutionEngine->addGlobalMapping(jlalloc1w_func, (void*)&alloc_1w); - jlalloc2w_func = Function::Create(FunctionType::get(jl_pvalue_llvmt, empty_args, false), Function::ExternalLinkage, diff --git a/src/gc.c b/src/gc.c index 524630fb77807..ba6554914b0a2 100644 --- a/src/gc.c +++ b/src/gc.c @@ -991,12 +991,6 @@ void *allocobj(size_t sz) return pool_alloc(&pools[szclass(sz)]); } -void *alloc_1w(void) -{ - // For now - return allocobj(1); -} - void *alloc_2w(void) { #ifdef MEMDEBUG diff --git a/src/julia.h b/src/julia.h index 3174e9930bf43..82f20fcb9d4ac 100644 --- a/src/julia.h +++ b/src/julia.h @@ -113,7 +113,7 @@ typedef struct { */ unsigned short how:2; unsigned short isshared:1; // data is shared by multiple Arrays - unsigned short isaligned:1; // data allocated with mem + unsigned short isaligned:1; // data allocated with memalign uint16_t elsize; uint32_t offset; // for 1-d only. does not need to get big. @@ -1127,7 +1127,6 @@ void *jl_gc_managed_realloc(void *d, size_t sz, size_t oldsz, int isaligned); void jl_gc_free_array(jl_array_t *a); void jl_gc_track_malloced_array(jl_array_t *a); void jl_gc_run_all_finalizers(); -void *alloc_1w(void); void *alloc_2w(void); void *alloc_3w(void); void *alloc_4w(void); From e02db98e162df55034d1a8e0db0c07f0aff0cdf3 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 19 Nov 2013 01:41:30 -0500 Subject: [PATCH 23/53] Separate out llvmcall --- base/boot.jl | 2 +- base/inference.jl | 4 -- src/ccall.cpp | 132 --------------------------------------------- src/intrinsics.cpp | 4 +- 4 files changed, 2 insertions(+), 140 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 61ca38de2073c..ec11c1ee58347 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -145,7 +145,7 @@ export JULIA_HOME, nothing, Main, # intrinsics module Intrinsics - #ccall, cglobal, llvmcall, abs_float, add_float, add_int, and_int, ashr_int, + #ccall, cglobal, abs_float, add_float, add_int, and_int, ashr_int, #box, bswap_int, checked_fptosi, checked_fptoui, checked_sadd, #checked_smul, checked_ssub, checked_uadd, checked_umul, checked_usub, #nan_dom_err, copysign_float, ctlz_int, ctpop_int, cttz_int, diff --git a/base/inference.jl b/base/inference.jl index 4f948e4c5c871..2ca6dfa1791c1 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -114,10 +114,6 @@ t_func[nan_dom_err] = (2, 2, (a, b)->a) t_func[eval(Core.Intrinsics,:ccall)] = (3, Inf, (fptr, rt, at, a...)->(is(rt,Type{Void}) ? Nothing : isType(rt) ? rt.parameters[1] : Any)) -t_func[eval(Core.Intrinsics,:llvmcall)] = - (3, Inf, (fptr, rt, at, a...)->(is(rt,Type{Void}) ? Nothing : - isType(rt) ? rt.parameters[1] : - isa(rt,Tuple) ? map(x->x.parameters[1],rt) : Any)) t_func[eval(Core.Intrinsics,:cglobal)] = (1, 2, (fptr, t...)->(isempty(t) ? Ptr{Void} : isType(t[1]) ? Ptr{t[1].parameters[1]} : Ptr)) diff --git a/src/ccall.cpp b/src/ccall.cpp index 81c2179bcb3ac..0bd3b400a87f5 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -493,138 +493,6 @@ static Value *emit_cglobal(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) return mark_julia_type(res, rt); } -// llvmcall(ir, (rettypes...), (argtypes...), args...) -static Value *emit_llvmcall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) -{ - JL_NARGSV(llvmcall, 3) - jl_value_t *rt = NULL, *at = NULL; - JL_GC_PUSH2(&rt, &at); - { - JL_TRY { - at = jl_interpret_toplevel_expr_in(ctx->module, args[3], - &jl_tupleref(ctx->sp,0), - jl_tuple_len(ctx->sp)/2); - } - JL_CATCH { - jl_rethrow_with_add("error interpreting llvmcall return type"); - } - } - { - JL_TRY { - rt = jl_interpret_toplevel_expr_in(ctx->module, args[2], - &jl_tupleref(ctx->sp,0), - jl_tuple_len(ctx->sp)/2); - } - JL_CATCH { - jl_rethrow_with_add("error interpreting ccall argument tuple"); - } - } - JL_TYPECHK(llvmcall, type, rt); - JL_TYPECHK(llvmcall, tuple, at); - JL_TYPECHK(llvmcall, type, at); - int i = 1; - // Make sure to find a unique name - std::string ir_name; - while(true) { - std::stringstream name; - name << (ctx->f->getName().str()) << i++; - ir_name = name.str(); - if(jl_Module->getFunction(ir_name) == NULL) - break; - } - jl_value_t *ir = static_eval(args[1], ctx, true); - if (!jl_is_byte_string(ir)) - { - jl_error("First argument to llvmcall must be a string"); - } - - std::stringstream ir_stream; - - // Generate arguments - std::string arguments; - llvm::raw_string_ostream argstream(arguments); - jl_tuple_t *tt = (jl_tuple_t*)at; - size_t nargt = jl_tuple_len(tt); - Value *argvals[nargt]; - /* - * Semantics for arguments are as follows: - * If the argument type is immutable (including bitstype), we pass the loaded llvm value - * type. Otherwise we pass a pointer to a jl_value_t. - */ - for (size_t i = 0; i < nargt; ++i) - { - jl_value_t *tti = jl_tupleref(tt,i); - Type *t = julia_type_to_llvm(tti); - t->print(argstream); - argstream << " "; - jl_value_t *argi = args[4+i]; - Value *arg; - bool needroot = false; - if (t == jl_pvalue_llvmt || !jl_isbits(tti)) { - arg = emit_expr(argi, ctx, true); - if (t == jl_pvalue_llvmt && arg->getType() != jl_pvalue_llvmt) { - arg = boxed(arg, ctx); - needroot = true; - } - } - else { - arg = emit_unboxed(argi, ctx); - if (jl_is_bitstype(expr_type(argi, ctx))) { - arg = emit_unbox(t, arg, tti); - } - } - -#ifdef JL_GC_MARKSWEEP - // make sure args are rooted - if (t == jl_pvalue_llvmt && (needroot || might_need_root(argi))) { - make_gcroot(arg, ctx); - } -#endif - bool mightNeedTempSpace = false; - argvals[i] = julia_to_native(t,tti,arg,argi,false,i,ctx,&mightNeedTempSpace,&mightNeedTempSpace); - if ((i+1) != nargt) - argstream << ","; - } - - Type *rettype; - std::string rstring; - llvm::raw_string_ostream rtypename(rstring); - // Construct return type - rettype = julia_type_to_llvm(rt); - rettype->print(rtypename); - - ir_stream << "; Number of arguments: " << nargt << "\n" - << "define "<getFunction(ir_name); - /* - * It might be tempting to just try to set the Always inline attribute on the function - * and hope for the best. However, this doesn't work since that would require an inlining - * pass (which is a Call Graph pass and cannot be managed by a FunctionPassManager). Instead - * We are sneaky and call the inliner directly. This however doesn't work until we've actually - * generated the entire function, so we need to store it in the context until the end of the - * function. This also has the benefit of looking exactly like we cut/pasted it in in `code_llvm`. - */ - f->setLinkage(GlobalValue::LinkOnceODRLinkage); - - // the actual call - CallInst *inst = builder.CreateCall(f,ArrayRef(&argvals[0],nargt)); - ctx->to_inline.push_back(inst); - - JL_GC_POP(); - - return mark_julia_type(inst,rt); -} - // --- code generator for ccall itself --- // ccall(pointer, rettype, (argtypes...), args...) diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 07aefcd207e24..05dcb0999b529 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -37,7 +37,7 @@ namespace JL_I { // pointer access pointerref, pointerset, pointertoref, // c interface - ccall, cglobal, jl_alloca, llvmcall + ccall, cglobal, jl_alloca }; }; @@ -669,7 +669,6 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, switch (f) { case ccall: return emit_ccall(args, nargs, ctx); case cglobal: return emit_cglobal(args, nargs, ctx); - case llvmcall: return emit_llvmcall(args, nargs, ctx); HANDLE(box,2) return generic_box(args[1], args[2], ctx); HANDLE(unbox,2) return generic_unbox(args[1], args[2], ctx); @@ -1217,5 +1216,4 @@ extern "C" void jl_init_intrinsic_functions(void) ADD_I(nan_dom_err); ADD_I(ccall); ADD_I(cglobal); ADD_I(jl_alloca); - ADD_I(llvmcall); } From 9deb3a156cdce20846d46f9d55c12ccae8ca52df Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 20 Nov 2013 15:00:36 -0500 Subject: [PATCH 24/53] Simplify emit_tupleset, but disallowing non-constant ones --- src/cgutils.cpp | 73 ++++++++++--------------------------------------- 1 file changed, 14 insertions(+), 59 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 2437537f51907..f27afdc7887ff 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -629,7 +629,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl } Type *ty = tuple->getType(); if (ty == jl_pvalue_llvmt) { //boxed - #ifdef OVERLAP_TUPLE_LENCreateS + #ifdef OVERLAP_TUPLE_LEN Value *slot = builder.CreateGEP(builder.CreateBitCast(tuple, jl_ppvalue_llvmt), i); #else @@ -641,6 +641,8 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl } else { Value *ret = NULL; + ConstantInt *idx = dyn_cast(i); + assert(idx != NULL && "tuplesets must use constant indices"); if (ty->isVectorTy()) { Type *ity = i->getType(); assert(ity->isIntegerTy()); @@ -653,65 +655,18 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl ret = builder.CreateInsertElement(tuple,x,builder.CreateSub(i,ConstantInt::get(T_int32,1))); } else { - ConstantInt *idx = dyn_cast(i); - if (idx != 0) { - unsigned ci = (unsigned)idx->getZExtValue()-1; - size_t n = jl_tuple_len(jt); - for (size_t i=0,j = 0; i(j)); - } - if(ty != T_void) - ++j; - } - } - else if (ty->isArrayTy()) { - ArrayType *at = dyn_cast(ty); - Value *tempSpace = builder.CreateAlloca(at); - builder.CreateStore(tuple,tempSpace); - Value *idxs[2]; - idxs[0] = ConstantInt::get(T_size,0); - idxs[1] = builder.CreateSub(i,ConstantInt::get(T_size,1)); - builder.CreateStore(x,builder.CreateGEP(tempSpace,ArrayRef(&idxs[0],2))); - ret = builder.CreateLoad(tempSpace); - } - else { - assert(ty->isStructTy()); - StructType *st = dyn_cast(ty); - size_t n = st->getNumElements(); - Value *ret = builder.CreateAlloca(st); - 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(i,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); - builder.SetInsertPoint(blk); - jl_value_t *jltype = jl_tupleref(jt,i); - Type *ty = julia_struct_to_llvm(jltype); - if (ty != T_void) { - Value *newAgg = builder.CreateInsertValue(tuple,x,ArrayRef(j)); - builder.CreateStore(newAgg,ret); - j++; - } - else { - builder.CreateStore(tuple,ret); - } - builder.CreateBr(after); - sw->addCase(ConstantInt::get((IntegerType*)T_size,i+1),blk); + unsigned ci = (unsigned)idx->getZExtValue()-1; + size_t n = jl_tuple_len(jt); + for (size_t i=0,j = 0; i(j)); } - builder.SetInsertPoint(after); - ret = builder.CreateLoad(ret); + if(ty != T_void) + ++j; } } return mark_julia_type(ret,jt); From ee26d21ccf92d54f82826074a70c77365ab55c72 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 21 Nov 2013 18:56:50 -0500 Subject: [PATCH 25/53] Add a missing GC root --- src/codegen.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 88cdbe35d1058..cda011c88d263 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1406,8 +1406,8 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, break; } if (i >= nargs) { - // all arguments immutable; can be statically evaluated jl_value_t *tt = (jl_value_t*)jl_alloc_tuple_uninit(nargs); + JL_GC_PUSH1(&tt); for(i=0; i < nargs; i++) { jl_tupleset(tt, i, expr_type(args[i+1],ctx)); } @@ -1430,6 +1430,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, tpl = emit_tupleset(tpl,ConstantInt::get(T_size,i+1),elt,tt,ctx); } JL_GC_POP(); + JL_GC_POP(); return tpl; } @@ -2682,8 +2683,6 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct finalize_gc_frame(&ctx); builder.CreateRet(r); - verifyFunction(*w); - return w; } From f9999b1c82fb7177b3357df4284963f98debb75b Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 22 Nov 2013 22:40:42 -0500 Subject: [PATCH 26/53] Fix an improperly adjusted gc frame Conflicts: src/cgutils.cpp --- src/cgutils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index f27afdc7887ff..358b746ce0f43 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1090,6 +1090,7 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) if (jl_is_tuple(jt)) { size_t n = jl_tuple_len(jt); Value *tpl = builder.CreateCall(jl_alloc_tuple_func,ConstantInt::get(T_size,n)); + int last_depth = ctx->argDepth; make_gcroot(tpl,ctx); for (size_t i = 0; i < n; ++i) { @@ -1097,7 +1098,7 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) Value *vi = emit_tupleref(v,ConstantInt::get(T_size,i+1),jt,ctx); emit_tupleset(tpl,ConstantInt::get(T_size,i+1),boxed(vi,ctx,jti),jt,ctx); } - ctx->argDepth--; + ctx->argDepth = last_depth; return tpl; } jl_datatype_t *jb = (jl_datatype_t*)jt; From a7d99e67d22e6e30c72bd5671481004668d35495 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 27 Nov 2013 17:27:37 -0500 Subject: [PATCH 27/53] Fix vararg root counting --- src/codegen.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index cda011c88d263..a0917310c31fc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2457,7 +2457,9 @@ static bool store_unboxed_p(jl_sym_t *s, jl_codectx_t *ctx) return (ctx->linfo->inferred && jltupleisbits(jt,false) && // don't unbox intrinsics, since inference depends on their having // stable addresses for table lookup. - jt != (jl_value_t*)jl_intrinsic_type && !vi.isCaptured); + jt != (jl_value_t*)jl_intrinsic_type && !vi.isCaptured && + // don't unbox vararg tuples + s != ctx->vaName); } static Value *alloc_local(jl_sym_t *s, jl_codectx_t *ctx) @@ -2465,12 +2467,9 @@ static Value *alloc_local(jl_sym_t *s, jl_codectx_t *ctx) jl_varinfo_t &vi = ctx->vars[s]; jl_value_t *jt = vi.declType; Value *lv = NULL; - Type *vtype = NULL; - if(store_unboxed_p(s,ctx) && s != ctx->vaName) - vtype = julia_type_to_llvm(jt); + assert(store_unboxed_p(s,ctx)); + Type *vtype = julia_type_to_llvm(jt); if (vtype != T_void) { - if (vtype == NULL) - vtype = jl_pvalue_llvmt; lv = builder.CreateAlloca(vtype, 0, s->name); if (vtype != jl_pvalue_llvmt) mark_julia_type(lv, jt); From d5ad8e62f0f882bf509e7604c6cb6dbb2f375b85 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 27 Nov 2013 17:30:05 -0500 Subject: [PATCH 28/53] Fix a rebase conflict --- src/ccall.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 0bd3b400a87f5..022e9a18779a5 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -800,16 +800,14 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) arg = emit_unboxed(argi, ctx); if (jl_is_bitstype(expr_type(argi, ctx))) { Type *at = arg->getType(); + Type *totype = addressOf ? largty->getContainedType(0) : largty; if (at != jl_pvalue_llvmt && at != totype && !(at->isPointerTy() && jargty==(jl_value_t*)jl_voidpointer_type)) { emit_type_error(arg, jargty, "ccall", ctx); arg = UndefValue::get(totype); } else { - if (addressOf) - arg = emit_unbox(largty->getContainedType(0), arg, jargty); - else - arg = emit_unbox(largty, arg, jargty); + arg = emit_unbox(totype, arg, jargty); } } } From 7caa198e0607787194b0c6a1f19012aff04e3620 Mon Sep 17 00:00:00 2001 From: timholy Date: Sun, 1 Dec 2013 05:44:45 -0600 Subject: [PATCH 29/53] Rationalize return types of tridiag and Woodbury solve!() --- base/linalg/tridiag.jl | 7 +++++-- base/linalg/woodbury.jl | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/base/linalg/tridiag.jl b/base/linalg/tridiag.jl index 1680e16e62347..d557a5e190131 100644 --- a/base/linalg/tridiag.jl +++ b/base/linalg/tridiag.jl @@ -226,10 +226,13 @@ function solve!{T<:BlasFloat}(x::AbstractArray{T}, xrng::Ranges{Int}, M::Tridiag x[ix] = xlast ix -= xstride end - x + nothing end -solve!(x::StridedVector, M::Tridiagonal, rhs::StridedVector) = solve!(x, 1:length(x), M, rhs, 1:length(rhs)) +function solve!(x::StridedVector, M::Tridiagonal, rhs::StridedVector) + solve!(x, 1:length(x), M, rhs, 1:length(rhs)) + x +end solve{TM<:BlasFloat,TB<:BlasFloat}(M::Tridiagonal{TM}, B::StridedVecOrMat{TB}) = solve!(zeros(typeof(one(TM)/one(TB)), size(B)), M, B) solve(M::Tridiagonal, B::StridedVecOrMat) = solve(float(M), float(B)) function solve!(X::StridedMatrix, M::Tridiagonal, B::StridedMatrix) diff --git a/base/linalg/woodbury.jl b/base/linalg/woodbury.jl index dd6c0d043e993..c706e31e1bf52 100644 --- a/base/linalg/woodbury.jl +++ b/base/linalg/woodbury.jl @@ -90,9 +90,13 @@ function solve!(x::AbstractArray, xrng::Ranges{Int}, W::Woodbury, rhs::AbstractA x[indx] = W.tmpN1[i] - W.tmpN2[i] indx += xinc end + nothing end -solve!(x::AbstractVector, W::Woodbury, rhs::AbstractVector) = solve!(x, 1:length(x), W, rhs, 1:length(rhs)) +function solve!(x::AbstractVector, W::Woodbury, rhs::AbstractVector) + solve!(x, 1:length(x), W, rhs, 1:length(rhs)) + x +end solve(W::Woodbury, rhs::AbstractVector) = solve!(similar(rhs), W, rhs) solve(W::Woodbury, B::StridedMatrix)=solve!(similar(B), W, B) function solve!(X::StridedMatrix, W::Woodbury, B::StridedMatrix) From 66f0552daed848ff23f203e073506a85a1f97103 Mon Sep 17 00:00:00 2001 From: Andreas Noack Jensen Date: Mon, 2 Dec 2013 08:54:08 +0100 Subject: [PATCH 30/53] Define integer indexing for Hermitian, Symmetric and Triangular, and symmetrize matrices when calling full --- base/linalg/hermitian.jl | 4 ++-- base/linalg/symmetric.jl | 4 ++-- base/linalg/triangular.jl | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/base/linalg/hermitian.jl b/base/linalg/hermitian.jl index 9c222ffeadc7f..e4f7f4f4179c4 100644 --- a/base/linalg/hermitian.jl +++ b/base/linalg/hermitian.jl @@ -16,8 +16,8 @@ function copy!(A::Hermitian, B::Hermitian) A end size(A::Hermitian, args...) = size(A.S, args...) -print_matrix(io::IO, A::Hermitian, rows::Integer, cols::Integer) = print_matrix(io, full(A), rows, cols) -full(A::Hermitian) = A.S +getindex(A::Hermitian, i::Integer, j::Integer) = (A.uplo == 'U') == (i < j) ? getindex(A.S, i, j) : conj(getindex(A.S, j, i)) +full(A::Hermitian) = symmetrize_conj!(A.S, A.uplo) ishermitian(A::Hermitian) = true issym{T<:Real}(A::Hermitian{T}) = true issym{T<:Complex}(A::Hermitian{T}) = all(imag(A.S) .== 0) diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index 8211c3f64afab..854fe25984dc1 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -16,8 +16,8 @@ function copy!(A::Symmetric, B::Symmetric) A end size(A::Symmetric, args...) = size(A.S, args...) -print_matrix(io::IO, A::Symmetric, rows::Integer, cols::Integer) = print_matrix(io, full(A), rows, cols) -full(A::Symmetric) = A.S +getindex(A::Symmetric, i::Integer, j::Integer) = (A.uplo == 'U') == (i < j) ? getindex(A.S, i, j) : getindex(A.S, j, i) +full(A::Symmetric) = symmetrize!(A.S, A.uplo) ishermitian{T<:Real}(A::Symmetric{T}) = true ishermitian{T<:Complex}(A::Symmetric{T}) = all(imag(A.S) .== 0) issym(A::Symmetric) = true diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index 88c9eaae32644..9fe27eda20de1 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -16,9 +16,9 @@ function Triangular(A::Matrix) end size(A::Triangular, args...) = size(A.UL, args...) -full(A::Triangular) = (istril(A) ? tril : triu)(A.UL) +full(A::Triangular) = (istril(A) ? tril! : triu!)(A.UL) -print_matrix(io::IO, A::Triangular, rows::Integer, cols::Integer) = print_matrix(io, full(A), rows, cols) +getindex{T}(A::Triangular{T}, i::Integer, j::Integer) = i == j ? A.UL[i,j] : ((A.uplo == 'U') == (i < j) ? getindex(A.UL, i, j) : zero(T)) istril(A::Triangular) = A.uplo == 'L' istriu(A::Triangular) = A.uplo == 'U' From 0d2d89e7d3ecab70a26b10e3ab1294fab585a9a9 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Mon, 2 Dec 2013 17:12:45 -0500 Subject: [PATCH 31/53] Enable tab completion of macros in the REPL Consider '@' a word character for tab-completion purposes. --- ui/repl-readline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/repl-readline.c b/ui/repl-readline.c index ccdaf56259bc9..cce1bffb3367a 100644 --- a/ui/repl-readline.c +++ b/ui/repl-readline.c @@ -742,7 +742,7 @@ static void init_rl(void) // make sure keywords are in symbol table (void)jl_symbol(lang_keywords[i]); } - rl_completer_word_break_characters = " \t\n\"\\'`@$><=;|&{}()[],+-*/?%^~!:"; + rl_completer_word_break_characters = " \t\n\"\\'`$><=;|&{}()[],+-*/?%^~!:"; Keymap keymaps[] = {emacs_standard_keymap, vi_insertion_keymap}; int i; for (i = 0; i < sizeof(keymaps)/sizeof(keymaps[0]); i++) { From de02f6b8e0428ab35c28eeb7686cac3dad39dbd1 Mon Sep 17 00:00:00 2001 From: Tobias Knopp Date: Tue, 3 Dec 2013 01:19:44 +0100 Subject: [PATCH 32/53] Add Documentation for Embedding Julia --- doc/manual/embedding.rst | 266 +++++++++++++++++++++++++++++++++++++++ doc/manual/index.rst | 1 + 2 files changed, 267 insertions(+) create mode 100644 doc/manual/embedding.rst diff --git a/doc/manual/embedding.rst b/doc/manual/embedding.rst new file mode 100644 index 0000000000000..4ec92d7c3f1b3 --- /dev/null +++ b/doc/manual/embedding.rst @@ -0,0 +1,266 @@ +.. _man-embedding: + +.. highlight:: c + +************************** + Embedding Julia +************************** + +As we have seen (:ref:`man-calling-c-and-fortran-code`) Julia has a very simple and efficient way to call functions that are written in the C programming language. But there are various situations where actually the opposite is needed: calling Julia function from C code. This can for instance be used to integrate code that has been prototyped in Julia into a larger C/C++ project, without the need to rewrite everything in C/C++. To make this possible Julia features a C API that can be used to embed Julia into a C/C++ program. As almost all programming languages have some way to call C functions, the Julia C-API can also be used to build further language bridges (E.g. calling Julia from Python or C#). + + +High-Level Embedding +===================== + +We start with a very simple C program that initializes Julia and calls some Julia code without the need to share data between Julia and C:: + + #include + + int main(int argc, char *argv[]) + { + jl_init(NULL); + jl_eval_string("print(sqrt(2.0))"); + + return 0; + } + +In order to build this program you have to put the path to the Julia header into the include path and link against libjulia. For instance, when Julia is installed to $JULIA_DIR, one can compile the above test program test.c with gcc using:: + + gcc -o test -I$JULIA_DIR/include/julia -L$JULIA_DIR/usr/lib -ljulia test.c + +Alternatively, please have a look at the ``embedding.c`` program that can be found in the julia source tree in the ``examples/`` folder. + +The first thing that has do be done before calling any other Julia C function is to initialize Julia. This is done by calling ``jl_init``, which takes as argument a C string (``const char*``) to the location where Julia is installed. When the argument is NULL, a standard Julia location is assumed. The second statement in the test program evaluates a Julia statement using a call to ``jl_eval_string``. + +Converting Types +======================== + +While it is very nice to be able to execute a command in the Julia interpreter, it would be even more interesting to return the value of the expression to the host program. As Julia is a dynamically typed language and C is a statically typed language, we have to convert data between the type systems. Converting C values into Julia values is called `boxing`, while converting the other way around is called `unboxing`. Our improved sample program that calculates the square root of 2 in Julia and reads back the result in C looks as follows:: + + jl_value_t* ret = jl_eval_string("sqrt(2.0)"); + + if(jl_is_float64(ret)) + { + double ret_unboxed = jl_unbox_float64(ret); + printf("sqrt(2.0) in C: %e \n", ret_unboxed); + } + +The return value of ``jl_eval_string`` is a pointer of type ``jl_value_t*``. This is the C type that holds Julia values of any type. In order to check whether ``ret`` is of a specific C type, we can use the ``jl_is_...`` functions. By typing ``typeof(sqrt(2.0))`` into the Julia shell we can see that the return type is float64 (i.e. double). To convert the boxed Julia value into a C double the ``jl_unbox_float64`` function is used in the above code snippet. + +Converting C values into Julia values is as simple as the other way around. One can just use the ``jl_box_...`` functions:: + + jl_value_t* a = jl_box_float64(3.0); + jl_value_t* b = jl_box_float32(3.0f); + jl_value_t* c = jl_box_int32(3); + +As we will see next, boxing is required to call Julia functions with specific arguments. + +Calling Julia Functions +======================== + +Calling Julia function can be done with the ``jl_eval_string`` function has has been described before. While ``jl_eval_string`` can call Julia functions and access the return value, there is a more flexible way for this, which allows to easily pass arguments to the Julia function. The following code does the same as ``jl_value_t* ret = jl_eval_string("sqrt(2.0)")``:: + + jl_function_t *func = jl_get_function(jl_base_module, "sqrt"); + jl_value_t* argument = jl_box_float64(2.0); + jl_value_t* ret = jl_call1(func, argument); + +In the first step, a handle to the Julia function ``sqrt`` is retrieved by calling ``jl_get_function``. The first argument passed to ``jl_get_function`` is a global pointer to the Base module in which ``sqrt`` is defined. Then, the double value is boxed using the ``jl_box_float64`` function. Finally, in the last step, the function is called by using the ``jl_call1`` function. The first argument of ``jl_call1`` is the Julia function handle while the second argument is the actual argument for the Julia function. Note, that there are also, ``jl_call0``, ``jl_call2``, and ``jl_call3`` functions for calling Julia functions without, with 2 or with 3 arguments. The general ``jl_call`` function has the signature:: + + jl_value_t *jl_call(jl_function_t *f, jl_value_t **args, int32_t nargs) + +Its second argument ``args`` is an array of ``jl_value_t*`` arguments while ``nargs`` is the number of arguments. + +Working with Arrays +======================== + +In next example, it is shown how to exchange arrays between Julia back and forth. In order to make this highly performant, the array data will be shared between C and Julia. +Julia arrays are represented in C by the datatype ``jl_array_t*``. Basically, ``jl_array_t`` is a struct that contains: + +- Information about the datatype +- A void pointer to the data block +- Information about the sizes of the array + +To keep things simple, we start with a 1D array. Creating an array containing Float64 elements of length 10 is done by:: + + jl_value_t* array_type = jl_apply_array_type( jl_float64_type, 1 ); + jl_array_t* x = jl_alloc_array_1d(array_type , 10); + +Alternatively, if you have already allocated the array you can generate a thin wrapper around that data:: + + double* existingArray = (double*) malloc(sizeof(double)*10); + jl_array_t* x = jl_ptr_to_array_1d(array_type, existingArray, 10, 0); + +The last parameter is a boolean indicating whether Julia should take over the ownership of the data (only usefull for dynamic arrays). In order to access the data of x, we can use ``jl_array_data``:: + + double* xData = (double*) jl_array_data(x); + +This is obviously more important when letting Julia allocate the array for us. Now we can fill the array:: + + for(size_t i=0; i max) + jl_too_many_args(function_name, max); + +or equivalently ``JL_NARGS(function_name,min,max)``. General exception that are not type or argument related can be raised using the funtions:: + + void jl_error(const char *str); + void jl_errorf(const char *fmt, ...); + +While ``jl_error`` takes a simple C string, ``jl_errorf`` can be used like a ``printf`` function with variable arguments:: + + jl_errorf("An error occurred as x = %d is to large", x); + +where in this example ``x`` is assumed to be an integer. + diff --git a/doc/manual/index.rst b/doc/manual/index.rst index 18c5b5174748f..526b18b507a62 100644 --- a/doc/manual/index.rst +++ b/doc/manual/index.rst @@ -30,6 +30,7 @@ parallel-computing running-external-programs calling-c-and-fortran-code + embedding packages performance-tips style-guide From 7db03ce15011929a31f1e19ae29e343737d1c631 Mon Sep 17 00:00:00 2001 From: Joachim Dahl Date: Tue, 3 Dec 2013 14:57:17 +0100 Subject: [PATCH 33/53] fixed her2k tests in test/linalg.jl --- doc/juliadoc | 2 +- test/linalg.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/juliadoc b/doc/juliadoc index 300b72cd13fe9..7aad4d1e67fd3 160000 --- a/doc/juliadoc +++ b/doc/juliadoc @@ -1 +1 @@ -Subproject commit 300b72cd13fe9b54b938a0b49416e4d860181d0f +Subproject commit 7aad4d1e67fd328269f8ff0ef3c725807a7d03d1 diff --git a/test/linalg.jl b/test/linalg.jl index 3651720d4d1c4..567cba0ceaf6a 100644 --- a/test/linalg.jl +++ b/test/linalg.jl @@ -516,8 +516,8 @@ for elty in (Complex64, Complex128) V = convert(Array{elty, 2}, V) @test_approx_eq tril(LinAlg.BLAS.her2k('L','N',U,V)) tril(U*V' + V*U') @test_approx_eq triu(LinAlg.BLAS.her2k('U','N',U,V)) triu(U*V' + V*U') - @test_approx_eq tril(LinAlg.BLAS.her2k('L','T',U,V)) tril(U'*V + V'*U) - @test_approx_eq triu(LinAlg.BLAS.her2k('U','T',U,V)) triu(U'*V + V'*U) + @test_approx_eq tril(LinAlg.BLAS.her2k('L','C',U,V)) tril(U'*V + V'*U) + @test_approx_eq triu(LinAlg.BLAS.her2k('U','C',U,V)) triu(U'*V + V'*U) end # LAPACK tests From ccc7c2b49c700a19aa98e81b97f0ca3beb5e80ae Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Tue, 3 Dec 2013 17:49:14 -0800 Subject: [PATCH 34/53] Fix segfaulting on strstr() failure See https://groups.google.com/forum/#!topic/julia-dev/aMWL08cQDsc for details --- src/ccall.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ccall.cpp b/src/ccall.cpp index f7047171606fb..562611992b211 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -24,6 +24,9 @@ extern "C" DLLEXPORT void jl_read_sonames() char *dot = strstr(name, ".so"); i=0; + if (NULL == dot) + continue; + // Detect if this entry is for the current architecture while (!isspace(dot[++i])) ; while (isspace(dot[++i])) ; From 6243ab6910f475a75358c55d50a96112fabc8cc6 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 4 Dec 2013 11:00:05 -0500 Subject: [PATCH 35/53] add more asserts for casts --- src/ast.c | 4 ++++ src/codegen.cpp | 6 ++++++ src/gf.c | 2 +- src/interpreter.c | 8 ++++++++ src/intrinsics.cpp | 6 ++++-- src/jltypes.c | 5 +++++ src/module.c | 1 + src/toplevel.c | 2 ++ 8 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/ast.c b/src/ast.c index e2f40207c6db9..c8016ad348f21 100644 --- a/src/ast.c +++ b/src/ast.c @@ -62,6 +62,7 @@ value_t fl_invoke_julia_macro(value_t *args, uint32_t nargs) JL_TRY { margs[0] = scm_to_julia(args[0], 1); f = (jl_function_t*)jl_toplevel_eval(margs[0]); + assert(jl_is_func(f)); result = jl_apply(f, &margs[1], nargs-1); } JL_CATCH { @@ -553,6 +554,7 @@ jl_lambda_info_t *jl_wrap_expr(jl_value_t *expr) // get array of formal argument expressions jl_array_t *jl_lam_args(jl_expr_t *l) { + assert(jl_is_expr(l)); assert(l->head == lambda_sym); jl_value_t *ae = jl_exprarg(l,0); assert(jl_is_array(ae)); @@ -562,6 +564,7 @@ jl_array_t *jl_lam_args(jl_expr_t *l) // get array of local var symbols jl_array_t *jl_lam_locals(jl_expr_t *l) { + assert(jl_is_expr(l)); jl_value_t *le = jl_exprarg(l, 1); assert(jl_is_array(le)); jl_value_t *ll = jl_cellref(le, 0); @@ -572,6 +575,7 @@ jl_array_t *jl_lam_locals(jl_expr_t *l) // get array of var info records jl_array_t *jl_lam_vinfo(jl_expr_t *l) { + assert(jl_is_expr(l)); jl_value_t *le = jl_exprarg(l, 1); assert(jl_is_array(le)); jl_value_t *ll = jl_cellref(le, 1); diff --git a/src/codegen.cpp b/src/codegen.cpp index 4f60f140c948f..c897e3d9d309f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1516,6 +1516,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, 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)); return literal_pointer_val(((jl_datatype_t*)ety)->instance); } return typed_load(emit_arrayptr(ary, args[1], ctx), idx, ety, ctx); @@ -1545,6 +1546,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, if (jl_array_store_unboxed(ety) && ((jl_datatype_t*)ety)->size == 0) { // no-op, but emit expr for possible effects + assert(jl_is_datatype(ety)); emit_expr(args[2],ctx,false); } else { @@ -2131,6 +2133,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, } else if (head == const_sym) { jl_sym_t *sym = (jl_sym_t*)args[0]; + assert(jl_is_symbol(sym)); jl_binding_t *bnd = NULL; (void)var_binding_pointer(sym, &bnd, true, ctx); if (bnd) { @@ -2500,6 +2503,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) jl_array_t *vi = (jl_array_t*)jl_cellref(vinfos, i); assert(jl_is_array(vi)); jl_sym_t *vname = ((jl_sym_t*)jl_cellref(vi,0)); + assert(jl_is_symbol(vname)); jl_varinfo_t &varinfo = ctx.vars[vname]; varinfo.isAssigned = (jl_vinfo_assigned(vi)!=0); varinfo.isCaptured = (jl_vinfo_capt(vi)!=0); @@ -2516,6 +2520,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) jl_array_t *vi = (jl_array_t*)jl_cellref(vinfos, i); assert(jl_is_array(vi)); jl_sym_t *vname = ((jl_sym_t*)jl_cellref(vi,0)); + assert(jl_is_symbol(vname)); jl_varinfo_t &varinfo = ctx.vars[vname]; varinfo.closureidx = i; varinfo.isAssigned = (jl_vinfo_assigned(vi)!=0); @@ -2721,6 +2726,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) } for(i=0; i < lvarslen; i++) { jl_sym_t *s = (jl_sym_t*)jl_cellref(lvars,i); + assert(jl_is_symbol(s)); if (store_unboxed_p(s, &ctx)) { alloc_local(s, &ctx); } diff --git a/src/gf.c b/src/gf.c index e634c680462b9..29bad66229a57 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1108,7 +1108,7 @@ jl_methlist_t *jl_method_list_insert(jl_methlist_t **pml, jl_tuple_t *type, if (jl_args_morespecific((jl_value_t*)type, (jl_value_t*)l->sig)) break; if (check_amb) { - check_ambiguous(*pml, (jl_tuple_t*)type, l, + check_ambiguous(*pml, type, l, method->linfo ? method->linfo->name : anonymous_sym, method->linfo); } diff --git a/src/interpreter.c b/src/interpreter.c index 4d97722dae71d..5d9d193ee9077 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -176,6 +176,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) } else if (ex->head == assign_sym) { jl_value_t *sym = args[0]; + assert(jl_is_symbol(sym)); size_t i; for (i=0; i < nl; i++) { if (locals[i*2] == sym) { @@ -258,6 +259,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) } else if (ex->head == const_sym) { jl_value_t *sym = args[0]; + assert(jl_is_symbol(sym)); for (size_t i=0; i < nl; i++) { if (locals[i*2] == sym) { return (jl_value_t*)jl_nothing; @@ -281,6 +283,8 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) jl_value_t *para = eval(args[1], locals, nl); jl_value_t *super = NULL; JL_GC_PUSH2(¶, &super); + assert(jl_is_tuple(para)); + assert(jl_is_symbol(name)); jl_datatype_t *dt = jl_new_abstracttype(name, jl_any_type, (jl_tuple_t*)para); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); @@ -294,7 +298,9 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) jl_value_t *name = args[0]; jl_value_t *super = NULL, *para = NULL, *vnb = NULL; JL_GC_PUSH3(¶, &super, &vnb); + assert(jl_is_symbol(name)); para = eval(args[1], locals, nl); + assert(jl_is_tuple(para)); vnb = eval(args[2], locals, nl); if (!jl_is_long(vnb)) jl_errorf("invalid declaration of bits type %s", ((jl_sym_t*)name)->name); @@ -314,7 +320,9 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) else if (ex->head == compositetype_sym) { void jl_add_constructors(jl_datatype_t *t); jl_value_t *name = args[0]; + assert(jl_is_symbol(name)); jl_value_t *para = eval(args[1], locals, nl); + assert(jl_is_tuple(para)); jl_value_t *fnames = NULL; jl_value_t *super = NULL; jl_datatype_t *dt = NULL; diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index a52354fc94226..786bf4c3dc0b1 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -540,7 +540,7 @@ static Value *emit_pointerref(jl_value_t *e, jl_value_t *i, jl_codectx_t *ctx) jl_value_t *ety = jl_tparam0(aty); if (jl_is_typevar(ety)) jl_error("pointerref: invalid pointer"); - if ((jl_datatype_t*)expr_type(i, ctx) != jl_long_type) { + if (expr_type(i, ctx) != (jl_value_t*)jl_long_type) { jl_error("pointerref: invalid index type"); } Value *thePtr = auto_unbox(e,ctx); @@ -554,6 +554,7 @@ static Value *emit_pointerref(jl_value_t *e, jl_value_t *i, jl_codectx_t *ctx) if (!jl_is_structtype(ety) || jl_is_array_type(ety) || !jl_is_leaf_type(ety)) { return emit_error("pointerref: invalid pointer type", ctx); } + assert(jl_is_datatype(ety)); uint64_t size = ((jl_datatype_t*)ety)->size; Value *strct = builder.CreateCall(jlallocobj_func, @@ -583,7 +584,7 @@ static Value *emit_pointerset(jl_value_t *e, jl_value_t *x, jl_value_t *i, jl_co if (!jl_subtype(xty, ety, 0)) { return emit_error("pointerset: type mismatch in assign", ctx); } - if ((jl_datatype_t*)expr_type(i, ctx) != jl_long_type) + if (expr_type(i, ctx) != (jl_value_t*)jl_long_type) jl_error("pointerset: invalid index type"); Value *idx = emit_unbox(T_size, T_psize, emit_unboxed(i, ctx)); Value *im1 = builder.CreateSub(idx, ConstantInt::get(T_size, 1)); @@ -594,6 +595,7 @@ static Value *emit_pointerset(jl_value_t *e, jl_value_t *x, jl_value_t *i, jl_co } Value *val = emit_expr(x,ctx,true,true); assert(val->getType() == jl_pvalue_llvmt); //Boxed + assert(jl_is_datatype(ety)); uint64_t size = ((jl_datatype_t*)ety)->size; builder.CreateMemCpy(builder.CreateGEP(builder.CreateBitCast(thePtr, T_pint8), im1), builder.CreateBitCast(emit_nthptr_addr(val, (size_t)1),T_pint8), size, 1); diff --git a/src/jltypes.c b/src/jltypes.c index 9a2411a892b27..166d5f80a25b4 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -1562,6 +1562,7 @@ static jl_value_t *lookup_type(jl_typename_t *tn, jl_value_t **key, size_t n) } for(size_t i=0; i < cl; i++) { jl_datatype_t *tt = (jl_datatype_t*)data[i]; + assert(jl_is_datatype(tt)); if (typekey_compare(tt, key, n)) { if (tn == jl_type_type->name && (jl_is_typector(key[0]) != jl_is_typector(jl_tupleref(tt->parameters,0)))) @@ -1585,6 +1586,7 @@ int jl_assign_type_uid(void) static void cache_type_(jl_value_t *type) { // only cache concrete types + assert(jl_is_datatype(type)); jl_tuple_t *t = ((jl_datatype_t*)type)->parameters; if (jl_tuple_len(t) == 0) return; if (jl_is_abstracttype(type)) { @@ -1612,6 +1614,7 @@ static void cache_type_(jl_value_t *type) cache = (jl_value_t*)nc; ((jl_datatype_t*)type)->name->cache = cache; } + assert(jl_is_array(cache)); jl_cell_1d_push((jl_array_t*)cache, (jl_value_t*)type); } else { @@ -1667,6 +1670,7 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_value_t **env, size_t n, if (jl_is_uniontype(t)) { jl_tuple_t *tw = (jl_tuple_t*)inst_type_w_((jl_value_t*)((jl_uniontype_t*)t)->types, env, n, stack); + assert(jl_is_tuple(tw)); JL_GC_PUSH1(&tw); jl_value_t *res = (jl_value_t*)jl_new_uniontype(tw); JL_GC_POP(); @@ -1684,6 +1688,7 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_value_t **env, size_t n, return (jl_value_t*)t; jl_value_t *result; size_t ntp = jl_tuple_len(tp); + assert(jl_is_datatype(tc)); assert(ntp == jl_tuple_len(((jl_datatype_t*)tc)->parameters)); jl_value_t **iparams; JL_GC_PUSHARGS(iparams, ntp+2); diff --git a/src/module.c b/src/module.c index 7896bb4f7702a..e6622d7fcde10 100644 --- a/src/module.c +++ b/src/module.c @@ -13,6 +13,7 @@ jl_module_t *jl_new_module(jl_sym_t *name) { jl_module_t *m = (jl_module_t*)allocobj(sizeof(jl_module_t)); m->type = (jl_value_t*)jl_module_type; + assert(jl_is_symbol(name)); m->name = name; m->constant_table = NULL; htable_new(&m->bindings, 0); diff --git a/src/toplevel.c b/src/toplevel.c index eebc5fff7190c..5dbe79458827d 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -218,6 +218,7 @@ static jl_module_t *eval_import_path_(jl_array_t *args, int retrying) m = jl_current_module; while (1) { var = (jl_sym_t*)jl_cellref(args,i); + assert(jl_is_symbol(var)); i++; if (var != dot_sym) { if (i == jl_array_len(args)) @@ -388,6 +389,7 @@ jl_value_t *jl_toplevel_eval_flex(jl_value_t *e, int fast) if (jl_is_expr(ex) && ex->head == thunk_sym) { thk = (jl_lambda_info_t*)jl_exprarg(ex,0); assert(jl_is_lambda_info(thk)); + assert(jl_is_expr(thk->ast)); ewc = jl_eval_with_compiler_p(jl_lam_body((jl_expr_t*)thk->ast), fast); if (!ewc) { if (jl_lam_vars_captured((jl_expr_t*)thk->ast)) { From 93e37f9461d19088477addfa6e9d3ed329eeb62b Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 4 Dec 2013 11:23:37 -0500 Subject: [PATCH 36/53] update juliadoc --- doc/juliadoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/juliadoc b/doc/juliadoc index 7aad4d1e67fd3..300b72cd13fe9 160000 --- a/doc/juliadoc +++ b/doc/juliadoc @@ -1 +1 @@ -Subproject commit 7aad4d1e67fd328269f8ff0ef3c725807a7d03d1 +Subproject commit 300b72cd13fe9b54b938a0b49416e4d860181d0f From 252ee05d7793464fa445e44b773b917c7b7d71a0 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 4 Dec 2013 12:09:08 -0500 Subject: [PATCH 37/53] improve method signature errors. fixes #5018 also separate error checking code so all checks are done before making changes --- src/ast.c | 10 ++++++++++ src/jltypes.c | 6 ++++-- src/julia.h | 1 + src/toplevel.c | 45 +++++++++++++++++++++++---------------------- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/ast.c b/src/ast.c index c8016ad348f21..972284faccc40 100644 --- a/src/ast.c +++ b/src/ast.c @@ -561,6 +561,16 @@ jl_array_t *jl_lam_args(jl_expr_t *l) return (jl_array_t*)ae; } +jl_sym_t *jl_lam_argname(jl_lambda_info_t *li, int i) +{ + jl_expr_t *ast; + if (jl_is_expr(li->ast)) + ast = (jl_expr_t*)li->ast; + else + ast = (jl_expr_t*)jl_uncompress_ast(li, li->ast); + return (jl_sym_t*)jl_arrayref(jl_lam_args(ast),i); +} + // get array of local var symbols jl_array_t *jl_lam_locals(jl_expr_t *l) { diff --git a/src/jltypes.c b/src/jltypes.c index 166d5f80a25b4..6e288e471857e 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -58,11 +58,13 @@ int jl_is_type(jl_value_t *v) { if (jl_is_tuple(v)) { jl_tuple_t *t = (jl_tuple_t*)v; - size_t i; - for(i=0; i < jl_tuple_len(t); i++) { + size_t i, l = jl_tuple_len(t); + for(i=0; i < l; i++) { jl_value_t *vv = jl_tupleref(t, i); if (!jl_is_typevar(vv) && !jl_is_type(vv)) return 0; + if (i < l-1 && jl_is_vararg_type(vv)) + return 0; } return 1; } diff --git a/src/julia.h b/src/julia.h index b78d39f667d76..30c950201c39f 100644 --- a/src/julia.h +++ b/src/julia.h @@ -997,6 +997,7 @@ jl_array_t *jl_lam_args(jl_expr_t *l); jl_array_t *jl_lam_locals(jl_expr_t *l); jl_array_t *jl_lam_vinfo(jl_expr_t *l); jl_array_t *jl_lam_capt(jl_expr_t *l); +jl_sym_t *jl_lam_argname(jl_lambda_info_t *li, int i); int jl_lam_vars_captured(jl_expr_t *ast); jl_expr_t *jl_lam_body(jl_expr_t *l); DLLEXPORT jl_value_t *jl_ast_rettype(jl_lambda_info_t *li, jl_value_t *ast); diff --git a/src/toplevel.c b/src/toplevel.c index 5dbe79458827d..e81d59b9ea1f4 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -566,20 +566,14 @@ jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, // argtypes is a tuple ((types...), (typevars...)) jl_tuple_t *t = (jl_tuple_t*)jl_t1(argtypes); argtypes = (jl_tuple_t*)jl_t0(argtypes); - jl_value_t *gf; - if (bnd) { - //jl_declare_constant(bnd); - if (bnd->value != NULL && !bnd->constp) { - jl_errorf("cannot define function %s; it already has a value", - bnd->name->name); - } - bnd->constp = 1; - } - if (*bp == NULL) { - gf = (jl_value_t*)jl_new_generic_function(name); - *bp = gf; + jl_value_t *gf=NULL; + + if (bnd && bnd->value != NULL && !bnd->constp) { + jl_errorf("cannot define function %s; it already has a value", + bnd->name->name); } - else { + + if (*bp != NULL) { gf = *bp; if (!jl_is_gf(gf)) { if (jl_is_datatype(gf) && @@ -591,20 +585,14 @@ jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, } } } - JL_GC_PUSH1(&gf); - assert(jl_is_function(f)); - assert(jl_is_tuple(argtypes)); - assert(jl_is_tuple(t)); - for(size_t i=0; i < jl_tuple_len(argtypes); i++) { + size_t na = jl_tuple_len(argtypes); + for(size_t i=0; i < na; i++) { jl_value_t *elt = jl_tupleref(argtypes,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_lambda_info_t *li = f->linfo; jl_errorf("invalid type for argument %s in method definition for %s at %s:%d", - jl_is_expr(li->ast) ? - ((jl_sym_t*)jl_arrayref(jl_lam_args((jl_expr_t*)li->ast),i))->name : - "?", - name->name, li->file->name, li->line); + jl_lam_argname(li,i)->name, name->name, li->file->name, li->line); } } @@ -620,6 +608,19 @@ jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, JL_PRINTF(JL_STDERR, ".\nThe method will not be callable.\n"); } } + + if (bnd) { + bnd->constp = 1; + } + if (*bp == NULL) { + gf = (jl_value_t*)jl_new_generic_function(name); + *bp = gf; + } + JL_GC_PUSH1(&gf); + assert(jl_is_function(f)); + assert(jl_is_tuple(argtypes)); + assert(jl_is_tuple(t)); + jl_add_method((jl_function_t*)gf, argtypes, f, t); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { From 893033c4502e625956c0fd53681487d8b0440924 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 4 Dec 2013 12:25:19 -0500 Subject: [PATCH 38/53] roll back on errors during type definitions. fixes #5009 --- src/interpreter.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index 5d9d193ee9077..fc8a6b1d5a986 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -323,24 +323,36 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) assert(jl_is_symbol(name)); jl_value_t *para = eval(args[1], locals, nl); assert(jl_is_tuple(para)); - jl_value_t *fnames = NULL; + jl_value_t *temp = NULL; jl_value_t *super = NULL; jl_datatype_t *dt = NULL; - JL_GC_PUSH4(¶, &super, &fnames, &dt); - fnames = eval(args[2], locals, nl); + JL_GC_PUSH4(¶, &super, &temp, &dt); + temp = eval(args[2], locals, nl); // field names dt = jl_new_datatype((jl_sym_t*)name, jl_any_type, (jl_tuple_t*)para, - (jl_tuple_t*)fnames, NULL, + (jl_tuple_t*)temp, NULL, 0, args[6]==jl_true ? 1 : 0); dt->fptr = jl_f_ctor_trampoline; dt->ctor_factory = eval(args[3], locals, nl); + jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); + temp = b->value; // save old value + // temporarily assign so binding is available for field types jl_checked_assignment(b, (jl_value_t*)dt); - inside_typedef = 1; - dt->types = (jl_tuple_t*)eval(args[5], locals, nl); - inside_typedef = 0; - jl_check_type_tuple(dt->types, dt->name->name, "type definition"); - super = eval(args[4], locals, nl); - jl_set_datatype_super(dt, super); + + JL_TRY { + // operations that can fail + inside_typedef = 1; + dt->types = (jl_tuple_t*)eval(args[5], locals, nl); + inside_typedef = 0; + jl_check_type_tuple(dt->types, dt->name->name, "type definition"); + super = eval(args[4], locals, nl); + jl_set_datatype_super(dt, super); + } + JL_CATCH { + b->value = temp; + jl_rethrow(); + } + for(size_t i=0; i < jl_tuple_len(para); i++) { ((jl_tvar_t*)jl_tupleref(para,i))->bound = 0; } From 72400eac8d2504fbc47f78b4cea82bd7a46d635c Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 4 Dec 2013 14:15:06 -0500 Subject: [PATCH 39/53] fix #5025, ordering used by nextfloat/prevfloat --- base/float.jl | 24 ++++++++++++++++++------ test/numbers.jl | 19 +++++++++++++++---- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/base/float.jl b/base/float.jl index f93fee64796fd..8844acd3e0f61 100644 --- a/base/float.jl +++ b/base/float.jl @@ -216,6 +216,24 @@ const NaN32 = box(Float32,unbox(Uint32,0x7fc00000)) const Inf = box(Float64,unbox(Uint64,0x7ff0000000000000)) const NaN = box(Float64,unbox(Uint64,0x7ff8000000000000)) +function float_lex_order(f::Integer, delta::Integer) + # convert from signed magnitude to 2's complement and back + if f < 0 + f = oftype(f, -(f & typemax(f))) + end + f = oftype(f, f + delta) + f < 0 ? oftype(f, -(f & typemax(f))) : f +end + +nextfloat(x::Float16, i::Integer) = + reinterpret(Float16,float_lex_order(reinterpret(Int16,x), i)) +nextfloat(x::Float32, i::Integer) = + reinterpret(Float32,float_lex_order(reinterpret(Int32,x), i)) +nextfloat(x::Float64, i::Integer) = + reinterpret(Float64,float_lex_order(reinterpret(Int64,x), i)) +nextfloat(x::FloatingPoint) = nextfloat(x,1) +prevfloat(x::FloatingPoint) = nextfloat(x,-1) + @eval begin inf(::Type{Float16}) = $Inf16 nan(::Type{Float16}) = $NaN16 @@ -249,12 +267,6 @@ const NaN = box(Float64,unbox(Uint64,0x7ff8000000000000)) realmin() = realmin(Float64) realmax() = realmax(Float64) - nextfloat(x::Float16, i::Integer) = box(Float16,add_int(reinterpret(Int16,x),unbox(Int16,int16(i)))) - nextfloat(x::Float32, i::Integer) = box(Float32,add_int(unbox(Float32,x),unbox(Int32,int32(i)))) - nextfloat(x::Float64, i::Integer) = box(Float64,add_int(unbox(Float64,x),unbox(Int64,int64(i)))) - nextfloat(x::FloatingPoint) = nextfloat(x,1) - prevfloat(x::FloatingPoint) = nextfloat(x,-1) - eps(x::FloatingPoint) = isfinite(x) ? abs(nextfloat(x)-x) : nan(x) eps(::Type{Float16}) = $(box(Float16,unbox(Uint16,0x1400))) eps(::Type{Float32}) = $(box(Float32,unbox(Uint32,0x34000000))) diff --git a/test/numbers.jl b/test/numbers.jl index 475a1309db12c..882e46778795e 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -1162,22 +1162,22 @@ end @test iround(Int, 0.5) == 1 @test iround(Int, prevfloat(0.5)) == 0 @test iround(Int, -0.5) == -1 -@test iround(Int, prevfloat(-0.5)) == 0 +@test iround(Int, nextfloat(-0.5)) == 0 @test iround(Uint, 0.5) == 1 @test iround(Uint, prevfloat(0.5)) == 0 @test_throws iround(Uint, -0.5) -@test iround(Uint, prevfloat(-0.5)) == 0 +@test iround(Uint, nextfloat(-0.5)) == 0 @test iround(Int, 0.5f0) == 1 @test iround(Int, prevfloat(0.5f0)) == 0 @test iround(Int, -0.5f0) == -1 -@test iround(Int, prevfloat(-0.5f0)) == 0 +@test iround(Int, nextfloat(-0.5f0)) == 0 @test iround(Uint, 0.5f0) == 1 @test iround(Uint, prevfloat(0.5f0)) == 0 @test_throws iround(Uint, -0.5f0) -@test iround(Uint, prevfloat(-0.5f0)) == 0 +@test iround(Uint, nextfloat(-0.5f0)) == 0 # numbers that can't be rounded by trunc(x+0.5) @test iround(Int64, 2.0^52 + 1) == 4503599627370497 @@ -1579,3 +1579,14 @@ end @test nextprod([2,3,5],30) == 30 @test nextprod([2,3,5],33) == 36 + +@test nextfloat(0.0) == 5.0e-324 +@test prevfloat(0.0) == -5.0e-324 +@test nextfloat(-0.0) == 5.0e-324 +@test prevfloat(-0.0) == -5.0e-324 +@test nextfloat(-5.0e-324) == 0.0 +@test prevfloat(5.0e-324) == 0.0 +@test nextfloat(-1.0) > -1.0 +@test prevfloat(-1.0) < -1.0 +@test nextfloat(nextfloat(0.0),-2) == -5.0e-324 +@test nextfloat(prevfloat(0.0), 2) == 5.0e-324 From a4f9c269873f3f027f4ace92bce99b81a5bf977f Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 4 Dec 2013 15:26:14 -0500 Subject: [PATCH 40/53] fix eps(realmax), add typemin and typemax for BigFloat --- base/float.jl | 22 +++++++++++++++++++++- base/floatfuncs.jl | 20 -------------------- base/mpfr.jl | 5 ++++- test/numbers.jl | 3 +++ 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/base/float.jl b/base/float.jl index 8844acd3e0f61..3881e5692b081 100644 --- a/base/float.jl +++ b/base/float.jl @@ -207,6 +207,21 @@ isless (a::FloatingPoint, b::Integer) = (a Date: Thu, 5 Dec 2013 15:10:11 +0000 Subject: [PATCH 41/53] add realmin realmax for BigFloat --- base/mpfr.jl | 6 +++++- test/mpfr.jl | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/base/mpfr.jl b/base/mpfr.jl index 127d300bf9b26..d7e4c2717a6f5 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -19,7 +19,8 @@ import gamma, lgamma, digamma, erf, erfc, zeta, log1p, airyai, iceil, ifloor, itrunc, eps, signbit, sin, cos, tan, sec, csc, cot, acos, asin, atan, cosh, sinh, tanh, sech, csch, coth, acosh, asinh, atanh, atan2, - serialize, deserialize, inf, nan, hash, cbrt, typemax, typemin + serialize, deserialize, inf, nan, hash, cbrt, typemax, typemin, + realmin, realmax import Base.Math.lgamma_r @@ -687,6 +688,9 @@ end eps(::Type{BigFloat}) = nextfloat(BigFloat(1)) - BigFloat(1) +realmin(::Type{BigFloat}) = nextfloat(zero(BigFloat)) +realmax(::Type{BigFloat}) = prevfloat(inf(BigFloat)) + function with_bigfloat_precision(f::Function, precision::Integer) old_precision = get_bigfloat_precision() set_bigfloat_precision(precision) diff --git a/test/mpfr.jl b/test/mpfr.jl index 18b71cf66df83..83424e0093d42 100644 --- a/test/mpfr.jl +++ b/test/mpfr.jl @@ -341,6 +341,14 @@ end x = eps(BigFloat) @test BigFloat(1) + x == BigFloat(1) + prevfloat(x) +# realmin/realmax +x = realmin(BigFloat) +@test x > 0 +@test prevfloat(x) == 0 +x = realmax(BigFloat) +@test !isinf(x) +@test isinf(nextfloat(x)) + # factorial with_bigfloat_precision(256) do x = BigFloat(42) From 3444911739c6fcde6cc8a63b8f7559276cb3909e Mon Sep 17 00:00:00 2001 From: Simon Kornblith Date: Thu, 5 Dec 2013 12:35:19 -0500 Subject: [PATCH 42/53] More accurate linspace for types with greater precision than Float64 --- base/array.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/base/array.jl b/base/array.jl index 8d4b9117fddad..377c1d0a14214 100644 --- a/base/array.jl +++ b/base/array.jl @@ -234,8 +234,9 @@ function linspace(start::Real, stop::Real, n::Integer) return a end n -= 1 + S = promote_type(T, Float64) for i=0:n - a[i+1] = start*((n-i)/n) + stop*(i/n) + a[i+1] = start*(convert(S, (n-i))/n) + stop*(convert(S, i)/n) end a end From 3038609f38b34fd7bb61f4e591a9d1788ffbbfa4 Mon Sep 17 00:00:00 2001 From: davidssmith Date: Thu, 5 Dec 2013 15:22:40 -0600 Subject: [PATCH 43/53] added negative bitarray rolling --- base/bitarray.jl | 2 ++ test/bitarray.jl | 2 ++ 2 files changed, 4 insertions(+) diff --git a/base/bitarray.jl b/base/bitarray.jl index b5e8486ba4504..2216f95954d27 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1720,6 +1720,7 @@ function rol(B::BitVector, i::Integer) n = length(B) i %= n i == 0 && return copy(B) + i < 0 && return ror(B, -i) A = BitArray(n) copy_chunks(A.chunks, 1, B.chunks, i+1, n-i) copy_chunks(A.chunks, n-i+1, B.chunks, 1, i) @@ -1730,6 +1731,7 @@ function ror(B::BitVector, i::Integer) n = length(B) i %= n i == 0 && return copy(B) + i < 0 && return rol(B, -i) A = BitArray(n) copy_chunks(A.chunks, i+1, B.chunks, 1, n-i) copy_chunks(A.chunks, 1, B.chunks, n-i+1, i) diff --git a/test/bitarray.jl b/test/bitarray.jl index 1fafcf252ccc0..62c4931fbd016 100644 --- a/test/bitarray.jl +++ b/test/bitarray.jl @@ -522,6 +522,8 @@ for m = [rand(1:v1)-1 0 1 63 64 65 191 192 193 v1-1] @test isequal(b1 >>> m, [ falses(m); b1[1:end-m] ]) @test isequal(rol(b1, m), [ b1[m+1:end]; b1[1:m] ]) @test isequal(ror(b1, m), [ b1[end-m+1:end]; b1[1:end-m] ]) + @test isequal(ror(b1, m), rol(b1, -m)) + @test isequal(rol(b1, m), ror(b1, -m)) end timesofar("datamove") From ba7fa14f74ec5d5f3e2420e1b04c6aff93f418af Mon Sep 17 00:00:00 2001 From: tknopp Date: Fri, 6 Dec 2013 04:35:15 +0100 Subject: [PATCH 44/53] Added section about memory management --- doc/manual/embedding.rst | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/doc/manual/embedding.rst b/doc/manual/embedding.rst index 4ec92d7c3f1b3..89aa7f51f2cb1 100644 --- a/doc/manual/embedding.rst +++ b/doc/manual/embedding.rst @@ -70,6 +70,33 @@ In the first step, a handle to the Julia function ``sqrt`` is retrieved by calli Its second argument ``args`` is an array of ``jl_value_t*`` arguments while ``nargs`` is the number of arguments. +Memory Management +======================== + +As we have seen before, most Julia C types are handled as pointers which raises the question: Who is responsible for freeing any memory that functions as for instance ``jl_call`` allocate? + +The fortune answer is: The garbage collector (GC)! The unfortunate issue arising is: The GC cannot know that we are holding a reference to a Julia value from C, which implies that the GC may free the memory, rendering our pointer invalid. We thus have to be careful when using pointers to Julia values. + +The first thing to remember is that the GC is only active within `certain` ``jl_...`` calls. It is therefore safe to use a pointer in-between ``jl_...`` calls. But in order to make sure that values also survive ``jl_...`` calls, we have to tell Julia that we hold a reference to a Julia value. This can be done using the ``JL_GC_PUSH`` macros:: + + jl_value_t* ret = jl_eval_string("sqrt(2.0)"); + JL_GC_PUSH1(&ret); + // Do something with ret + JL_POP(); + +The last call tells Julia that we do not anymore hold a reference to the Julia value and that the GC is now allowed to collect the value behind the ``ret`` pointer. Several Julia values can be pushed at once using the ``JL_GC_PUSH2`` , ``JL_GC_PUSH3`` , and ``JL_GC_PUSH4`` macros. To push an array of Julia values one can use the ``JL_GC_PUSHARGS`` macro, which takes as first argument a C array of ``jl_value_t`` pointers (i.e. ``jl_value_t**``) and as second argument the length of the array. + +Manipulating the Garbage Collector +--------------------------------------------------- + +There are some functions to control the GC. In the normal use case, these should not be necessary to be used. + +========================= ============================================================================== +``void jl_gc_collect()`` Force a GC run +``void jl_gc_disable()`` Disable the GC +``void jl_gc_enable()`` Enable the GC +========================= ============================================================================== + Working with Arrays ======================== @@ -263,4 +290,3 @@ While ``jl_error`` takes a simple C string, ``jl_errorf`` can be used like a ``p jl_errorf("An error occurred as x = %d is to large", x); where in this example ``x`` is assumed to be an integer. - From 016467bd4a4cf240f3a146187818d0a06e515752 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 5 Dec 2013 22:36:29 -0500 Subject: [PATCH 45/53] allow scale(b,A) or scale(A,b) when b is a scalar as well as a vector, don't restrict scale unnecessarily to arrays of numbers (e.g. scaling arrays of arrays should work), and improve documentation for scale\! --- base/linalg/generic.jl | 8 +++++--- doc/stdlib/linalg.rst | 29 +++++++++++++++++------------ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/base/linalg/generic.jl b/base/linalg/generic.jl index 1aaabdfb70dde..0d47dd708cd48 100644 --- a/base/linalg/generic.jl +++ b/base/linalg/generic.jl @@ -1,13 +1,15 @@ ## linalg.jl: Some generic Linear Algebra definitions -scale{T<:Number}(X::AbstractArray{T}, s::Number) = scale!(copy(X), s) +scale(X::AbstractArray, s::Number) = scale!(copy(X), s) +scale(s::Number, X::AbstractArray) = scale!(copy(X), s) -function scale!{T<:Number}(X::AbstractArray{T}, s::Number) +function scale!(X::AbstractArray, s::Number) for i in 1:length(X) - X[i] *= s + @inbounds X[i] *= s end X end +scale!(s::Number, X::AbstractArray) = scale!(X, s) cross(a::AbstractVector, b::AbstractVector) = [a[2]*b[3]-a[3]*b[2], a[3]*b[1]-a[1]*b[3], a[1]*b[2]-a[2]*b[1]] diff --git a/doc/stdlib/linalg.rst b/doc/stdlib/linalg.rst index 6a884a6c4e6f6..c49abcb5d1a76 100644 --- a/doc/stdlib/linalg.rst +++ b/doc/stdlib/linalg.rst @@ -247,23 +247,28 @@ Linear algebra functions in Julia are largely implemented by calling functions f Construct a diagonal matrix and place ``v`` on the ``k``-th diagonal. -.. function:: scale(A, B) +.. function:: scale(A, b), scale(b, A) - ``scale(A::Array, B::Number)`` scales all values in ``A`` with ``B``. - Note: In cases where the array is big enough, ``scale`` can be much - faster than ``A .* B``, due to the use of BLAS. + Scale an array ``A`` by a scalar ``b``, returning a new array. - ``scale(A::Matrix, B::Vector)`` is the same as multiplying with a - diagonal matrix on the right, and scales the columns of ``A`` with - the values in ``B``. + If ``A`` is a matrix and ``b`` is a vector, then ``scale!(A,b)`` + scales each column ``i`` of ``A`` by ``b[i]`` (similar to + ``A*diagm(b)``), while ``scale!(b,A)`` scales each row ``i`` of + ``A`` by ``b[i]`` (similar to ``diagm(b)*A``), returning a new array. - ``scale(A::Vector, B::Matrix)`` is the same as multiplying with a - diagonal matrix on the left, and scales the rows of ``B`` with the - values in ``A``. + Note: for large ``A``, ``scale`` can be much faster than ``A .* b`` or + ``b .* A``, due to the use of BLAS. -.. function:: scale!(A, B) +.. function:: scale!(A, b), scale!(b, A) - ``scale!(A,B)`` overwrites the input array with the scaled result. + Scale an array ``A`` by a scalar ``b``, similar to ``scale`` but + overwriting ``A`` in-place. + + If ``A`` is a matrix and ``b`` is a vector, then ``scale!(A,b)`` + scales each column ``i`` of ``A`` by ``b[i]`` (similar to + ``A*diagm(b)``), while ``scale!(b,A)`` scales each row ``i`` of + ``A`` by ``b[i]`` (similar to ``diagm(b)*A``), again operating in-place + on ``A``. .. function:: symmetrize!(A[, UL::Char]) From 04f5c341e017ee84c5b6e5cfc646d6980588583f Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Thu, 5 Dec 2013 20:06:53 -0800 Subject: [PATCH 46/53] Use warn() instead of println in base/sprase/sparsematrix.jl Closes #5038 --- base/sparse/sparsematrix.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index cb69e77105e3f..b86ae8a81352d 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -287,7 +287,7 @@ function findn{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) J[count] = col count += 1 else - println("warning: sparse matrix contains explicit stored zeros") + warn("sparse matrix contains explicit stored zeros") end end @@ -313,7 +313,7 @@ function findnz{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) V[count] = S.nzval[k] count += 1 else - println("warning: sparse matrix contains explicit stored zeros") + warn("sparse matrix contains explicit stored zeros") end end From 22bcba382568cc6dbdc3924dfb27750080884a30 Mon Sep 17 00:00:00 2001 From: "Viral B. Shah" Date: Fri, 6 Dec 2013 10:09:23 +0530 Subject: [PATCH 47/53] Use warn_once instead of warn (#5038) --- base/sparse/sparsematrix.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index b86ae8a81352d..fad0c6b4932db 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -287,7 +287,7 @@ function findn{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) J[count] = col count += 1 else - warn("sparse matrix contains explicit stored zeros") + warn_once("sparse matrix contains explicit stored zeros") end end @@ -313,7 +313,7 @@ function findnz{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}) V[count] = S.nzval[k] count += 1 else - warn("sparse matrix contains explicit stored zeros") + warn_once("sparse matrix contains explicit stored zeros") end end From 8ce7dfb84e6b4ac02eb7f1c2e73a31f6c98ab4c7 Mon Sep 17 00:00:00 2001 From: "Viral B. Shah" Date: Sat, 7 Dec 2013 12:57:08 +0530 Subject: [PATCH 48/53] Add sparse matvec to perf benchmark (#4707) --- test/perf/kernel/getdivgrad.jl | 46 ++++++++++++++++++++++++++++++++++ test/perf/kernel/perf.jl | 16 ++++++++---- 2 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 test/perf/kernel/getdivgrad.jl diff --git a/test/perf/kernel/getdivgrad.jl b/test/perf/kernel/getdivgrad.jl new file mode 100644 index 0000000000000..953042ff96106 --- /dev/null +++ b/test/perf/kernel/getdivgrad.jl @@ -0,0 +1,46 @@ +# https://github.com/JuliaLang/julia/issues/4707 + +#----------------- Get the A matrix +function getDivGrad(n1,n2,n3) + + # the Divergence + D1 = kron(speye(n3),kron(speye(n2),ddx(n1))) + D2 = kron(speye(n3),kron(ddx(n2),speye(n1))) + D3 = kron(ddx(n3),kron(speye(n2),speye(n1))) + # DIV from faces to cell-centers + Div = [D1 D2 D3] + + return Div*Div'; +end + +#----------------- 1D finite difference on staggered grid +function ddx(n) +# generate 1D derivatives + return d = spdiags(ones(n)*[-1 1],[0,1],n,n+1) +end + +#------------- Build a diagonal matrix +function spdiags(B,d,m,n) +# spdiags(B,d,m,n) +# creates a sparse matrix from its diagonals + + d = d[:] + p = length(d) + + len = zeros(p+1,1) + for k = 1:p + len[k+1] = int(len[k]+length(max(1,1-d[k]):min(m,n-d[k]))) + end + a = zeros(int(len[p+1]),3) + for k = 1:p + # Append new d[k]-th diagonal to compact form + i = max(1,1-d[k]):min(m,n-d[k]) + a[(int(len[k])+1):int(len[k+1]),:] = [i i+d[k] B[i+(m>=n)*d[k],k]] + end + + A = sparse(int(a[:,1]),int(a[:,2]),a[:,3],m,n); + + return A + +end + diff --git a/test/perf/kernel/perf.jl b/test/perf/kernel/perf.jl index 40a1b4c76b107..835915775757a 100644 --- a/test/perf/kernel/perf.jl +++ b/test/perf/kernel/perf.jl @@ -24,16 +24,22 @@ include("gk.jl") # issue #942 s = sparse(ones(280,280)); -@timeit s*s "sparsemul" "Sparse matrix multiplication" - -# issue #939 -y = [500000:-1:1]; -@timeit sortperm(y) "sortperm" "Sorting of a worst-case vector" +@timeit s*s "sparsemul" "Sparse matrix - sparse matrix multiplication" # issue #938 x = 1:600000; @timeit sparse(x,x,x) "sparserange" "Construction of a sparse array from ranges" +# issue 4707 +include("getdivgrad.jl") +A = getDivGrad(64,64,64) +v = rand(64^3) +@timeit A*v "matvec" "Sparse matrix - dense vector multiplication" + +# issue #939 +y = [500000:-1:1]; +@timeit sortperm(y) "sortperm" "Sorting of a worst-case vector" + # issue #445 include("stockcorr.jl") @timeit stockcorr() "stockcorr" "Correlation analysis of random matrices" From c79569015e7d329cace74984db00c23eda4df2ab Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Sat, 7 Dec 2013 07:58:07 -0500 Subject: [PATCH 49/53] NEWS for #4042 --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 8d8cfb24074bc..28c6541249148 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,8 @@ Julia v0.3.0 Release Notes New language features --------------------- + * Greatly enhanced performance for passing and returning tuples ([#4042]). + New library functions --------------------- From 0cd88f56593b2f1c3e4f48ce583de59a69f9db52 Mon Sep 17 00:00:00 2001 From: Galen O'Neil Date: Sat, 7 Dec 2013 10:47:16 -0700 Subject: [PATCH 50/53] more consitent/useful description of predicate in ie all() --- doc/stdlib/base.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index fbea66738502b..8ccde61aab6e0 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -556,15 +556,17 @@ Iterable Collections .. function:: count(p, itr) -> Integer - Count the number of elements in ``itr`` for which predicate ``p`` is true. + Count the number of elements in ``itr`` for which predicate ``p`` returns true. .. function:: any(p, itr) -> Bool - Determine whether any element of ``itr`` satisfies the given predicate. + Determine whether predicate ``p`` returns true for any elements of ``itr``. .. function:: all(p, itr) -> Bool - Determine whether all elements of ``itr`` satisfy the given predicate. + Determine whether predicate ``p`` returns true for all elements of ``itr``. + + **Example**: ``all((i) -> i>i, [4,5,6]) = true`` .. function:: map(f, c) -> collection @@ -3538,7 +3540,7 @@ Indexing, Assignment, and Concatenation .. function:: findfirst(predicate, A) - Return the index of the first element that satisfies the given predicate in ``A``. + Return the index of the first element of ``A`` for which ``predicate`` returns true. .. function:: findnext(A, i) @@ -3546,8 +3548,7 @@ Indexing, Assignment, and Concatenation .. function:: findnext(predicate, A, i) - Find the next index >= ``i`` of an element of ``A`` satisfying the given predicate, - or ``0`` if not found. + Find the next index >= ``i`` of an element of ``A`` for which ``predicate`` returns true, or ``0`` if not found. .. function:: findnext(A, v, i) From 3d276788be73c54f170d6063280e795d2de3079e Mon Sep 17 00:00:00 2001 From: timholy Date: Sat, 7 Dec 2013 16:11:06 -0600 Subject: [PATCH 51/53] Fix #5056 --- base/io.jl | 11 +++++------ src/julia.expmap | 3 ++- src/support/ios.c | 22 +++++++++++++++------- src/support/ios.h | 6 ++++-- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/base/io.jl b/base/io.jl index 0813c34537945..422426f4c6dcf 100644 --- a/base/io.jl +++ b/base/io.jl @@ -267,9 +267,8 @@ fd(s::IOStream) = int(ccall(:jl_ios_fd, Clong, (Ptr{Void},), s.ios)) close(s::IOStream) = ccall(:ios_close, Void, (Ptr{Void},), s.ios) isopen(s::IOStream) = bool(ccall(:ios_isopen, Cint, (Ptr{Void},), s.ios)) flush(s::IOStream) = ccall(:ios_flush, Void, (Ptr{Void},), s.ios) -isreadonly(s::IOStream) = bool(ccall(:ios_get_readonly, Cint, (Ptr{Void},), s.ios)) -iswritable(s::IOStream) = !isreadonly(s) -isreadable(s::IOStream) = true +iswritable(s::IOStream) = bool(ccall(:ios_get_writable, Cint, (Ptr{Void},), s.ios)) +isreadable(s::IOStream) = bool(ccall(:ios_get_readable, Cint, (Ptr{Void},), s.ios)) function truncate(s::IOStream, n::Integer) ccall(:ios_trunc, Int32, (Ptr{Void}, Uint), s.ios, n) == 0 || @@ -351,7 +350,7 @@ write(s::IOStream, b::Uint8) = int(ccall(:jl_putc, Int32, (Uint8, Ptr{Void}), b, function write{T}(s::IOStream, a::Array{T}) if isbits(T) - if isreadonly(s) + if !iswritable(s) error("attempt to write to a read-only IOStream") end int(ccall(:ios_write, Uint, (Ptr{Void}, Ptr{Void}, Uint), @@ -362,7 +361,7 @@ function write{T}(s::IOStream, a::Array{T}) end function write(s::IOStream, p::Ptr, nb::Integer) - if isreadonly(s) + if !iswritable(s) error("attempt to write to a read-only IOStream") end int(ccall(:ios_write, Uint, (Ptr{Void}, Ptr{Void}, Uint), s.ios, p, nb)) @@ -409,7 +408,7 @@ end ## text I/O ## function write(s::IOStream, c::Char) - if isreadonly(s) + if !iswritable(s) error("attempt to write to a read-only IOStream") end int(ccall(:ios_pututf8, Int32, (Ptr{Void}, Char), s.ios, c)) diff --git a/src/julia.expmap b/src/julia.expmap index 56648bcc2f26a..208f821899e8e 100644 --- a/src/julia.expmap +++ b/src/julia.expmap @@ -19,7 +19,8 @@ ios_fd; ios_file; ios_flush; - ios_get_readonly; + ios_get_readable; + ios_get_writable; ios_getc; ios_getutf8; ios_mem; diff --git a/src/support/ios.c b/src/support/ios.c index 5f01e7dac1497..1321c5ec67a63 100644 --- a/src/support/ios.c +++ b/src/support/ios.c @@ -352,7 +352,7 @@ DLLEXPORT size_t ios_write_direct(ios_t *dest, ios_t *src) size_t ios_write(ios_t *s, const char *data, size_t n) { - if (s->readonly) return 0; + if (!s->writable) return 0; if (n == 0) return 0; size_t space; size_t wrote = 0; @@ -687,17 +687,22 @@ int ios_bufmode(ios_t *s, bufmode_t mode) return 0; } -int ios_get_readonly(ios_t *s) +int ios_get_readable(ios_t *s) { - return s->readonly; + return s->readable; +} + +int ios_get_writable(ios_t *s) +{ + return s->writable; } void ios_set_readonly(ios_t *s) { - if (s->readonly) return; + if (!s->writable) return; ios_flush(s); s->state = bst_none; - s->readonly = 1; + s->writable = 0; } static size_t ios_copy_(ios_t *to, ios_t *from, size_t nbytes, bool_t all) @@ -786,8 +791,9 @@ static void _ios_init(ios_t *s) s->ownbuf = 1; s->ownfd = 0; s->_eof = 0; + s->readable = 1; + s->writable = 1; s->rereadable = 0; - s->readonly = 0; } /* stream object initializers. we do no allocation. */ @@ -809,8 +815,10 @@ ios_t *ios_file(ios_t *s, char *fname, int rd, int wr, int create, int trunc) if (fd == -1) goto open_file_err; s = ios_fd(s, fd, 1, 1); + if (!rd) + s->readable = 0; if (!wr) - s->readonly = 1; + s->writable = 0; return s; open_file_err: s->fd = -1; diff --git a/src/support/ios.h b/src/support/ios.h index b08784a623f08..8c6cfb0fcae93 100644 --- a/src/support/ios.h +++ b/src/support/ios.h @@ -38,7 +38,8 @@ typedef struct { // to be a pointer long fd; - unsigned char readonly:1; + unsigned char readable:1; + unsigned char writable:1; unsigned char ownbuf:1; unsigned char ownfd:1; unsigned char _eof:1; @@ -77,7 +78,8 @@ DLLEXPORT char *ios_takebuf(ios_t *s, size_t *psize); // release buffer to call // set buffer space to use DLLEXPORT int ios_setbuf(ios_t *s, char *buf, size_t size, int own); DLLEXPORT int ios_bufmode(ios_t *s, bufmode_t mode); -DLLEXPORT int ios_get_readonly(ios_t *s); +DLLEXPORT int ios_get_readable(ios_t *s); +DLLEXPORT int ios_get_writable(ios_t *s); DLLEXPORT void ios_set_readonly(ios_t *s); DLLEXPORT size_t ios_copy(ios_t *to, ios_t *from, size_t nbytes); DLLEXPORT size_t ios_copyall(ios_t *to, ios_t *from); From 161c29394bca004d6191686da5d995ead0cc0686 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 7 Dec 2013 20:41:46 -0500 Subject: [PATCH 52/53] formatting fixes --- src/ccall.cpp | 5 +++-- src/cgutils.cpp | 26 +++++++++++++------------- src/codegen.cpp | 34 ++++++++++++++++++---------------- src/intrinsics.cpp | 14 ++++++-------- 4 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 8ac34fc19ef2f..154bc21bd3599 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -317,7 +317,8 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv, // //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); - } else if (jl_is_tuple(jt)) { + } + else if (jl_is_tuple(jt)) { return emit_unbox(ty,jv,jt); } // TODO: error for & with non-pointer argument type @@ -798,7 +799,7 @@ static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) arg = boxed(arg,ctx); needroot = true; } - } + } else { arg = emit_unboxed(argi, ctx); if (jl_is_bitstype(expr_type(argi, ctx))) { diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 358b746ce0f43..bfcd14c225160 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -89,7 +89,7 @@ static Type *julia_type_to_llvm(jl_value_t *jt) // http://llvm.org/bugs/show_bug.cgi?id=12618 if (isvector && type != T_int1) { Type *ret = NULL; - if(type == T_void) + if (type == T_void) return T_void; if (type->isSingleValueType()) ret = VectorType::get(type,ntypes); @@ -614,7 +614,7 @@ static Value *emit_tuplelen(Value *t,jl_value_t *jt) Value *lenbits = emit_nthptr(t, 1); return builder.CreatePtrToInt(lenbits, T_size); #endif - } + } else { //unboxed return ConstantInt::get(T_size,jl_tuple_len(jt)); } @@ -648,9 +648,9 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl assert(ity->isIntegerTy()); IntegerType *iity = dyn_cast(ity); // ExtractElement needs i32 *sigh* - if(iity->getBitWidth() > 32) + if (iity->getBitWidth() > 32) i = builder.CreateTrunc(i,T_int32); - else if(iity->getBitWidth() < 32) + else if (iity->getBitWidth() < 32) i = builder.CreateZExt(i,T_int32); ret = builder.CreateInsertElement(tuple,x,builder.CreateSub(i,ConstantInt::get(T_int32,1))); } @@ -665,7 +665,7 @@ static Value *emit_tupleset(Value *tuple, Value *i, Value *x, jl_value_t *jt, jl else ret = builder.CreateInsertValue(tuple,x,ArrayRef(j)); } - if(ty != T_void) + if (ty != T_void) ++j; } } @@ -697,9 +697,9 @@ static Value *emit_tupleref(Value *tuple, Value *ival, jl_value_t *jt, jl_codect assert(ity->isIntegerTy()); IntegerType *iity = dyn_cast(ity); // ExtractElement needs i32 *sigh* - if(iity->getBitWidth() > 32) + if (iity->getBitWidth() > 32) ival = builder.CreateTrunc(ival,T_int32); - else if(iity->getBitWidth() < 32) + else if (iity->getBitWidth() < 32) ival = builder.CreateZExt(ival,T_int32); return builder.CreateExtractElement(tuple,builder.CreateSub(ival,ConstantInt::get(T_int32,1))); } @@ -715,7 +715,7 @@ static Value *emit_tupleref(Value *tuple, Value *ival, jl_value_t *jt, jl_codect else return mark_julia_type(builder.CreateExtractValue(tuple,ArrayRef(j)),jl_tupleref(jt,i)); } - if(ty != T_void) + if (ty != T_void) ++j; } assert("Out of bounds!"); @@ -1036,9 +1036,9 @@ static jl_value_t *static_constant_instance(Constant *constant, jl_value_t *jt) ConstantVector *cvec = NULL; if ((carr = dyn_cast(constant)) != NULL) nargs = carr->getType()->getNumElements(); - else if((cst = dyn_cast(constant)) != NULL) + else if ((cst = dyn_cast(constant)) != NULL) nargs = cst->getType()->getNumElements(); - else if((cvec = dyn_cast(constant)) != NULL) + else if ((cvec = dyn_cast(constant)) != NULL) nargs = cvec->getType()->getNumElements(); else assert(false && "Cannot process this type of constant"); @@ -1066,7 +1066,7 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) if (jt == NULL || jl_is_uniontype(jt) || jl_is_abstracttype(jt)) jt = julia_type_of(v); jl_value_t *s = static_void_instance(jt); - if(jl_is_tuple(jt) && jl_tuple_len(jt) > 0) + if (jl_is_tuple(jt) && jl_tuple_len(jt) > 0) jl_add_linfo_root(ctx->linfo, s); return literal_pointer_val(s); } @@ -1077,12 +1077,12 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt) jt = julia_type_of(v); if (t == T_void) { jl_value_t *s = static_void_instance(jt); - if(jl_is_tuple(jt) && jl_tuple_len(jt) > 0) + if (jl_is_tuple(jt) && jl_tuple_len(jt) > 0) jl_add_linfo_root(ctx->linfo, s); return literal_pointer_val(s); } Constant *c = NULL; - if((c = dyn_cast(v)) != NULL) { + if ((c = dyn_cast(v)) != NULL) { jl_value_t *s = static_constant_instance(c,jt); jl_add_linfo_root(ctx->linfo, s); return literal_pointer_val(s); diff --git a/src/codegen.cpp b/src/codegen.cpp index 8f08e6dcece8b..e14d7e5051168 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1419,8 +1419,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, Type *ety = NULL; if (tpl != NULL) ety = jl_llvmtuple_eltype(tpl->getType(),tt,i); - if(tpl == NULL || ety == T_void) - { + if (tpl == NULL || ety == T_void) { emit_expr(args[i+1],ctx); //for side effects (if any) continue; } @@ -1766,7 +1765,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, for(size_t i=0; i < nargs; i++) { Type *at = cft->getParamType(idx); Type *et = julia_type_to_llvm(jl_tupleref(f->linfo->specTypes,i)); - if(et == T_void) { + if (et == T_void) { // Still emit the expression in case it has side effects emit_expr(args[i+1], ctx); continue; @@ -1921,7 +1920,7 @@ static Value *emit_var(jl_sym_t *sym, jl_value_t *ty, jl_codectx_t *ctx, bool is } jl_binding_t *jbp=NULL; Value *bp = var_binding_pointer(sym, &jbp, false, ctx); - if(bp == NULL) + if (bp == NULL) return NULL; assert(jbp != NULL); if (jbp->value != NULL) { @@ -2277,7 +2276,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, for(size_t i=0; i < na; i++) { jl_value_t *jtype = jl_tupleref(sty->types,i); Type *fty = julia_type_to_llvm(jtype); - if(fty == T_void) + if (fty == T_void) continue; Value *fval = emit_unbox(fty, emit_unboxed(args[i+1],ctx), jtype); if (fty == T_int1) @@ -2656,7 +2655,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct continue; theNewArg = emit_unbox(lty, theArg, ty); } - else if(jl_is_tuple(ty)) { + else if (jl_is_tuple(ty)) { Type *lty = julia_struct_to_llvm(ty); if (lty != jl_pvalue_llvmt) { if (lty == T_void) @@ -3072,7 +3071,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) // step 11. check arg count if (ctx.linfo->specTypes == NULL) { - if (va) { + if (va) { Value *enough = builder.CreateICmpUGE(argCount, ConstantInt::get(T_int32, nreq)); @@ -3122,8 +3121,9 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) } Value *theArg = NULL; - if (specsig) + if (specsig) { theArg = argPtr; + } else { assert(argPtr != NULL); theArg = builder.CreateLoad(argPtr, false); @@ -3133,7 +3133,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) if (lv == NULL) { if (ctx.vars[s].isGhost) { ctx.vars[s].passedAs = NULL; - } + } else { // if this argument hasn't been given space yet, we've decided // to leave it in the input argument array. @@ -3150,16 +3150,19 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) } builder.CreateStore(builder.CreateCall(jlbox_func, theArg), lv); } - else if (dyn_cast(lv) != NULL) + else if (dyn_cast(lv) != NULL) { builder.CreateStore(boxed(theArg,&ctx), lv); - else if (dyn_cast(lv)->getAllocatedType() == jl_pvalue_llvmt) + } + else if (dyn_cast(lv)->getAllocatedType() == jl_pvalue_llvmt) { builder.CreateStore(theArg,lv); - else + } + else { builder.CreateStore(emit_unbox(dyn_cast(lv)->getAllocatedType(), theArg, lam->specTypes == NULL ? NULL : jl_tupleref(lam->specTypes,i)), lv); + } } // get arrayvar data if applicable if (arrayvars.find(s) != arrayvars.end()) { @@ -3175,11 +3178,10 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) if (!vi.escapes && !vi.isAssigned) { ctx.vaStack = true; } - else if(!vi.isGhost) { + else if (!vi.isGhost) { // restarg = jl_f_tuple(NULL, &args[nreq], nargs-nreq) Value *lv = vi.memvalue; - if (dyn_cast(lv) != NULL || dyn_cast(lv)->getAllocatedType() == jl_pvalue_llvmt) - { + if (dyn_cast(lv) != NULL || dyn_cast(lv)->getAllocatedType() == jl_pvalue_llvmt) { Value *restTuple = builder.CreateCall3(jltuple_func, V_null, builder.CreateGEP(argArray, @@ -3190,7 +3192,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) builder.CreateStore(builder.CreateCall(jlbox_func, restTuple), lv); else builder.CreateStore(restTuple, lv); - } + } else { // TODO: Perhaps allow this in the future, but for now sice varargs are always unspecialized // we don't diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 17d1de861a406..cce68a80735c1 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -165,15 +165,14 @@ static Value *emit_unboxed(jl_value_t *e, jl_codectx_t *ctx) static Type *jl_llvmtuple_eltype(Type *tuple, jl_value_t *jt, size_t i) { Type *ety = NULL; - if(tuple->isArrayTy()) + if (tuple->isArrayTy()) ety = dyn_cast(tuple)->getElementType(); - else if(tuple->isVectorTy()) + else if (tuple->isVectorTy()) ety = dyn_cast(tuple)->getElementType(); - else if(tuple == T_void) + else if (tuple == T_void) ety = T_void; - else if (tuple->isStructTy()) { + else if (tuple->isStructTy()) ety = julia_type_to_llvm(jl_tupleref((jl_tuple_t*)jt,i)); - } else assert(false); return ety; @@ -213,15 +212,14 @@ static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt) return x; } if ( (jt != NULL && jl_is_tuple(jt)) || to->isVectorTy() || to->isArrayTy() || - (to->isStructTy() && dyn_cast(to)->isLiteral()) ) - { + (to->isStructTy() && dyn_cast(to)->isLiteral()) ) { assert(jt != 0); assert(jl_is_tuple(jt)); assert(to != T_void); Value *tpl = UndefValue::get(to); for (size_t i = 0; i < jl_tuple_len(jt); ++i) { Type *ety = jl_llvmtuple_eltype(to,jt,i); - if(ety == T_void) + if (ety == T_void) continue; Value *ref = emit_tupleref(x,ConstantInt::get(T_size,i+1),jt,NULL); Value *elt = emit_unbox(ety,ref,julia_type_of(ref)); From 60907ae47a12bf0f05b9da010642f6a5e09d1703 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 7 Dec 2013 20:46:15 -0500 Subject: [PATCH 53/53] edit embedding chapter also remove several uses of "very". --- doc/manual/embedding.rst | 230 ++++++++----------------- doc/manual/mathematical-operations.rst | 2 +- doc/manual/methods.rst | 4 +- doc/manual/noteworthy-differences.rst | 2 +- doc/manual/parallel-computing.rst | 4 +- 5 files changed, 79 insertions(+), 163 deletions(-) diff --git a/doc/manual/embedding.rst b/doc/manual/embedding.rst index 89aa7f51f2cb1..922db4a702d7d 100644 --- a/doc/manual/embedding.rst +++ b/doc/manual/embedding.rst @@ -6,90 +6,91 @@ Embedding Julia ************************** -As we have seen (:ref:`man-calling-c-and-fortran-code`) Julia has a very simple and efficient way to call functions that are written in the C programming language. But there are various situations where actually the opposite is needed: calling Julia function from C code. This can for instance be used to integrate code that has been prototyped in Julia into a larger C/C++ project, without the need to rewrite everything in C/C++. To make this possible Julia features a C API that can be used to embed Julia into a C/C++ program. As almost all programming languages have some way to call C functions, the Julia C-API can also be used to build further language bridges (E.g. calling Julia from Python or C#). +As we have seen (:ref:`man-calling-c-and-fortran-code`) Julia has a simple and efficient way to call functions written in C. But there are situations where the opposite is needed: calling Julia function from C code. This can be used to integrate Julia code into a larger C/C++ project, without the need to rewrite everything in C/C++. Julia has a C API to make this possible. As almost all programming languages have some way to call C functions, the Julia C API can also be used to build further language bridges (e.g. calling Julia from Python or C#). High-Level Embedding ===================== -We start with a very simple C program that initializes Julia and calls some Julia code without the need to share data between Julia and C:: +We start with a simple C program that initializes Julia and calls some Julia code:: #include int main(int argc, char *argv[]) { - jl_init(NULL); - jl_eval_string("print(sqrt(2.0))"); + jl_init(NULL); + jl_eval_string("print(sqrt(2.0))"); - return 0; + return 0; } -In order to build this program you have to put the path to the Julia header into the include path and link against libjulia. For instance, when Julia is installed to $JULIA_DIR, one can compile the above test program test.c with gcc using:: +In order to build this program you have to put the path to the Julia header into the include path and link against ``libjulia``. For instance, when Julia is installed to ``$JULIA_DIR``, one can compile the above test program ``test.c`` with gcc using:: gcc -o test -I$JULIA_DIR/include/julia -L$JULIA_DIR/usr/lib -ljulia test.c -Alternatively, please have a look at the ``embedding.c`` program that can be found in the julia source tree in the ``examples/`` folder. +Alternatively, look at the ``embedding.c`` program in the julia source tree in the ``examples/`` folder. -The first thing that has do be done before calling any other Julia C function is to initialize Julia. This is done by calling ``jl_init``, which takes as argument a C string (``const char*``) to the location where Julia is installed. When the argument is NULL, a standard Julia location is assumed. The second statement in the test program evaluates a Julia statement using a call to ``jl_eval_string``. +The first thing that has do be done before calling any other Julia C function is to initialize Julia. This is done by calling ``jl_init``, which takes as argument a C string (``const char*``) to the location where Julia is installed. When the argument is ``NULL``, a standard Julia location is assumed. The second statement in the test program evaluates a Julia statement using a call to ``jl_eval_string``. Converting Types ======================== -While it is very nice to be able to execute a command in the Julia interpreter, it would be even more interesting to return the value of the expression to the host program. As Julia is a dynamically typed language and C is a statically typed language, we have to convert data between the type systems. Converting C values into Julia values is called `boxing`, while converting the other way around is called `unboxing`. Our improved sample program that calculates the square root of 2 in Julia and reads back the result in C looks as follows:: +Real applications will not just need to execute expressions, but also return their values to the host program. ``jl_eval_string`` returns a ``jl_value_t*``, which is a pointer to a heap-allocated Julia object. Storing simple data types like ``Float64`` in this way is called ``boxing``, and extracting the stored primitive data is called ``unboxing``. Our improved sample program that calculates the square root of 2 in Julia and reads back the result in C looks as follows:: - jl_value_t* ret = jl_eval_string("sqrt(2.0)"); + jl_value_t *ret = jl_eval_string("sqrt(2.0)"); - if(jl_is_float64(ret)) - { + if (jl_is_float64(ret)) { double ret_unboxed = jl_unbox_float64(ret); printf("sqrt(2.0) in C: %e \n", ret_unboxed); } -The return value of ``jl_eval_string`` is a pointer of type ``jl_value_t*``. This is the C type that holds Julia values of any type. In order to check whether ``ret`` is of a specific C type, we can use the ``jl_is_...`` functions. By typing ``typeof(sqrt(2.0))`` into the Julia shell we can see that the return type is float64 (i.e. double). To convert the boxed Julia value into a C double the ``jl_unbox_float64`` function is used in the above code snippet. +In order to check whether ``ret`` is of a specific Julia type, we can use the ``jl_is_...`` functions. By typing ``typeof(sqrt(2.0))`` into the Julia shell we can see that the return type is ``Float64`` (``double`` in C). To convert the boxed Julia value into a C double the ``jl_unbox_float64`` function is used in the above code snippet. -Converting C values into Julia values is as simple as the other way around. One can just use the ``jl_box_...`` functions:: +Corresponding ``jl_box_...`` functions are used to convert the other way:: - jl_value_t* a = jl_box_float64(3.0); - jl_value_t* b = jl_box_float32(3.0f); - jl_value_t* c = jl_box_int32(3); + jl_value_t *a = jl_box_float64(3.0); + jl_value_t *b = jl_box_float32(3.0f); + jl_value_t *c = jl_box_int32(3); As we will see next, boxing is required to call Julia functions with specific arguments. Calling Julia Functions ======================== -Calling Julia function can be done with the ``jl_eval_string`` function has has been described before. While ``jl_eval_string`` can call Julia functions and access the return value, there is a more flexible way for this, which allows to easily pass arguments to the Julia function. The following code does the same as ``jl_value_t* ret = jl_eval_string("sqrt(2.0)")``:: +While ``jl_eval_string`` allows C to obtain the result of a Julia expression, it does not allow passing arguments computed in C to Julia. For this you will need to invoke Julia functions directly, using ``jl_call``:: jl_function_t *func = jl_get_function(jl_base_module, "sqrt"); - jl_value_t* argument = jl_box_float64(2.0); - jl_value_t* ret = jl_call1(func, argument); + jl_value_t *argument = jl_box_float64(2.0); + jl_value_t *ret = jl_call1(func, argument); -In the first step, a handle to the Julia function ``sqrt`` is retrieved by calling ``jl_get_function``. The first argument passed to ``jl_get_function`` is a global pointer to the Base module in which ``sqrt`` is defined. Then, the double value is boxed using the ``jl_box_float64`` function. Finally, in the last step, the function is called by using the ``jl_call1`` function. The first argument of ``jl_call1`` is the Julia function handle while the second argument is the actual argument for the Julia function. Note, that there are also, ``jl_call0``, ``jl_call2``, and ``jl_call3`` functions for calling Julia functions without, with 2 or with 3 arguments. The general ``jl_call`` function has the signature:: +In the first step, a handle to the Julia function ``sqrt`` is retrieved by calling ``jl_get_function``. The first argument passed to ``jl_get_function`` is a pointer to the ``Base`` module in which ``sqrt`` is defined. Then, the double value is boxed using ``jl_box_float64``. Finally, in the last step, the function is called using ``jl_call1``. ``jl_call0``, ``jl_call2``, and ``jl_call3`` functions also exist, to conveniently handle different numbers of arguments. To pass more arguments, use ``jl_call``:: jl_value_t *jl_call(jl_function_t *f, jl_value_t **args, int32_t nargs) -Its second argument ``args`` is an array of ``jl_value_t*`` arguments while ``nargs`` is the number of arguments. +Its second argument ``args`` is an array of ``jl_value_t*`` arguments and ``nargs`` is the number of arguments. Memory Management ======================== -As we have seen before, most Julia C types are handled as pointers which raises the question: Who is responsible for freeing any memory that functions as for instance ``jl_call`` allocate? +As we have seen, Julia objects are represented in C as pointers. This raises the question of who is responsible for freeing these objects. -The fortune answer is: The garbage collector (GC)! The unfortunate issue arising is: The GC cannot know that we are holding a reference to a Julia value from C, which implies that the GC may free the memory, rendering our pointer invalid. We thus have to be careful when using pointers to Julia values. +Typically, Julia objects are freed by a garbage collector (GC), but the GC does not automatically know that we are holding a reference to a Julia value from C. This means the GC can free objects out from under you, rendering pointers invalid. -The first thing to remember is that the GC is only active within `certain` ``jl_...`` calls. It is therefore safe to use a pointer in-between ``jl_...`` calls. But in order to make sure that values also survive ``jl_...`` calls, we have to tell Julia that we hold a reference to a Julia value. This can be done using the ``JL_GC_PUSH`` macros:: +The GC can only run when Julia objects are allocated. Calls like ``jl_box_float64`` perform allocation, and allocation might also happen at any point in running Julia code. However, it is generally safe to use pointers in between ``jl_...`` calls. But in order to make sure that values can survive ``jl_...`` calls, we have to tell Julia that we hold a reference to a Julia value. This can be done using the ``JL_GC_PUSH`` macros:: - jl_value_t* ret = jl_eval_string("sqrt(2.0)"); + jl_value_t *ret = jl_eval_string("sqrt(2.0)"); JL_GC_PUSH1(&ret); // Do something with ret JL_POP(); -The last call tells Julia that we do not anymore hold a reference to the Julia value and that the GC is now allowed to collect the value behind the ``ret`` pointer. Several Julia values can be pushed at once using the ``JL_GC_PUSH2`` , ``JL_GC_PUSH3`` , and ``JL_GC_PUSH4`` macros. To push an array of Julia values one can use the ``JL_GC_PUSHARGS`` macro, which takes as first argument a C array of ``jl_value_t`` pointers (i.e. ``jl_value_t**``) and as second argument the length of the array. +The ``JL_POP`` call releases the references established by the previous ``JL_PUSH``. + +Several Julia values can be pushed at once using the ``JL_GC_PUSH2`` , ``JL_GC_PUSH3`` , and ``JL_GC_PUSH4`` macros. To push an array of Julia values one can use the ``JL_GC_PUSHARGS`` macro, which takes as first argument a C array of ``jl_value_t*`` (i.e. ``jl_value_t**``) and as second argument the length of the array. Manipulating the Garbage Collector --------------------------------------------------- -There are some functions to control the GC. In the normal use case, these should not be necessary to be used. +There are some functions to control the GC. In normal use cases, these should not be necessary. ========================= ============================================================================== ``void jl_gc_collect()`` Force a GC run @@ -100,193 +101,108 @@ There are some functions to control the GC. In the normal use case, these should Working with Arrays ======================== -In next example, it is shown how to exchange arrays between Julia back and forth. In order to make this highly performant, the array data will be shared between C and Julia. +Julia and C can share array data without copying. The next example will show how this works. + Julia arrays are represented in C by the datatype ``jl_array_t*``. Basically, ``jl_array_t`` is a struct that contains: - Information about the datatype -- A void pointer to the data block +- A pointer to the data block - Information about the sizes of the array To keep things simple, we start with a 1D array. Creating an array containing Float64 elements of length 10 is done by:: - jl_value_t* array_type = jl_apply_array_type( jl_float64_type, 1 ); - jl_array_t* x = jl_alloc_array_1d(array_type , 10); + jl_value_t* array_type = jl_apply_array_type(jl_float64_type, 1); + jl_array_t* x = jl_alloc_array_1d(array_type, 10); -Alternatively, if you have already allocated the array you can generate a thin wrapper around that data:: +Alternatively, if you have already allocated the array you can generate a thin wrapper around its data:: - double* existingArray = (double*) malloc(sizeof(double)*10); - jl_array_t* x = jl_ptr_to_array_1d(array_type, existingArray, 10, 0); + double *existingArray = (double*)malloc(sizeof(double)*10); + jl_array_t *x = jl_ptr_to_array_1d(array_type, existingArray, 10, 0); -The last parameter is a boolean indicating whether Julia should take over the ownership of the data (only usefull for dynamic arrays). In order to access the data of x, we can use ``jl_array_data``:: +The last argument is a boolean indicating whether Julia should take ownership of the data. If this argument is non-zero, the GC will call ``free`` on the data pointer when the array is no longer referenced. + +In order to access the data of x, we can use ``jl_array_data``:: - double* xData = (double*) jl_array_data(x); + double *xData = (double*)jl_array_data(x); -This is obviously more important when letting Julia allocate the array for us. Now we can fill the array:: +Now we can fill the array:: for(size_t i=0; i max) - jl_too_many_args(function_name, max); - -or equivalently ``JL_NARGS(function_name,min,max)``. General exception that are not type or argument related can be raised using the funtions:: +General exceptions can be raised using the funtions:: void jl_error(const char *str); void jl_errorf(const char *fmt, ...); -While ``jl_error`` takes a simple C string, ``jl_errorf`` can be used like a ``printf`` function with variable arguments:: +``jl_error`` takes a C string, and ``jl_errorf`` is called like ``printf``:: - jl_errorf("An error occurred as x = %d is to large", x); + jl_errorf("argument x = %d is too large", x); where in this example ``x`` is assumed to be an integer. diff --git a/doc/manual/mathematical-operations.rst b/doc/manual/mathematical-operations.rst index 247cc23d2825e..a2262504ae74d 100644 --- a/doc/manual/mathematical-operations.rst +++ b/doc/manual/mathematical-operations.rst @@ -248,7 +248,7 @@ Function Tests if false Mixed-type comparisons between signed integers, unsigned integers, and -floats can be very tricky. A great deal of care has been taken to ensure +floats can be tricky. A great deal of care has been taken to ensure that Julia does them correctly. Chaining comparisons diff --git a/doc/manual/methods.rst b/doc/manual/methods.rst index 9831266f14f38..18463c0c3e024 100644 --- a/doc/manual/methods.rst +++ b/doc/manual/methods.rst @@ -6,7 +6,7 @@ Recall from :ref:`man-functions` that a function is an object that maps a tuple of arguments to a return value, or throws an exception -if no appropriate value can be returned. It is very common for the same +if no appropriate value can be returned. It is common for the same conceptual function or operation to be implemented quite differently for different types of arguments: adding two integers is very different from adding two floating-point numbers, both of which are distinct from @@ -49,7 +49,7 @@ argument more than any of the others: does the addition operation in ``x + y`` belong to ``x`` any more than it does to ``y``? The implementation of a mathematical operator generally depends on the types of all of its arguments. Even beyond mathematical operations, however, -multiple dispatch ends up being a very powerful and convenient paradigm +multiple dispatch ends up being a powerful and convenient paradigm for structuring and organizing programs. .. [#] In C++ or Java, for example, in a method call like diff --git a/doc/manual/noteworthy-differences.rst b/doc/manual/noteworthy-differences.rst index 65ca9f3ab6b91..599e282c756dc 100644 --- a/doc/manual/noteworthy-differences.rst +++ b/doc/manual/noteworthy-differences.rst @@ -74,7 +74,7 @@ One of Julia's goals is to provide an effective language for data analysis and s - Julia does not treat the numbers ``0`` and ``1`` as Booleans. You cannot write ``if (1)`` in Julia, because ``if`` statements accept only booleans. Instead, you can write ``if true``. - Julia does not provide ``nrow`` and ``ncol``. Instead, use ``size(M, 1)`` for ``nrow(M)`` and ``size(M, 2)`` for ``ncol(M)``. - Julia's SVD is not thinned by default, unlike R. To get results like R's, you will often want to call ``svd(X, true)`` on a matrix ``X``. -- Julia is very careful to distinguish scalars, vectors and matrices. In R, ``1`` and ``c(1)`` are the same. In Julia, they can not be used interchangeably. One potentially confusing result of this is that ``x' * y`` for vectors ``x`` and ``y`` is a 1-element vector, not a scalar. To get a scalar, use ``dot(x, y)``. +- Julia is careful to distinguish scalars, vectors and matrices. In R, ``1`` and ``c(1)`` are the same. In Julia, they can not be used interchangeably. One potentially confusing result of this is that ``x' * y`` for vectors ``x`` and ``y`` is a 1-element vector, not a scalar. To get a scalar, use ``dot(x, y)``. - Julia's ``diag()`` and ``diagm()`` are not like R's. - Julia cannot assign to the results of function calls on the left-hand of an assignment operation: you cannot write ``diag(M) = ones(n)``. - Julia discourages populating the main namespace with functions. Most statistical functionality for Julia is found in `packages `_ like the DataFrames and Distributions packages: diff --git a/doc/manual/parallel-computing.rst b/doc/manual/parallel-computing.rst index 2b2941080f984..8944977c973cc 100644 --- a/doc/manual/parallel-computing.rst +++ b/doc/manual/parallel-computing.rst @@ -11,7 +11,7 @@ There are two major factors that influence performance: the speed of the CPUs themselves, and the speed of their access to memory. In a cluster, it's fairly obvious that a given CPU will have fastest access to the RAM within the same computer (node). Perhaps more surprisingly, similar -issues are very relevant on a typical multicore laptop, due to +issues are relevant on a typical multicore laptop, due to differences in the speed of main memory and the `cache `_. Consequently, a good multiprocessing environment should allow control over the @@ -211,7 +211,7 @@ the first. In this toy example, the two methods are easy to distinguish and choose from. However, in a real program designing data movement might require -more thought and very likely some measurement. For example, if the first +more thought and likely some measurement. For example, if the first process needs matrix ``A`` then the first method might be better. Or, if computing ``A`` is expensive and only the current process has it, then moving it to another process might be unavoidable. Or, if the