static Value *mark_julia_type(Value *v, jl_value_t *jt) { if (jt == (jl_value_t*)jl_any_type || v->getType()==jl_pvalue_llvmt) return v; if (has_julia_type(v)) { if (julia_type_of(v) == jt) return v; } else if (julia_type_of_without_metadata(v,false) == jt) { return v; } if (dyn_cast<Instruction>(v) == NULL) v = NoOpInst(v); assert(dyn_cast<Instruction>(v)); char name[3]; int id = jl_type_to_typeid(jt); // store id as base-255 to avoid NUL name[0] = (id%255)+1; name[1] = (id/255)+1; name[2] = '\0'; MDString *md = MDString::get(jl_LLVMContext, name); MDNode *mdn = MDNode::get(jl_LLVMContext, ArrayRef<Value*>(md)); ((Instruction*)v)->setMetadata("julia_type", mdn); return v; }
// 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) { 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); jl_value_t *jt = julia_type_of(v); jl_bits_type_t *jb = (jl_bits_type_t*)jt; if (jb == jl_int8_type) return builder.CreateCall(box_int8_func, builder.CreateSExt(v, T_int32)); if (jb == jl_int16_type) return builder.CreateCall(box_int16_func, v); if (jb == jl_int32_type) return builder.CreateCall(box_int32_func, v); if (jb == jl_int64_type) return builder.CreateCall(box_int64_func, v); if (jb == jl_float32_type) return builder.CreateCall(box_float32_func, v); //if (jb == jl_float64_type) return builder.CreateCall(box_float64_func, v); if (jb == jl_float64_type) { // manually inline alloc & init of Float64 box. cheap, I know. #ifdef __LP64__ Value *newv = builder.CreateCall(jlalloc2w_func); #else Value *newv = builder.CreateCall(jlalloc3w_func); #endif return init_bits_value(newv, jt, t, v); } if (jb == jl_uint8_type) return builder.CreateCall(box_uint8_func, builder.CreateZExt(v, T_int32)); if (jb == jl_uint16_type) return builder.CreateCall(box_uint16_func, v); 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_is_bits_type(jt)) { if (v->getType()->isPointerTy()) { v = builder.CreatePtrToInt(v, T_size); } int nb = jl_bitstype_nbits(jt); if (nb == 8) return builder.CreateCall2(box8_func, literal_pointer_val(jt), v); if (nb == 16) return builder.CreateCall2(box16_func, literal_pointer_val(jt), v); if (nb == 32) return builder.CreateCall2(box32_func, literal_pointer_val(jt), v); if (nb == 64) return builder.CreateCall2(box64_func, literal_pointer_val(jt), v); size_t sz = sizeof(void*) + (nb+7)/8; Value *newv = builder.CreateCall(jlallocobj_func, ConstantInt::get(T_size, sz)); // TODO: make sure this is rooted. I think it is. return init_bits_value(newv, jt, t, v); } assert("Don't know how to box this type" && false); return NULL; }
// 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) { 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); jl_value_t *jt = julia_type_of(v); jl_bits_type_t *jb = (jl_bits_type_t*)jt; if (jb == jl_int8_type) return builder.CreateCall(box_int8_func, builder.CreateSExt(v, T_int32)); if (jb == jl_int16_type) return builder.CreateCall(box_int16_func, v); if (jb == jl_int32_type) return builder.CreateCall(box_int32_func, v); if (jb == jl_int64_type) return builder.CreateCall(box_int64_func, v); if (jb == jl_float32_type) return builder.CreateCall(box_float32_func, v); if (jb == jl_float64_type) return builder.CreateCall(box_float64_func, v); if (jb == jl_uint8_type) return builder.CreateCall(box_uint8_func, builder.CreateZExt(v, T_int32)); if (jb == jl_uint16_type) return builder.CreateCall(box_uint16_func, v); 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_is_bits_type(jt)) { if (v->getType()->isPointerTy()) { v = builder.CreatePtrToInt(v, T_size); } int nb = jl_bitstype_nbits(jt); if (nb == 8) return builder.CreateCall2(box8_func, literal_pointer_val(jt), v); if (nb == 16) return builder.CreateCall2(box16_func, literal_pointer_val(jt), v); if (nb == 32) return builder.CreateCall2(box32_func, literal_pointer_val(jt), v); if (nb == 64) return builder.CreateCall2(box64_func, literal_pointer_val(jt), v); size_t sz = sizeof(void*) + (nb+7)/8; Value *newv = builder.CreateCall(jlallocobj_func, ConstantInt::get(T_size, sz)); builder.CreateStore(literal_pointer_val(jt), builder.CreateBitCast(newv, jl_ppvalue_llvmt)); builder.CreateStore(v, builder.CreateBitCast(bitstype_pointer(newv), PointerType::get(t,0))); // TODO: make sure this is rooted. I think it is. return builder.CreateBitCast(newv, jl_pvalue_llvmt); } assert("Don't know how to box this type" && false); return NULL; }
// 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) { 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) jt = julia_type_of(v); jl_datatype_t *jb = (jl_datatype_t*)jt; assert(jl_is_datatype(jb)); if (jb == jl_int8_type) return builder.CreateCall(box_int8_func, builder.CreateSExt(v, T_int32)); if (jb == jl_int16_type) return builder.CreateCall(box_int16_func, v); if (jb == jl_int32_type) return builder.CreateCall(box_int32_func, v); if (jb == jl_int64_type) return builder.CreateCall(box_int64_func, v); if (jb == jl_float32_type) return builder.CreateCall(box_float32_func, v); //if (jb == jl_float64_type) return builder.CreateCall(box_float64_func, v); if (jb == jl_float64_type) { // manually inline alloc & init of Float64 box. cheap, I know. #ifdef _P64 Value *newv = builder.CreateCall(jlalloc2w_func); #else Value *newv = builder.CreateCall(jlalloc3w_func); #endif return init_bits_value(newv, literal_pointer_val(jt), t, v); } if (jb == jl_uint8_type) return builder.CreateCall(box_uint8_func, builder.CreateZExt(v, T_int32)); if (jb == jl_uint16_type) return builder.CreateCall(box_uint16_func, v); 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; } if (!jb->abstract && jb->size == 0) { if (jb->instance == NULL) jl_new_struct_uninit(jb); assert(jb->instance != NULL); return literal_pointer_val(jb->instance); } return allocate_box_dynamic(literal_pointer_val(jt),jl_datatype_size(jt),v); }
static Value *emit_typeof(Value *p) { // given p, a jl_value_t*, compute its type tag if (p->getType() == jl_pvalue_llvmt) { Value *tt = builder.CreateBitCast(p, jl_ppvalue_llvmt); tt = builder. CreateLoad(builder.CreateGEP(tt,ConstantInt::get(T_size,0)), false); #ifdef OVERLAP_TUPLE_LEN tt = builder. CreateIntToPtr(builder. CreateAnd(builder.CreatePtrToInt(tt, T_int64), ConstantInt::get(T_int64,0x000ffffffffffffe)), jl_pvalue_llvmt); #endif return tt; } return literal_pointer_val(julia_type_of(p)); }
static Value *tpropagate(Value *a, Value *b) { if (has_julia_type(a)) return mark_julia_type(b, julia_type_of(a)); return b; }