// run time version of bitcast intrinsic JL_DLLEXPORT jl_value_t *jl_bitcast(jl_value_t *ty, jl_value_t *v) { JL_TYPECHK(bitcast, datatype, ty); if (!jl_is_concrete_type(ty) || !jl_is_primitivetype(ty)) jl_error("bitcast: target type not a leaf primitive type"); if (!jl_is_primitivetype(jl_typeof(v))) jl_error("bitcast: value not a primitive type"); if (jl_datatype_size(jl_typeof(v)) != jl_datatype_size(ty)) jl_error("bitcast: argument size does not match size of target type"); if (ty == jl_typeof(v)) return v; if (ty == (jl_value_t*)jl_bool_type) return *(uint8_t*)jl_data_ptr(v) & 1 ? jl_true : jl_false; return jl_new_bits(ty, jl_data_ptr(v)); }
// Determine if homogeneous tuple with fields of type t will have // a special alignment beyond normal Julia rules. // Return special alignment if one exists, 0 if normal alignment rules hold. // A non-zero result *must* match the LLVM rules for a vector type <nfields x t>. // For sake of Ahead-Of-Time (AOT) compilation, this routine has to work // without LLVM being available. unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *t) { if (!jl_is_vecelement_type(t)) return 0; // LLVM 3.7 and 3.8 either crash or generate wrong code for many // SIMD vector sizes N. It seems the rule is that N can have at // most 2 non-zero bits. (This is true at least for N<=100.) See // also <https://llvm.org/bugs/show_bug.cgi?id=27708>. size_t mask = nfields; // See e.g. // <https://graphics.stanford.edu/%7Eseander/bithacks.html> for an // explanation of this bit-counting algorithm. mask &= mask-1; // clear least-significant 1 if present mask &= mask-1; // clear another 1 if (mask) return 0; // nfields has more than two 1s assert(jl_datatype_nfields(t)==1); jl_value_t *ty = jl_field_type(t, 0); if (!jl_is_primitivetype(ty)) // LLVM requires that a vector element be a primitive type. // LLVM allows pointer types as vector elements, but until a // motivating use case comes up for Julia, we reject pointers. return 0; size_t elsz = jl_datatype_size(ty); if (elsz>8 || (1<<elsz & 0x116) == 0) // Element size is not 1, 2, 4, or 8. return 0; size_t size = nfields*elsz; // LLVM's alignment rule for vectors seems to be to round up to // a power of two, even if that's overkill for the target hardware. size_t alignment=1; for( ; size>alignment; alignment*=2 ) continue; return alignment; }
bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab) override { size_t size = jl_datatype_size(dt); if (is_complex64(dt) || is_complex128(dt) || (jl_is_primitivetype(dt) && size <= 8)) return false; ab.addAttribute(Attribute::ByVal); return true; }
bool use_sret(jl_datatype_t *dt) override { size_t size = jl_datatype_size(dt); if (size == 0) return false; if (is_complex64(dt) || (jl_is_primitivetype(dt) && size <= 8)) return false; return true; }
// count the homogeneous floating agregate size (saturating at max count of 8) unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const { size_t i, l = ty->layout->nfields; // handle homogeneous float aggregates if (l == 0) { if (ty != jl_float64_type && ty != jl_float32_type) return 9; *hva = false; if (*ty0 == NULL) *ty0 = ty; else if (*hva || ty->size != (*ty0)->size) return 9; return 1; } // handle homogeneous vector aggregates jl_datatype_t *fld0 = (jl_datatype_t*)jl_field_type(ty, 0); if (!jl_is_datatype(fld0) || ty->name == jl_vecelement_typename) return 9; if (fld0->name == jl_vecelement_typename) { if (!jl_is_primitivetype(jl_tparam0(fld0)) || jl_datatype_size(ty) > 16) return 9; if (l != 1 && l != 2 && l != 4 && l != 8 && l != 16) return 9; *hva = true; if (*ty0 == NULL) *ty0 = ty; else if (!*hva || ty->size != (*ty0)->size) return 9; for (i = 1; i < l; i++) { jl_datatype_t *fld = (jl_datatype_t*)jl_field_type(ty, i); if (fld != fld0) return 9; } return 1; } // recurse through other struct types int n = 0; for (i = 0; i < l; i++) { jl_datatype_t *fld = (jl_datatype_t*)jl_field_type(ty, i); if (!jl_is_datatype(fld) || ((jl_datatype_t*)fld)->layout == NULL) return 9; n += isHFA((jl_datatype_t*)fld, ty0, hva); if (n > 8) return 9; } return n; }
Type *preferred_llvm_type(jl_datatype_t *dt, bool isret) const override { // Arguments are either scalar or passed by value size_t size = jl_datatype_size(dt); // don't need to change bitstypes if (!jl_datatype_nfields(dt)) return NULL; // legalize this into [n x f32/f64] jl_datatype_t *ty0 = NULL; bool hva = false; int hfa = isHFA(dt, &ty0, &hva); if (hfa <= 8) { if (ty0 == jl_float32_type) { return ArrayType::get(T_float32, hfa); } else if (ty0 == jl_float64_type) { return ArrayType::get(T_float64, hfa); } else { jl_datatype_t *vecty = (jl_datatype_t*)jl_field_type(ty0, 0); assert(jl_is_datatype(vecty) && vecty->name == jl_vecelement_typename); jl_value_t *elemty = jl_tparam0(vecty); assert(jl_is_primitivetype(elemty)); Type *ety = julia_type_to_llvm(elemty); Type *vty = VectorType::get(ety, jl_datatype_nfields(ty0)); return ArrayType::get(vty, hfa); } } // rewrite integer-sized (non-HFA) struct to an array // the bitsize of the integer gives the desired alignment if (size > 8) { if (jl_datatype_align(dt) <= 8) { return ArrayType::get(T_int64, (size + 7) / 8); } else { Type *T_int128 = Type::getIntNTy(jl_LLVMContext, 128); return ArrayType::get(T_int128, (size + 15) / 16); } } return Type::getIntNTy(jl_LLVMContext, size * 8); }