Skip to content

Commit

Permalink
complete ppc64le c-abi (sans vector types extension)
Browse files Browse the repository at this point in the history
future work: consider adding `align 8` to byval to match clang
  • Loading branch information
vtjnash committed Jun 1, 2016
1 parent 9b8a7d4 commit 800da85
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 32 deletions.
53 changes: 37 additions & 16 deletions src/abi_ppc64le.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/abi_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
18 changes: 4 additions & 14 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<AttrBuilder> paramattrs;
AbiState abi = default_abi_state;
sret = 0;
Expand All @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4126,8 +4126,10 @@ static std::unique_ptr<Module> 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");
Expand Down

0 comments on commit 800da85

Please sign in to comment.