From 9f2002c9d230fe76d39bc6faa2f1977ebfac2024 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sun, 11 Aug 2013 03:35:44 -0400 Subject: [PATCH 01/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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/28] 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); } } }