Commit f8bd1cd3b1
Changed files (3)
src/all_types.hpp
@@ -74,6 +74,7 @@ enum UndefAllowed {
enum X64CABIClass {
X64CABIClass_Unknown,
X64CABIClass_MEMORY,
+ X64CABIClass_MEMORY_nobyval,
X64CABIClass_INTEGER,
X64CABIClass_SSE,
};
src/analyze.cpp
@@ -919,14 +919,13 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
if (type_is_c_abi_int(g, fn_type_id->return_type)) {
return false;
}
- if (g->zig_target->arch == ZigLLVM_x86) {
- X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
- return abi_class == X64CABIClass_MEMORY;
- } else if (g->zig_target->arch == ZigLLVM_x86_64) {
+ if (g->zig_target->arch == ZigLLVM_x86 ||
+ g->zig_target->arch == ZigLLVM_x86_64 ||
+ target_is_arm(g->zig_target) ||
+ target_is_riscv(g->zig_target))
+ {
X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
- return abi_class == X64CABIClass_MEMORY;
- } else if (target_is_arm(g->zig_target) || target_is_riscv(g->zig_target)) {
- return type_size(g, fn_type_id->return_type) > 16;
+ return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval;
} else if (g->zig_target->arch == ZigLLVM_mipsel) {
return false;
}
@@ -7509,6 +7508,11 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) {
if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) {
return type_windows_abi_x86_64_class(g, ty, ty_size);
+ } else if (g->zig_target->arch == ZigLLVM_aarch64 ||
+ g->zig_target->arch == ZigLLVM_aarch64_be)
+ {
+ X64CABIClass result = type_system_V_abi_x86_64_class(g, ty, ty_size);
+ return (result == X64CABIClass_MEMORY) ? X64CABIClass_MEMORY_nobyval : result;
} else {
return type_system_V_abi_x86_64_class(g, ty, ty_size);
}
src/codegen.cpp
@@ -1847,51 +1847,64 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
return true;
}
- // Arrays are just pointers
- if (ty->id == ZigTypeIdArray) {
- assert(handle_is_ptr(ty));
- switch (fn_walk->id) {
- case FnWalkIdAttrs:
- // arrays passed to C ABI functions may not be at address 0
- addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
- addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
- fn_walk->data.attrs.gen_i += 1;
- break;
- case FnWalkIdCall:
- fn_walk->data.call.gen_param_values->append(val);
- break;
- case FnWalkIdTypes: {
- ZigType *gen_type = get_pointer_to_type(g, ty, true);
- fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type));
- fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type));
- break;
- }
- case FnWalkIdVars: {
- var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
- di_arg_index = fn_walk->data.vars.gen_i;
- dest_ty = get_pointer_to_type(g, ty, false);
- fn_walk->data.vars.gen_i += 1;
- goto var_ok;
- }
- case FnWalkIdInits:
- if (var->decl_node) {
- gen_var_debug_decl(g, var);
+ {
+ // Arrays are just pointers
+ if (ty->id == ZigTypeIdArray) {
+ assert(handle_is_ptr(ty));
+ switch (fn_walk->id) {
+ case FnWalkIdAttrs:
+ // arrays passed to C ABI functions may not be at address 0
+ addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
+ addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
+ fn_walk->data.attrs.gen_i += 1;
+ break;
+ case FnWalkIdCall:
+ fn_walk->data.call.gen_param_values->append(val);
+ break;
+ case FnWalkIdTypes: {
+ ZigType *gen_type = get_pointer_to_type(g, ty, true);
+ fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type));
+ fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type));
+ break;
}
- fn_walk->data.inits.gen_i += 1;
- break;
+ case FnWalkIdVars: {
+ var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
+ di_arg_index = fn_walk->data.vars.gen_i;
+ dest_ty = get_pointer_to_type(g, ty, false);
+ fn_walk->data.vars.gen_i += 1;
+ goto var_ok;
+ }
+ case FnWalkIdInits:
+ if (var->decl_node) {
+ gen_var_debug_decl(g, var);
+ }
+ fn_walk->data.inits.gen_i += 1;
+ break;
+ }
+ return true;
}
- return true;
- }
- if (g->zig_target->arch == ZigLLVM_x86_64) {
X64CABIClass abi_class = type_c_abi_x86_64_class(g, ty);
size_t ty_size = type_size(g, ty);
- if (abi_class == X64CABIClass_MEMORY) {
+ if (abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval) {
assert(handle_is_ptr(ty));
switch (fn_walk->id) {
case FnWalkIdAttrs:
- ZigLLVMAddByValAttr(llvm_fn, fn_walk->data.attrs.gen_i + 1, get_llvm_type(g, ty));
- addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
+ if (abi_class != X64CABIClass_MEMORY_nobyval) {
+ ZigLLVMAddByValAttr(llvm_fn, fn_walk->data.attrs.gen_i + 1, get_llvm_type(g, ty));
+ addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
+ } else if (g->zig_target->arch == ZigLLVM_aarch64 ||
+ g->zig_target->arch == ZigLLVM_aarch64_be)
+ {
+ // no attrs needed
+ } else {
+ if (source_node != nullptr) {
+ give_up_with_c_abi_error(g, source_node);
+ }
+ // otherwise allow codegen code to report a compile error
+ return false;
+ }
+
// Byvalue parameters must not have address 0
addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
fn_walk->data.attrs.gen_i += 1;