void rewriteFunctionType(TypeFunction *tf, IrFuncTy &fty) override { Type *retTy = fty.ret->type->toBasetype(); if (!fty.ret->byref && retTy->ty == Tstruct) { // Rewrite HFAs only because union HFAs are turned into IR types that are // non-HFA and messes up register selection if (isHFA((TypeStruct *)retTy, &fty.ret->ltype)) { fty.ret->rewrite = &hfaToArray; fty.ret->ltype = hfaToArray.type(fty.ret->type); } else { fty.ret->rewrite = &integerRewrite; fty.ret->ltype = integerRewrite.type(fty.ret->type); } } for (auto arg : fty.args) { if (!arg->byref) rewriteArgument(fty, *arg); } // extern(D): reverse parameter order for non variadics, for DMD-compliance if (tf->linkage == LINKd && tf->varargs != 1 && fty.args.size() > 1) { fty.reverseParams = true; } }
void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override { // structs and arrays need rewrite as i32 arrays. This keeps data layout // unchanged when passed in registers r0-r3 and is necessary to match C ABI // for struct passing. Without out this rewrite, each field or array // element is passed in own register. For example: char[4] now all fits in // r0, where before it consumed r0-r3. Type *ty = arg.type->toBasetype(); // TODO: want to also rewrite Tsarray as i32 arrays, but sometimes // llvm selects an aligned ldrd instruction even though the ptr is // unaligned (e.g. walking through members of array char[5][]). // if (ty->ty == Tstruct || ty->ty == Tsarray) if (ty->ty == Tstruct) { // Rewrite HFAs only because union HFAs are turned into IR types that are // non-HFA and messes up register selection if (isHFA((TypeStruct *)ty, &arg.ltype)) { arg.rewrite = &hfaToArray; } else if (DtoAlignment(ty) <= 4) { arg.rewrite = &compositeToArray32; arg.ltype = compositeToArray32.type(arg.type); } else { arg.rewrite = &compositeToArray64; arg.ltype = compositeToArray64.type(arg.type); } } }
bool use_sret(jl_datatype_t *dt) override { jl_datatype_t *ty0 = NULL; bool hva = false; if (jl_datatype_size(dt) > 16 && isHFA(dt, &ty0, &hva) > 8) return true; return false; }
bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab) override { jl_datatype_t *ty0 = NULL; bool hva = false; if (jl_datatype_size(dt) > 64 && isHFA(dt, &ty0, &hva) > 8) { ab.addAttribute(Attribute::ByVal); return true; } return false; }
void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override { // FIXME Type *ty = arg.type->toBasetype(); if (ty->ty == Tstruct || ty->ty == Tsarray) { // Rewrite HFAs only because union HFAs are turned into IR types that are // non-HFA and messes up register selection if (ty->ty == Tstruct && isHFA((TypeStruct *)ty, &arg.ltype)) { hfaToArray.applyTo(arg, arg.ltype); } else { compositeToArray64.applyTo(arg); } } }
bool returnInArg(TypeFunction *tf) override { if (tf->isref) { return false; } Type *rt = tf->next->toBasetype(); // FIXME if (tf->linkage == LINKd) return rt->ty == Tsarray || rt->ty == Tstruct; return rt->ty == Tsarray || (rt->ty == Tstruct && rt->size() > 16 && !isHFA((TypeStruct *)rt)); }
// 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; }
bool returnInArg(TypeFunction *tf) override { // AAPCS 5.4 wants composites > 4-bytes returned by arg except for // Homogeneous Aggregates of up-to 4 float types (6.1.2.1) - an HFA. // TODO: see if Tsarray should be candidate for HFA. if (tf->isref) return false; Type *rt = tf->next->toBasetype(); if (!isPOD(rt)) return true; return rt->ty == Tsarray || (rt->ty == Tstruct && rt->size() > 4 && (gTargetMachine->Options.FloatABIType == llvm::FloatABI::Soft || !isHFA((TypeStruct *)rt))); }
void rewriteFunctionType(IrFuncTy &fty) override { Type *retTy = fty.ret->type->toBasetype(); if (!fty.ret->byref && retTy->ty == Tstruct) { // Rewrite HFAs only because union HFAs are turned into IR types that are // non-HFA and messes up register selection if (isHFA((TypeStruct *)retTy, &fty.ret->ltype)) { hfaToArray.applyTo(*fty.ret, fty.ret->ltype); } else { integerRewrite.applyTo(*fty.ret); } } for (auto arg : fty.args) { if (!arg->byref) rewriteArgument(fty, *arg); } }
void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override { Type *ty = arg.type->toBasetype(); if (ty->ty == Tstruct || ty->ty == Tsarray) { if (ty->ty == Tstruct && isHFA((TypeStruct *)ty, &arg.ltype, 8)) { arg.rewrite = &hfaToArray; arg.ltype = hfaToArray.type(arg.type); } else if (canRewriteAsInt(ty, true)) { arg.rewrite = &integerRewrite; arg.ltype = integerRewrite.type(arg.type); } else { arg.rewrite = &compositeToArray64; arg.ltype = compositeToArray64.type(arg.type); } } else if (ty->isintegral()) { arg.attrs.add(ty->isunsigned() ? LLAttribute::ZExt : LLAttribute::SExt); } }
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); }
void rewriteFunctionType(TypeFunction *tf, IrFuncTy &fty) override { Type *retTy = fty.ret->type->toBasetype(); if (!fty.ret->byref && retTy->ty == Tstruct) { // Rewrite HFAs only because union HFAs are turned into IR types that are // non-HFA and messes up register selection if (isHFA((TypeStruct *)retTy, &fty.ret->ltype)) { fty.ret->rewrite = &hfaToArray; fty.ret->ltype = hfaToArray.type(fty.ret->type); } else { fty.ret->rewrite = &integerRewrite; fty.ret->ltype = integerRewrite.type(fty.ret->type); } } for (auto arg : fty.args) { if (!arg->byref) rewriteArgument(fty, *arg); else if (passByVal(arg->type)) arg->attrs.remove(LLAttribute::ByVal); } }
bool passByVal(TypeFunction *, Type *t) override { t = t->toBasetype(); return t->ty == Tsarray || (t->ty == Tstruct && t->size() > 16 && !isHFA((TypeStruct *)t)); }