Commit f8bd1cd3b1

Andrew Kelley <andrew@ziglang.org>
2019-10-25 01:13:21
implement partial C ABI support for aarch64
1 parent 32c8953
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;