diff --git a/src/abi_ppc64le.cpp b/src/abi_ppc64le.cpp index 12c4782547202..40c75247e33b3 100644 --- a/src/abi_ppc64le.cpp +++ b/src/abi_ppc64le.cpp @@ -42,46 +42,67 @@ typedef bool AbiState; AbiState default_abi_state = 0; -static bool isHFA(jl_datatype_t *ty) +// count the homogeneous floating agregate size (saturating at max count of 8) +static unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0) { size_t i, l = ty->nfields; - jl_value_t *fld0 = jl_field_type(ty, 0); - if (l > 8) - return false; - if (fld0 != (jl_value_t*)jl_float64_type && fld0 != (jl_value_t*)jl_float32_type) - return false; - for (i = 1; i < l; i++) { + if (l == 0) { + if (*ty0 == NULL) { + if (ty == jl_float64_type || ty == jl_float32_type) + *ty0 = ty; + } + return ty == *ty0 ? 1 : 9; + } + int n = 0; + for (i = 0; i < l; i++) { jl_value_t *fld = jl_field_type(ty, i); - if (fld != fld0) - return false; + if (!jl_is_datatype(fld)) + return 9; + n += isHFA((jl_datatype_t*)fld, ty0); + if (n > 8) + return 9; } - return true; + return n; } bool use_sret(AbiState *state, jl_value_t *ty) { // Assume jl_is_datatype(ty) && !jl_is_abstracttype(ty) jl_datatype_t *dt = (jl_datatype_t*)ty; - if (dt->size > 16 && !isHFA(dt)) + jl_datatype_t *ty0 = NULL; + if (dt->size > 16 && isHFA(dt, &ty0) > 8) return true; return false; } void needPassByRef(AbiState *state, jl_value_t *ty, bool *byRef, bool *inReg) { - *byRef = false; + if (!jl_is_datatype(ty) || jl_is_abstracttype(ty) || jl_is_cpointer_type(ty) || jl_is_array_type(ty)) + return; + size_t size = jl_datatype_size(ty); + if (size > 64) + *byRef = true; } Type *preferred_llvm_type(jl_value_t *ty, bool isret) { // Arguments are either scalar or passed by value - if (!jl_is_datatype(ty) || jl_is_abstracttype(ty)) + if (!jl_is_datatype(ty) || jl_is_abstracttype(ty) || jl_is_cpointer_type(ty) || jl_is_array_type(ty)) return NULL; jl_datatype_t *dt = (jl_datatype_t*)ty; - // rewrite integer sized (non-HFA) struct to the corresponding integer - if (!dt->nfields || (isret ? use_sret(NULL, ty) : false) || isHFA(dt)) + size_t size = dt->size; + // don't need to change bitstypes + if (!dt->nfields) return NULL; - return Type::getIntNTy(jl_LLVMContext, dt->size * 8); + // legalize this into [n x f32/f64] + jl_datatype_t *ty0 = NULL; + int hfa = isHFA(dt, &ty0); + if (hfa <= 8) + return ArrayType::get(ty0 == jl_float32_type ? T_float32 : T_float64, hfa); + // rewrite integer-sized (non-HFA) struct to an array of i64 + if (size > 8) + return ArrayType::get(T_int64, (size + 7) / 8); + return Type::getIntNTy(jl_LLVMContext, size * 8); } bool need_private_copy(jl_value_t *ty, bool byRef) diff --git a/src/abi_win32.cpp b/src/abi_win32.cpp index 1209f72520c57..c9cfd10f2b545 100644 --- a/src/abi_win32.cpp +++ b/src/abi_win32.cpp @@ -67,7 +67,7 @@ Type *preferred_llvm_type(jl_value_t *ty, bool isret) return NULL; jl_datatype_t *dt = (jl_datatype_t*)ty; // rewrite integer sized (non-sret) struct to the corresponding integer - if (!dt->nfields || use_sret(NULL, ty)) + if (!dt->nfields) return NULL; return Type::getIntNTy(jl_LLVMContext, dt->size * 8); } diff --git a/src/ccall.cpp b/src/ccall.cpp index 7d9b2f7302d13..9682a269fe132 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -876,7 +876,6 @@ static std::string generate_func_sig( size_t nargt = jl_svec_len(tt); assert(rt && !jl_is_abstract_ref_type(rt)); - AttrBuilder retattrs; std::vector paramattrs; AbiState abi = default_abi_state; sret = 0; @@ -885,7 +884,7 @@ static std::string generate_func_sig( *prt = *lrt = T_void; } else { - *prt = preferred_llvm_type(rt, true); + *prt = sret ? NULL : preferred_llvm_type(rt, true); if (*prt == NULL) *prt = *lrt; @@ -895,6 +894,7 @@ static std::string generate_func_sig( #if !defined(_OS_WINDOWS_) || defined(LLVM35) // llvm used to use the old mingw ABI, skipping this marking works around that difference paramattrs[0].addAttribute(Attribute::StructRet); #endif + paramattrs[0].addAttribute(Attribute::NoAlias); fargt_sig.push_back(PointerType::get(*prt, 0)); sret = 1; } @@ -953,14 +953,8 @@ static std::string generate_func_sig( needPassByRef(&abi, tti, &byRef, &inReg); } - Type *pat = preferred_llvm_type(tti, false); - if (pat != NULL) { - assert(!byRef); // it is an error for an ABI to specify a preferred type for a pointer arg - } - else if (byRef) { - pat = PointerType::get(t, 0); - } - else { + Type *pat = byRef ? PointerType::get(t, 0) : preferred_llvm_type(tti, false); + if (pat == NULL) { pat = t; } @@ -994,10 +988,6 @@ static std::string generate_func_sig( } while (current_isVa && i < nargs); // if is this is the vararg, loop to the end } - if (retattrs.hasAttributes()) { - attributes = AttributeSet::get(jl_LLVMContext, AttributeSet::ReturnIndex, retattrs); - } - for (i = 0; i < nargs + sret; ++i) { if (paramattrs[i].hasAttributes()) { attributes = attributes.addAttributes(jl_LLVMContext, i + 1, diff --git a/src/codegen.cpp b/src/codegen.cpp index 9df623d2970ac..d7d2005b3cdd5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4126,8 +4126,10 @@ static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_func f = Function::Create(FunctionType::get(rt, fsig, false), GlobalVariable::ExternalLinkage, funcName.str(), M); - if (ctx.sret) + if (ctx.sret) { f->addAttribute(1, Attribute::StructRet); + f->addAttribute(1, Attribute::NoAlias); + } addComdat(f); #ifdef LLVM37 f->addFnAttr("no-frame-pointer-elim", "true");