authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-23 12:16:58-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-23 12:16:58-07:00
log04472af328632d80ea9ea089cfd5de8fac6dd039
tree7b8d46635c0a0accc82277a6209a87e4d4b9d13b
parenta3033c7bd9ec26abd2f831cf75eb85f06590deed
parentf2a7aba586157482131611c57a283f3b4cfee98d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13251 from Vexu/c-abi

implement ARM C ABI, separate C ABI tests from standalone tests

13 files changed, 694 insertions(+), 201 deletions(-)

build.zig+1
......@@ -508,6 +508,7 @@ pub fn build(b: *Builder) !void {
508508 b.enable_wasmtime,
509509 b.enable_wine,
510510 ));
511 test_step.dependOn(tests.addCAbiTests(b, skip_non_native));
511512 test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests));
512513 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
513514 test_step.dependOn(tests.addCliTests(b, test_filter, modes));
src/arch/aarch64/abi.zig+38-24
......@@ -5,41 +5,54 @@ const Register = bits.Register;
55const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
66const Type = @import("../../type.zig").Type;
77
8pub const Class = enum(u8) { memory, integer, none, float_array, _ };
8pub const Class = union(enum) {
9 memory,
10 byval,
11 integer,
12 double_integer,
13 float_array: u8,
14};
915
1016/// For `float_array` the second element will be the amount of floats.
11pub fn classifyType(ty: Type, target: std.Target) [2]Class {
12 var maybe_float_bits: ?u16 = null;
13 const float_count = countFloats(ty, target, &maybe_float_bits);
14 if (float_count <= sret_float_count) return .{ .float_array, @intToEnum(Class, float_count) };
15 return classifyTypeInner(ty, target);
16}
17pub fn classifyType(ty: Type, target: std.Target) Class {
18 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime());
1719
18fn classifyTypeInner(ty: Type, target: std.Target) [2]Class {
19 if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none };
20 var maybe_float_bits: ?u16 = null;
2021 switch (ty.zigTypeTag()) {
2122 .Struct => {
22 if (ty.containerLayout() == .Packed) return .{ .integer, .none };
23 if (ty.containerLayout() == .Packed) return .byval;
24 const float_count = countFloats(ty, target, &maybe_float_bits);
25 if (float_count <= sret_float_count) return .{ .float_array = float_count };
26
2327 const bit_size = ty.bitSize(target);
24 if (bit_size > 128) return .{ .memory, .none };
25 if (bit_size > 64) return .{ .integer, .integer };
26 return .{ .integer, .none };
28 if (bit_size > 128) return .memory;
29 if (bit_size > 64) return .double_integer;
30 return .integer;
2731 },
2832 .Union => {
33 if (ty.containerLayout() == .Packed) return .byval;
34 const float_count = countFloats(ty, target, &maybe_float_bits);
35 if (float_count <= sret_float_count) return .{ .float_array = float_count };
36
37 const bit_size = ty.bitSize(target);
38 if (bit_size > 128) return .memory;
39 if (bit_size > 64) return .double_integer;
40 return .integer;
41 },
42 .Int, .Enum, .ErrorSet, .Float, .Bool => return .byval,
43 .Vector => {
2944 const bit_size = ty.bitSize(target);
30 if (bit_size > 128) return .{ .memory, .none };
31 if (bit_size > 64) return .{ .integer, .integer };
32 return .{ .integer, .none };
45 // TODO is this controlled by a cpu feature?
46 if (bit_size > 128) return .memory;
47 return .byval;
3348 },
34 .Int, .Enum, .ErrorSet, .Vector, .Float, .Bool => return .{ .integer, .none },
35 .Array => return .{ .memory, .none },
3649 .Optional => {
3750 std.debug.assert(ty.isPtrLikeOptional());
38 return .{ .integer, .none };
51 return .byval;
3952 },
4053 .Pointer => {
4154 std.debug.assert(!ty.isSlice());
42 return .{ .integer, .none };
55 return .byval;
4356 },
4457 .ErrorUnion,
4558 .Frame,
......@@ -55,17 +68,18 @@ fn classifyTypeInner(ty: Type, target: std.Target) [2]Class {
5568 .Fn,
5669 .Opaque,
5770 .EnumLiteral,
71 .Array,
5872 => unreachable,
5973 }
6074}
6175
6276const sret_float_count = 4;
63fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 {
64 const invalid = std.math.maxInt(u32);
77fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u8 {
78 const invalid = std.math.maxInt(u8);
6579 switch (ty.zigTypeTag()) {
6680 .Union => {
6781 const fields = ty.unionFields();
68 var max_count: u32 = 0;
82 var max_count: u8 = 0;
6983 for (fields.values()) |field| {
7084 const field_count = countFloats(field.ty, target, maybe_float_bits);
7185 if (field_count == invalid) return invalid;
......@@ -76,7 +90,7 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 {
7690 },
7791 .Struct => {
7892 const fields_len = ty.structFieldCount();
79 var count: u32 = 0;
93 var count: u8 = 0;
8094 var i: u32 = 0;
8195 while (i < fields_len) : (i += 1) {
8296 const field_ty = ty.structFieldType(i);
src/arch/arm/abi.zig+154
......@@ -2,6 +2,160 @@ const std = @import("std");
22const bits = @import("bits.zig");
33const Register = bits.Register;
44const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
5const Type = @import("../../type.zig").Type;
6
7pub const Class = union(enum) {
8 memory,
9 byval,
10 i32_array: u8,
11 i64_array: u8,
12
13 fn arrSize(total_size: u64, arr_size: u64) Class {
14 const count = @intCast(u8, std.mem.alignForward(total_size, arr_size) / arr_size);
15 if (arr_size == 32) {
16 return .{ .i32_array = count };
17 } else {
18 return .{ .i64_array = count };
19 }
20 }
21};
22
23pub const Context = enum { ret, arg };
24
25pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class {
26 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime());
27
28 var maybe_float_bits: ?u16 = null;
29 const max_byval_size = 512;
30 switch (ty.zigTypeTag()) {
31 .Struct => {
32 const bit_size = ty.bitSize(target);
33 if (ty.containerLayout() == .Packed) {
34 if (bit_size > 64) return .memory;
35 return .byval;
36 }
37 if (bit_size > max_byval_size) return .memory;
38 const float_count = countFloats(ty, target, &maybe_float_bits);
39 if (float_count <= byval_float_count) return .byval;
40
41 const fields = ty.structFieldCount();
42 var i: u32 = 0;
43 while (i < fields) : (i += 1) {
44 const field_ty = ty.structFieldType(i);
45 const field_alignment = ty.structFieldAlign(i, target);
46 const field_size = field_ty.bitSize(target);
47 if (field_size > 32 or field_alignment > 32) {
48 return Class.arrSize(bit_size, 64);
49 }
50 }
51 return Class.arrSize(bit_size, 32);
52 },
53 .Union => {
54 const bit_size = ty.bitSize(target);
55 if (ty.containerLayout() == .Packed) {
56 if (bit_size > 64) return .memory;
57 return .byval;
58 }
59 if (bit_size > max_byval_size) return .memory;
60 const float_count = countFloats(ty, target, &maybe_float_bits);
61 if (float_count <= byval_float_count) return .byval;
62
63 for (ty.unionFields().values()) |field| {
64 if (field.ty.bitSize(target) > 32 or field.normalAlignment(target) > 32) {
65 return Class.arrSize(bit_size, 64);
66 }
67 }
68 return Class.arrSize(bit_size, 32);
69 },
70 .Bool, .Float => return .byval,
71 .Int => {
72 // TODO this is incorrect for _BitInt(128) but implementing
73 // this correctly makes implementing compiler-rt impossible.
74 // const bit_size = ty.bitSize(target);
75 // if (bit_size > 64) return .memory;
76 return .byval;
77 },
78 .Enum, .ErrorSet => {
79 const bit_size = ty.bitSize(target);
80 if (bit_size > 64) return .memory;
81 return .byval;
82 },
83 .Vector => {
84 const bit_size = ty.bitSize(target);
85 // TODO is this controlled by a cpu feature?
86 if (ctx == .ret and bit_size > 128) return .memory;
87 if (bit_size > 512) return .memory;
88 return .byval;
89 },
90 .Optional => {
91 std.debug.assert(ty.isPtrLikeOptional());
92 return .byval;
93 },
94 .Pointer => {
95 std.debug.assert(!ty.isSlice());
96 return .byval;
97 },
98 .ErrorUnion,
99 .Frame,
100 .AnyFrame,
101 .NoReturn,
102 .Void,
103 .Type,
104 .ComptimeFloat,
105 .ComptimeInt,
106 .Undefined,
107 .Null,
108 .BoundFn,
109 .Fn,
110 .Opaque,
111 .EnumLiteral,
112 .Array,
113 => unreachable,
114 }
115}
116
117const byval_float_count = 4;
118fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 {
119 const invalid = std.math.maxInt(u32);
120 switch (ty.zigTypeTag()) {
121 .Union => {
122 const fields = ty.unionFields();
123 var max_count: u32 = 0;
124 for (fields.values()) |field| {
125 const field_count = countFloats(field.ty, target, maybe_float_bits);
126 if (field_count == invalid) return invalid;
127 if (field_count > max_count) max_count = field_count;
128 if (max_count > byval_float_count) return invalid;
129 }
130 return max_count;
131 },
132 .Struct => {
133 const fields_len = ty.structFieldCount();
134 var count: u32 = 0;
135 var i: u32 = 0;
136 while (i < fields_len) : (i += 1) {
137 const field_ty = ty.structFieldType(i);
138 const field_count = countFloats(field_ty, target, maybe_float_bits);
139 if (field_count == invalid) return invalid;
140 count += field_count;
141 if (count > byval_float_count) return invalid;
142 }
143 return count;
144 },
145 .Float => {
146 const float_bits = maybe_float_bits.* orelse {
147 const float_bits = ty.floatBits(target);
148 if (float_bits != 32 and float_bits != 64) return invalid;
149 maybe_float_bits.* = float_bits;
150 return 1;
151 };
152 if (ty.floatBits(target) == float_bits) return 1;
153 return invalid;
154 },
155 .Void => return 0,
156 else => return invalid,
157 }
158}
5159
6160pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };
7161pub const caller_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3 };
src/arch/riscv64/abi.zig+69
......@@ -2,6 +2,75 @@ const std = @import("std");
22const bits = @import("bits.zig");
33const Register = bits.Register;
44const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
5const Type = @import("../../type.zig").Type;
6
7pub const Class = enum { memory, byval, integer, double_integer };
8
9pub fn classifyType(ty: Type, target: std.Target) Class {
10 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime());
11
12 const max_byval_size = target.cpu.arch.ptrBitWidth() * 2;
13 switch (ty.zigTypeTag()) {
14 .Struct => {
15 const bit_size = ty.bitSize(target);
16 if (ty.containerLayout() == .Packed) {
17 if (bit_size > max_byval_size) return .memory;
18 return .byval;
19 }
20 // TODO this doesn't exactly match what clang produces but its better than nothing
21 if (bit_size > max_byval_size) return .memory;
22 if (bit_size > max_byval_size / 2) return .double_integer;
23 return .integer;
24 },
25 .Union => {
26 const bit_size = ty.bitSize(target);
27 if (ty.containerLayout() == .Packed) {
28 if (bit_size > max_byval_size) return .memory;
29 return .byval;
30 }
31 // TODO this doesn't exactly match what clang produces but its better than nothing
32 if (bit_size > max_byval_size) return .memory;
33 if (bit_size > max_byval_size / 2) return .double_integer;
34 return .integer;
35 },
36 .Bool => return .integer,
37 .Float => return .byval,
38 .Int, .Enum, .ErrorSet => {
39 const bit_size = ty.bitSize(target);
40 if (bit_size > max_byval_size) return .memory;
41 return .byval;
42 },
43 .Vector => {
44 const bit_size = ty.bitSize(target);
45 if (bit_size > max_byval_size) return .memory;
46 return .integer;
47 },
48 .Optional => {
49 std.debug.assert(ty.isPtrLikeOptional());
50 return .byval;
51 },
52 .Pointer => {
53 std.debug.assert(!ty.isSlice());
54 return .byval;
55 },
56 .ErrorUnion,
57 .Frame,
58 .AnyFrame,
59 .NoReturn,
60 .Void,
61 .Type,
62 .ComptimeFloat,
63 .ComptimeInt,
64 .Undefined,
65 .Null,
66 .BoundFn,
67 .Fn,
68 .Opaque,
69 .EnumLiteral,
70 .Array,
71 => unreachable,
72 }
73}
574
675pub const callee_preserved_regs = [_]Register{
776 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
src/arch/x86_64/CodeGen.zig+1-1
......@@ -7149,7 +7149,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
71497149
71507150 const classes: []const abi.Class = switch (self.target.os.tag) {
71517151 .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)},
7152 else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*), .none),
7152 else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none),
71537153 };
71547154 if (classes.len > 1) {
71557155 return self.fail("TODO handle multiple classes per type", .{});
src/arch/x86_64/abi.zig+21-3
......@@ -60,9 +60,11 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
6060 }
6161}
6262
63pub const Context = enum { ret, arg };
64
6365/// There are a maximum of 8 possible return slots. Returned values are in
6466/// the beginning of the array; unused slots are filled with .none.
65pub fn classifySystemV(ty: Type, target: Target) [8]Class {
67pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
6668 const memory_class = [_]Class{
6769 .memory, .none, .none, .none,
6870 .none, .none, .none, .none,
......@@ -134,6 +136,22 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
134136 },
135137 .Vector => {
136138 const elem_ty = ty.childType();
139 if (ctx == .arg) {
140 const bit_size = ty.bitSize(target);
141 if (bit_size > 128) return memory_class;
142 if (bit_size > 80) return .{
143 .integer, .integer, .none, .none,
144 .none, .none, .none, .none,
145 };
146 if (bit_size > 64) return .{
147 .x87, .none, .none, .none,
148 .none, .none, .none, .none,
149 };
150 return .{
151 .integer, .none, .none, .none,
152 .none, .none, .none, .none,
153 };
154 }
137155 const bits = elem_ty.bitSize(target) * ty.arrayLen();
138156 if (bits <= 64) return .{
139157 .sse, .none, .none, .none,
......@@ -201,7 +219,7 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
201219 }
202220 }
203221 const field_size = field.ty.abiSize(target);
204 const field_class_array = classifySystemV(field.ty, target);
222 const field_class_array = classifySystemV(field.ty, target, .arg);
205223 const field_class = std.mem.sliceTo(&field_class_array, .none);
206224 if (byte_i + field_size <= 8) {
207225 // Combine this field with the previous one.
......@@ -315,7 +333,7 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
315333 }
316334 }
317335 // Combine this field with the previous one.
318 const field_class = classifySystemV(field.ty, target);
336 const field_class = classifySystemV(field.ty, target, .arg);
319337 for (result) |*result_item, i| {
320338 const field_item = field_class[i];
321339 // "If both classes are equal, this is the resulting class."
src/codegen/llvm.zig+143-51
......@@ -24,6 +24,8 @@ const CType = @import("../type.zig").CType;
2424const x86_64_abi = @import("../arch/x86_64/abi.zig");
2525const wasm_c_abi = @import("../arch/wasm/abi.zig");
2626const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
27const arm_c_abi = @import("../arch/arm/abi.zig");
28const riscv_c_abi = @import("../arch/riscv64/abi.zig");
2729
2830const Error = error{ OutOfMemory, CodegenFail };
2931
......@@ -1130,6 +1132,25 @@ pub const Object = struct {
11301132 const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
11311133 _ = builder.buildStore(param, casted_ptr);
11321134
1135 if (isByRef(param_ty)) {
1136 try args.append(arg_ptr);
1137 } else {
1138 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1139 load_inst.setAlignment(alignment);
1140 try args.append(load_inst);
1141 }
1142 },
1143 .i32_array, .i64_array => {
1144 const param_ty = fn_info.param_types[it.zig_index - 1];
1145 const param_llvm_ty = try dg.lowerType(param_ty);
1146 const param = llvm_func.getParam(llvm_arg_i);
1147 llvm_arg_i += 1;
1148
1149 const alignment = param_ty.abiAlignment(target);
1150 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
1151 const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
1152 _ = builder.buildStore(param, casted_ptr);
1153
11331154 if (isByRef(param_ty)) {
11341155 try args.append(arg_ptr);
11351156 } else {
......@@ -2578,6 +2599,8 @@ pub const DeclGen = struct {
25782599 .multiple_llvm_float,
25792600 .as_u16,
25802601 .float_array,
2602 .i32_array,
2603 .i64_array,
25812604 => continue,
25822605
25832606 .slice => unreachable, // extern functions do not support slice types.
......@@ -3132,6 +3155,11 @@ pub const DeclGen = struct {
31323155 const arr_ty = float_ty.arrayType(field_count);
31333156 try llvm_params.append(arr_ty);
31343157 },
3158 .i32_array, .i64_array => |arr_len| {
3159 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
3160 const arr_ty = dg.context.intType(elem_size).arrayType(arr_len);
3161 try llvm_params.append(arr_ty);
3162 },
31353163 };
31363164
31373165 return llvm.functionType(
......@@ -4822,6 +4850,25 @@ pub const FuncGen = struct {
48224850 load_inst.setAlignment(alignment);
48234851 try llvm_args.append(load_inst);
48244852 },
4853 .i32_array, .i64_array => |arr_len| {
4854 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
4855 const arg = args[it.zig_index - 1];
4856 const arg_ty = self.air.typeOf(arg);
4857 var llvm_arg = try self.resolveInst(arg);
4858 if (!isByRef(arg_ty)) {
4859 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4860 const store_inst = self.builder.buildStore(llvm_arg, p);
4861 store_inst.setAlignment(arg_ty.abiAlignment(target));
4862 llvm_arg = store_inst;
4863 }
4864
4865 const array_llvm_ty = self.dg.context.intType(elem_size).arrayType(arr_len);
4866 const casted = self.builder.buildBitCast(llvm_arg, array_llvm_ty.pointerType(0), "");
4867 const alignment = arg_ty.abiAlignment(target);
4868 const load_inst = self.builder.buildLoad(array_llvm_ty, casted, "");
4869 load_inst.setAlignment(alignment);
4870 try llvm_args.append(load_inst);
4871 },
48254872 };
48264873
48274874 const call = self.builder.buildCall(
......@@ -10083,10 +10130,16 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
1008310130 .mips, .mipsel => return false,
1008410131 .x86_64 => switch (target.os.tag) {
1008510132 .windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory,
10086 else => return x86_64_abi.classifySystemV(fn_info.return_type, target)[0] == .memory,
10133 else => return x86_64_abi.classifySystemV(fn_info.return_type, target, .ret)[0] == .memory,
1008710134 },
1008810135 .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,
10089 .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target)[0] == .memory,
10136 .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory,
10137 .arm, .armeb => switch (arm_c_abi.classifyType(fn_info.return_type, target, .ret)) {
10138 .memory, .i64_array => return true,
10139 .i32_array => |size| return size != 1,
10140 .byval => return false,
10141 },
10142 .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, target) == .memory,
1009010143 else => return false, // TODO investigate C ABI for other architectures
1009110144 },
1009210145 else => return false,
......@@ -10139,7 +10192,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
1013910192 if (is_scalar) {
1014010193 return dg.lowerType(fn_info.return_type);
1014110194 }
10142 const classes = x86_64_abi.classifySystemV(fn_info.return_type, target);
10195 const classes = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret);
1014310196 if (classes[0] == .memory) {
1014410197 return dg.context.voidType();
1014510198 }
......@@ -10197,22 +10250,44 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
1019710250 return dg.context.intType(@intCast(c_uint, abi_size * 8));
1019810251 },
1019910252 .aarch64, .aarch64_be => {
10200 if (is_scalar) {
10201 return dg.lowerType(fn_info.return_type);
10202 }
10203 const classes = aarch64_c_abi.classifyType(fn_info.return_type, target);
10204 if (classes[0] == .memory or classes[0] == .none) {
10205 return dg.context.voidType();
10253 switch (aarch64_c_abi.classifyType(fn_info.return_type, target)) {
10254 .memory => return dg.context.voidType(),
10255 .float_array => return dg.lowerType(fn_info.return_type),
10256 .byval => return dg.lowerType(fn_info.return_type),
10257 .integer => {
10258 const bit_size = fn_info.return_type.bitSize(target);
10259 return dg.context.intType(@intCast(c_uint, bit_size));
10260 },
10261 .double_integer => return dg.context.intType(64).arrayType(2),
1020610262 }
10207 if (classes[0] == .float_array) {
10208 return dg.lowerType(fn_info.return_type);
10263 },
10264 .arm, .armeb => {
10265 switch (arm_c_abi.classifyType(fn_info.return_type, target, .ret)) {
10266 .memory, .i64_array => return dg.context.voidType(),
10267 .i32_array => |len| if (len == 1) {
10268 return dg.context.intType(32);
10269 } else {
10270 return dg.context.voidType();
10271 },
10272 .byval => return dg.lowerType(fn_info.return_type),
1020910273 }
10210 if (classes[1] == .none) {
10211 const bit_size = fn_info.return_type.bitSize(target);
10212 return dg.context.intType(@intCast(c_uint, bit_size));
10274 },
10275 .riscv32, .riscv64 => {
10276 switch (riscv_c_abi.classifyType(fn_info.return_type, target)) {
10277 .memory => return dg.context.voidType(),
10278 .integer => {
10279 const bit_size = fn_info.return_type.bitSize(target);
10280 return dg.context.intType(@intCast(c_uint, bit_size));
10281 },
10282 .double_integer => {
10283 var llvm_types_buffer: [2]*llvm.Type = .{
10284 dg.context.intType(64),
10285 dg.context.intType(64),
10286 };
10287 return dg.context.structType(&llvm_types_buffer, 2, .False);
10288 },
10289 .byval => return dg.lowerType(fn_info.return_type),
1021310290 }
10214
10215 return dg.context.intType(64).arrayType(2);
1021610291 },
1021710292 // TODO investigate C ABI for other architectures
1021810293 else => return dg.lowerType(fn_info.return_type),
......@@ -10242,6 +10317,8 @@ const ParamTypeIterator = struct {
1024210317 slice,
1024310318 as_u16,
1024410319 float_array: u8,
10320 i32_array: u8,
10321 i64_array: u8,
1024510322 };
1024610323
1024710324 pub fn next(it: *ParamTypeIterator) ?Lowering {
......@@ -10288,15 +10365,6 @@ const ParamTypeIterator = struct {
1028810365 .C => {
1028910366 const is_scalar = isScalar(ty);
1029010367 switch (it.target.cpu.arch) {
10291 .riscv32, .riscv64 => {
10292 it.zig_index += 1;
10293 it.llvm_index += 1;
10294 if (ty.tag() == .f16) {
10295 return .as_u16;
10296 } else {
10297 return .byval;
10298 }
10299 },
1030010368 .mips, .mipsel => {
1030110369 it.zig_index += 1;
1030210370 it.llvm_index += 1;
......@@ -10334,18 +10402,18 @@ const ParamTypeIterator = struct {
1033410402 else => unreachable,
1033510403 },
1033610404 else => {
10337 if (is_scalar) {
10338 it.zig_index += 1;
10339 it.llvm_index += 1;
10340 return .byval;
10341 }
10342 const classes = x86_64_abi.classifySystemV(ty, it.target);
10405 const classes = x86_64_abi.classifySystemV(ty, it.target, .arg);
1034310406 if (classes[0] == .memory) {
1034410407 it.zig_index += 1;
1034510408 it.llvm_index += 1;
1034610409 it.byval_attr = true;
1034710410 return .byref;
1034810411 }
10412 if (is_scalar) {
10413 it.zig_index += 1;
10414 it.llvm_index += 1;
10415 return .byval;
10416 }
1034910417 var llvm_types_buffer: [8]u16 = undefined;
1035010418 var llvm_types_index: u32 = 0;
1035110419 for (classes) |class| {
......@@ -10383,11 +10451,6 @@ const ParamTypeIterator = struct {
1038310451 it.llvm_index += 1;
1038410452 return .abi_sized_int;
1038510453 }
10386 if (classes[0] == .sse and classes[1] == .none) {
10387 it.zig_index += 1;
10388 it.llvm_index += 1;
10389 return .byval;
10390 }
1039110454 it.llvm_types_buffer = llvm_types_buffer;
1039210455 it.llvm_types_len = llvm_types_index;
1039310456 it.llvm_index += llvm_types_index;
......@@ -10410,24 +10473,45 @@ const ParamTypeIterator = struct {
1041010473 .aarch64, .aarch64_be => {
1041110474 it.zig_index += 1;
1041210475 it.llvm_index += 1;
10413 if (is_scalar) {
10414 return .byval;
10476 switch (aarch64_c_abi.classifyType(ty, it.target)) {
10477 .memory => return .byref,
10478 .float_array => |len| return Lowering{ .float_array = len },
10479 .byval => return .byval,
10480 .integer => {
10481 it.llvm_types_len = 1;
10482 it.llvm_types_buffer[0] = 64;
10483 return .multiple_llvm_ints;
10484 },
10485 .double_integer => return Lowering{ .i64_array = 2 },
1041510486 }
10416 const classes = aarch64_c_abi.classifyType(ty, it.target);
10417 if (classes[0] == .memory) {
10418 return .byref;
10487 },
10488 .arm, .armeb => {
10489 it.zig_index += 1;
10490 it.llvm_index += 1;
10491 switch (arm_c_abi.classifyType(ty, it.target, .arg)) {
10492 .memory => {
10493 it.byval_attr = true;
10494 return .byref;
10495 },
10496 .byval => return .byval,
10497 .i32_array => |size| return Lowering{ .i32_array = size },
10498 .i64_array => |size| return Lowering{ .i64_array = size },
1041910499 }
10420 if (classes[0] == .float_array) {
10421 return Lowering{ .float_array = @enumToInt(classes[1]) };
10500 },
10501 .riscv32, .riscv64 => {
10502 it.zig_index += 1;
10503 it.llvm_index += 1;
10504 if (ty.tag() == .f16) {
10505 return .as_u16;
1042210506 }
10423 if (classes[1] == .none) {
10424 it.llvm_types_len = 1;
10425 } else {
10426 it.llvm_types_len = 2;
10507 switch (riscv_c_abi.classifyType(ty, it.target)) {
10508 .memory => {
10509 return .byref;
10510 },
10511 .byval => return .byval,
10512 .integer => return .abi_sized_int,
10513 .double_integer => return Lowering{ .i64_array = 2 },
1042710514 }
10428 it.llvm_types_buffer[0] = 64;
10429 it.llvm_types_buffer[1] = 64;
10430 return .multiple_llvm_ints;
1043110515 },
1043210516 // TODO investigate C ABI for other architectures
1043310517 else => {
......@@ -10475,8 +10559,16 @@ fn ccAbiPromoteInt(
1047510559 };
1047610560 if (int_info.bits <= 16) return int_info.signedness;
1047710561 switch (target.cpu.arch) {
10562 .riscv64 => {
10563 if (int_info.bits == 32) {
10564 // LLVM always signextends 32 bit ints, unsure if bug.
10565 return .signed;
10566 }
10567 if (int_info.bits < 64) {
10568 return int_info.signedness;
10569 }
10570 },
1047810571 .sparc64,
10479 .riscv64,
1048010572 .powerpc64,
1048110573 .powerpc64le,
1048210574 => {
test/c_abi/build.zig deleted-22
......@@ -1,22 +0,0 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const rel_opts = b.standardReleaseOptions();
5 const target = b.standardTargetOptions(.{});
6
7 const c_obj = b.addObject("cfuncs", null);
8 c_obj.addCSourceFile("cfuncs.c", &[_][]const u8{"-std=c99"});
9 c_obj.setBuildMode(rel_opts);
10 c_obj.linkSystemLibrary("c");
11 c_obj.target = target;
12
13 const main = b.addTest("main.zig");
14 main.setBuildMode(rel_opts);
15 main.addObject(c_obj);
16 main.target = target;
17
18 const test_step = b.step("test", "Test the program");
19 test_step.dependOn(&main.step);
20
21 b.default_step.dependOn(test_step);
22}
test/c_abi/build_wasm.zig deleted-24
......@@ -1,24 +0,0 @@
1const std = @import("std");
2const Builder = std.build.Builder;
3
4pub fn build(b: *Builder) void {
5 const rel_opts = b.standardReleaseOptions();
6 const target: std.zig.CrossTarget = .{ .cpu_arch = .wasm32, .os_tag = .wasi };
7 b.use_stage1 = false;
8
9 const c_obj = b.addObject("cfuncs", null);
10 c_obj.addCSourceFile("cfuncs.c", &[_][]const u8{"-std=c99"});
11 c_obj.setBuildMode(rel_opts);
12 c_obj.linkSystemLibrary("c");
13 c_obj.setTarget(target);
14
15 const main = b.addTest("main.zig");
16 main.setBuildMode(rel_opts);
17 main.addObject(c_obj);
18 main.setTarget(target);
19
20 const test_step = b.step("test", "Test the program");
21 test_step.dependOn(&main.step);
22
23 b.default_step.dependOn(test_step);
24}
test/c_abi/cfuncs.c+84-15
......@@ -1,8 +1,8 @@
1#include <complex.h>
12#include <inttypes.h>
2#include <stdlib.h>
33#include <stdbool.h>
4#include <stdlib.h>
45#include <string.h>
5#include <complex.h>
66
77void zig_panic();
88
......@@ -12,6 +12,14 @@ static void assert_or_panic(bool ok) {
1212 }
1313}
1414
15#if defined __powerpc__ && !defined _ARCH_PPC64
16# define ZIG_PPC32
17#endif
18
19#if defined __riscv && defined _ILP32
20# define ZIG_RISCV32
21#endif
22
1523#ifdef __i386__
1624# define ZIG_NO_I128
1725#endif
......@@ -24,6 +32,14 @@ static void assert_or_panic(bool ok) {
2432# define ZIG_NO_I128
2533#endif
2634
35#ifdef ZIG_PPC32
36# define ZIG_NO_I128
37#endif
38
39#ifdef ZIG_RISCV32
40# define ZIG_NO_I128
41#endif
42
2743#ifdef __i386__
2844# define ZIG_NO_COMPLEX
2945#endif
......@@ -32,6 +48,18 @@ static void assert_or_panic(bool ok) {
3248# define ZIG_NO_COMPLEX
3349#endif
3450
51#ifdef __arm__
52# define ZIG_NO_COMPLEX
53#endif
54
55#ifdef __powerpc__
56# define ZIG_NO_COMPLEX
57#endif
58
59#ifdef __riscv
60# define ZIG_NO_COMPLEX
61#endif
62
3563#ifndef ZIG_NO_I128
3664struct i128 {
3765 __int128 value;
......@@ -206,7 +234,7 @@ void run_c_tests(void) {
206234 zig_longdouble(12.34l);
207235 zig_five_floats(1.0f, 2.0f, 3.0f, 4.0f, 5.0f);
208236
209 zig_ptr((void*)0xdeadbeefL);
237 zig_ptr((void *)0xdeadbeefL);
210238
211239 zig_bool(true);
212240
......@@ -249,14 +277,15 @@ void run_c_tests(void) {
249277 }
250278#endif
251279
252#if !defined __mips__ && !defined __riscv
280#if !defined __mips__ && !defined ZIG_PPC32
253281 {
254282 struct BigStruct s = {1, 2, 3, 4, 5};
255283 zig_big_struct(s);
256284 }
257285#endif
258286
259#if !defined __i386__ && !defined __arm__ && !defined __mips__ && !defined __riscv
287#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
288 !defined ZIG_PPC32 && !defined _ARCH_PPC64
260289 {
261290 struct SmallStructInts s = {1, 2, 3, 4};
262291 zig_small_struct_ints(s);
......@@ -281,28 +310,30 @@ void run_c_tests(void) {
281310 zig_small_packed_struct(s);
282311 }
283312
284#if !defined __i386__ && !defined __arm__ && !defined __mips__ && !defined __riscv
313#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
314 !defined ZIG_PPC32 && !defined _ARCH_PPC64
285315 {
286316 struct SplitStructInts s = {1234, 100, 1337};
287317 zig_split_struct_ints(s);
288318 }
289319#endif
290320
291#if !defined __arm__ && !defined __riscv
321#if !defined __arm__ && !defined ZIG_PPC32 && !defined _ARCH_PPC64
292322 {
293323 struct MedStructMixed s = {1234, 100.0f, 1337.0f};
294324 zig_med_struct_mixed(s);
295325 }
296326#endif
297327
298#if !defined __i386__ && !defined __arm__ && !defined __mips__ && !defined __riscv
328#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
329 !defined ZIG_PPC32 && !defined _ARCH_PPC64
299330 {
300331 struct SplitStructMixed s = {1234, 100, 1337.0f};
301332 zig_split_struct_mixed(s);
302333 }
303334#endif
304335
305#if !defined __mips__ && !defined __riscv
336#if !defined __mips__ && !defined ZIG_PPC32
306337 {
307338 struct BigStruct s = {30, 31, 32, 33, 34};
308339 struct BigStruct res = zig_big_struct_both(s);
......@@ -314,7 +345,7 @@ void run_c_tests(void) {
314345 }
315346#endif
316347
317#ifndef __riscv
348#if !defined ZIG_PPC32 && !defined _ARCH_PPC64
318349 {
319350 struct Rect r1 = {1, 21, 16, 4};
320351 struct Rect r2 = {178, 189, 21, 15};
......@@ -322,7 +353,7 @@ void run_c_tests(void) {
322353 }
323354#endif
324355
325#if !defined __mips__ && !defined __riscv
356#if !defined __mips__ && !defined ZIG_PPC32
326357 {
327358 struct FloatRect r1 = {1, 21, 16, 4};
328359 struct FloatRect r2 = {178, 189, 21, 15};
......@@ -335,9 +366,7 @@ void run_c_tests(void) {
335366
336367 assert_or_panic(zig_ret_u8() == 0xff);
337368 assert_or_panic(zig_ret_u16() == 0xffff);
338#ifndef __riscv
339369 assert_or_panic(zig_ret_u32() == 0xffffffff);
340#endif
341370 assert_or_panic(zig_ret_u64() == 0xffffffffffffffff);
342371
343372 assert_or_panic(zig_ret_i8() == -1);
......@@ -404,7 +433,7 @@ void c_long_double(long double x) {
404433}
405434
406435void c_ptr(void *x) {
407 assert_or_panic(x == (void*)0xdeadbeefL);
436 assert_or_panic(x == (void *)0xdeadbeefL);
408437}
409438
410439void c_bool(bool x) {
......@@ -672,7 +701,7 @@ void c_struct_with_array(StructWithArray x) {
672701}
673702
674703StructWithArray c_ret_struct_with_array() {
675 return (StructWithArray) { 4, {}, 155 };
704 return (StructWithArray){4, {}, 155};
676705}
677706
678707typedef struct {
......@@ -701,3 +730,43 @@ FloatArrayStruct c_ret_float_array_struct() {
701730 x.size.height = 4;
702731 return x;
703732}
733
734typedef uint32_t SmallVec __attribute__((vector_size(2 * sizeof(uint32_t))));
735
736void c_small_vec(SmallVec vec) {
737 assert_or_panic(vec[0] == 1);
738 assert_or_panic(vec[1] == 2);
739}
740
741SmallVec c_ret_small_vec(void) {
742 return (SmallVec){3, 4};
743}
744
745typedef size_t BigVec __attribute__((vector_size(8 * sizeof(size_t))));
746
747void c_big_vec(BigVec vec) {
748 assert_or_panic(vec[0] == 1);
749 assert_or_panic(vec[1] == 2);
750 assert_or_panic(vec[2] == 3);
751 assert_or_panic(vec[3] == 4);
752 assert_or_panic(vec[4] == 5);
753 assert_or_panic(vec[5] == 6);
754 assert_or_panic(vec[6] == 7);
755 assert_or_panic(vec[7] == 8);
756}
757
758BigVec c_ret_big_vec(void) {
759 return (BigVec){9, 10, 11, 12, 13, 14, 15, 16};
760}
761
762typedef struct {
763 float x, y;
764} Vector2;
765
766void c_ptr_size_float_struct(Vector2 vec) {
767 assert_or_panic(vec.x == 1);
768 assert_or_panic(vec.y == 2);
769}
770Vector2 c_ret_ptr_size_float_struct(void) {
771 return (Vector2){3, 4};
772}
test/c_abi/main.zig+104-44
......@@ -3,7 +3,7 @@ const builtin = @import("builtin");
33const print = std.debug.print;
44const expect = std.testing.expect;
55const has_i128 = builtin.cpu.arch != .i386 and !builtin.cpu.arch.isARM() and
6 !builtin.cpu.arch.isMIPS();
6 !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC();
77
88extern fn run_c_tests() void;
99
......@@ -112,6 +112,9 @@ test "C ABI floats" {
112112}
113113
114114test "C ABI long double" {
115 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
116 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
117
115118 c_long_double(12.34);
116119}
117120
......@@ -167,7 +170,8 @@ extern fn c_cmultd_comp(a_r: f64, a_i: f64, b_r: f64, b_i: f64) ComplexDouble;
167170extern fn c_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat;
168171extern fn c_cmultd(a: ComplexDouble, b: ComplexDouble) ComplexDouble;
169172
170const complex_abi_compatible = builtin.cpu.arch != .i386 and !builtin.cpu.arch.isMIPS();
173const complex_abi_compatible = builtin.cpu.arch != .i386 and !builtin.cpu.arch.isMIPS() and
174 !builtin.cpu.arch.isARM() and !builtin.cpu.arch.isPPC() and !builtin.cpu.arch.isRISCV();
171175
172176test "C ABI complex float" {
173177 if (!complex_abi_compatible) return error.SkipZigTest;
......@@ -177,8 +181,8 @@ test "C ABI complex float" {
177181 const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };
178182
179183 const z = c_cmultf(a, b);
180 expect(z.real == 1.5) catch @panic("test failure: zig_complex_float 1");
181 expect(z.imag == 13.5) catch @panic("test failure: zig_complex_float 2");
184 try expect(z.real == 1.5);
185 try expect(z.imag == 13.5);
182186}
183187
184188test "C ABI complex float by component" {
......@@ -188,8 +192,8 @@ test "C ABI complex float by component" {
188192 const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };
189193
190194 const z2 = c_cmultf_comp(a.real, a.imag, b.real, b.imag);
191 expect(z2.real == 1.5) catch @panic("test failure: zig_complex_float 3");
192 expect(z2.imag == 13.5) catch @panic("test failure: zig_complex_float 4");
195 try expect(z2.real == 1.5);
196 try expect(z2.imag == 13.5);
193197}
194198
195199test "C ABI complex double" {
......@@ -199,8 +203,8 @@ test "C ABI complex double" {
199203 const b = ComplexDouble{ .real = 11.3, .imag = -1.5 };
200204
201205 const z = c_cmultd(a, b);
202 expect(z.real == 1.5) catch @panic("test failure: zig_complex_double 1");
203 expect(z.imag == 13.5) catch @panic("test failure: zig_complex_double 2");
206 try expect(z.real == 1.5);
207 try expect(z.imag == 13.5);
204208}
205209
206210test "C ABI complex double by component" {
......@@ -210,8 +214,8 @@ test "C ABI complex double by component" {
210214 const b = ComplexDouble{ .real = 11.3, .imag = -1.5 };
211215
212216 const z = c_cmultd_comp(a.real, a.imag, b.real, b.imag);
213 expect(z.real == 1.5) catch @panic("test failure: zig_complex_double 3");
214 expect(z.imag == 13.5) catch @panic("test failure: zig_complex_double 4");
217 try expect(z.real == 1.5);
218 try expect(z.imag == 13.5);
215219}
216220
217221export fn zig_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat {
......@@ -261,7 +265,7 @@ extern fn c_big_struct(BigStruct) void;
261265
262266test "C ABI big struct" {
263267 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
264 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
268 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
265269
266270 var s = BigStruct{
267271 .a = 1,
......@@ -287,7 +291,7 @@ const BigUnion = extern union {
287291extern fn c_big_union(BigUnion) void;
288292
289293test "C ABI big union" {
290 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
294 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
291295
292296 var x = BigUnion{
293297 .a = BigStruct{
......@@ -320,9 +324,9 @@ extern fn c_ret_med_struct_mixed() MedStructMixed;
320324
321325test "C ABI medium struct of ints and floats" {
322326 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
323 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
324327 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
325 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
328 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
329 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
326330
327331 var s = MedStructMixed{
328332 .a = 1234,
......@@ -331,9 +335,9 @@ test "C ABI medium struct of ints and floats" {
331335 };
332336 c_med_struct_mixed(s);
333337 var s2 = c_ret_med_struct_mixed();
334 expect(s2.a == 1234) catch @panic("test failure");
335 expect(s2.b == 100.0) catch @panic("test failure");
336 expect(s2.c == 1337.0) catch @panic("test failure");
338 try expect(s2.a == 1234);
339 try expect(s2.b == 100.0);
340 try expect(s2.c == 1337.0);
337341}
338342
339343export fn zig_med_struct_mixed(x: MedStructMixed) void {
......@@ -353,9 +357,9 @@ extern fn c_ret_small_struct_ints() SmallStructInts;
353357
354358test "C ABI small struct of ints" {
355359 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
356 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
357360 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
358 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
361 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
362 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
359363
360364 var s = SmallStructInts{
361365 .a = 1,
......@@ -365,10 +369,10 @@ test "C ABI small struct of ints" {
365369 };
366370 c_small_struct_ints(s);
367371 var s2 = c_ret_small_struct_ints();
368 expect(s2.a == 1) catch @panic("test failure");
369 expect(s2.b == 2) catch @panic("test failure");
370 expect(s2.c == 3) catch @panic("test failure");
371 expect(s2.d == 4) catch @panic("test failure");
372 try expect(s2.a == 1);
373 try expect(s2.b == 2);
374 try expect(s2.c == 3);
375 try expect(s2.d == 4);
372376}
373377
374378export fn zig_small_struct_ints(x: SmallStructInts) void {
......@@ -435,9 +439,9 @@ extern fn c_split_struct_ints(SplitStructInt) void;
435439
436440test "C ABI split struct of ints" {
437441 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
438 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
439442 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
440 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
443 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
444 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
441445
442446 var s = SplitStructInt{
443447 .a = 1234,
......@@ -463,9 +467,9 @@ extern fn c_ret_split_struct_mixed() SplitStructMixed;
463467
464468test "C ABI split struct of ints and floats" {
465469 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
466 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
467470 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
468 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
471 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
472 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
469473
470474 var s = SplitStructMixed{
471475 .a = 1234,
......@@ -474,9 +478,9 @@ test "C ABI split struct of ints and floats" {
474478 };
475479 c_split_struct_mixed(s);
476480 var s2 = c_ret_split_struct_mixed();
477 expect(s2.a == 1234) catch @panic("test failure");
478 expect(s2.b == 100) catch @panic("test failure");
479 expect(s2.c == 1337.0) catch @panic("test failure");
481 try expect(s2.a == 1234);
482 try expect(s2.b == 100);
483 try expect(s2.c == 1337.0);
480484}
481485
482486export fn zig_split_struct_mixed(x: SplitStructMixed) void {
......@@ -492,7 +496,7 @@ extern fn c_multiple_struct_floats(FloatRect, FloatRect) void;
492496
493497test "C ABI sret and byval together" {
494498 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
495 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
499 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
496500
497501 var s = BigStruct{
498502 .a = 1,
......@@ -543,9 +547,9 @@ const Vector5 = extern struct {
543547extern fn c_big_struct_floats(Vector5) void;
544548
545549test "C ABI structs of floats as parameter" {
546 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
547550 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
548 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
551 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
552 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
549553
550554 var v3 = Vector3{
551555 .x = 3.0,
......@@ -584,7 +588,8 @@ export fn zig_multiple_struct_ints(x: Rect, y: Rect) void {
584588}
585589
586590test "C ABI structs of ints as multiple parameters" {
587 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
591 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
592 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
588593
589594 var r1 = Rect{
590595 .left = 1,
......@@ -621,7 +626,7 @@ export fn zig_multiple_struct_floats(x: FloatRect, y: FloatRect) void {
621626
622627test "C ABI structs of floats as multiple parameters" {
623628 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
624 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
629 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
625630
626631 var r1 = FloatRect{
627632 .left = 1,
......@@ -725,15 +730,15 @@ extern fn c_ret_struct_with_array() StructWithArray;
725730
726731test "Struct with array as padding." {
727732 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
728 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
729733 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
730 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
734 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
735 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
731736
732737 c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2 });
733738
734739 var x = c_ret_struct_with_array();
735 try std.testing.expect(x.a == 4);
736 try std.testing.expect(x.b == 155);
740 try expect(x.a == 4);
741 try expect(x.b == 155);
737742}
738743
739744const FloatArrayStruct = extern struct {
......@@ -752,7 +757,7 @@ extern fn c_ret_float_array_struct() FloatArrayStruct;
752757
753758test "Float array like struct" {
754759 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
755 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
760 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
756761
757762 c_float_array_struct(.{
758763 .origin = .{
......@@ -766,8 +771,63 @@ test "Float array like struct" {
766771 });
767772
768773 var x = c_ret_float_array_struct();
769 try std.testing.expect(x.origin.x == 1);
770 try std.testing.expect(x.origin.y == 2);
771 try std.testing.expect(x.size.width == 3);
772 try std.testing.expect(x.size.height == 4);
774 try expect(x.origin.x == 1);
775 try expect(x.origin.y == 2);
776 try expect(x.size.width == 3);
777 try expect(x.size.height == 4);
778}
779
780const SmallVec = @Vector(2, u32);
781
782extern fn c_small_vec(SmallVec) void;
783extern fn c_ret_small_vec() SmallVec;
784
785test "small simd vector" {
786 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
787 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
788
789 c_small_vec(.{ 1, 2 });
790
791 var x = c_ret_small_vec();
792 try expect(x[0] == 3);
793 try expect(x[1] == 4);
794}
795
796const BigVec = @Vector(8, usize);
797
798extern fn c_big_vec(BigVec) void;
799extern fn c_ret_big_vec() BigVec;
800
801test "big simd vector" {
802 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
803
804 c_big_vec(.{ 1, 2, 3, 4, 5, 6, 7, 8 });
805
806 var x = c_ret_big_vec();
807 try expect(x[0] == 9);
808 try expect(x[1] == 10);
809 try expect(x[2] == 11);
810 try expect(x[3] == 12);
811 try expect(x[4] == 13);
812 try expect(x[5] == 14);
813 try expect(x[6] == 15);
814 try expect(x[7] == 16);
815}
816
817const Vector2 = extern struct { x: f32, y: f32 };
818
819extern fn c_ptr_size_float_struct(Vector2) void;
820extern fn c_ret_ptr_size_float_struct() Vector2;
821
822test "C ABI pointer sized float struct" {
823 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
824 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
825 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
826 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
827
828 c_ptr_size_float_struct(.{ .x = 1, .y = 2 });
829
830 var x = c_ret_ptr_size_float_struct();
831 try expect(x.x == 3);
832 try expect(x.y == 4);
773833}
test/standalone.zig-17
......@@ -44,23 +44,6 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
4444 if (builtin.os.tag != .wasi) {
4545 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{});
4646 }
47 // C ABI compatibility issue: https://github.com/ziglang/zig/issues/1481
48 if (builtin.cpu.arch == .x86_64) {
49 if (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) {
50 cases.addBuildFile("test/c_abi/build.zig", .{});
51 }
52 }
53 if (builtin.cpu.arch.isAARCH64() and builtin.zig_backend == .stage2_llvm) {
54 cases.addBuildFile("test/c_abi/build.zig", .{});
55 }
56 if (builtin.cpu.arch == .i386 and builtin.zig_backend == .stage2_llvm) {
57 cases.addBuildFile("test/c_abi/build.zig", .{});
58 }
59 // C ABI tests only pass for the Wasm target when using stage2
60 cases.addBuildFile("test/c_abi/build_wasm.zig", .{
61 .requires_stage2 = true,
62 .use_emulation = true,
63 });
6447
6548 cases.addBuildFile("test/standalone/c_compiler/build.zig", .{
6649 .build_modes = true,
test/tests.zig+79
......@@ -1268,3 +1268,82 @@ fn printInvocation(args: []const []const u8) void {
12681268 }
12691269 std.debug.print("\n", .{});
12701270}
1271
1272const c_abi_targets = [_]CrossTarget{
1273 .{},
1274 .{
1275 .cpu_arch = .x86_64,
1276 .os_tag = .linux,
1277 .abi = .musl,
1278 },
1279 .{
1280 .cpu_arch = .i386,
1281 .os_tag = .linux,
1282 .abi = .musl,
1283 },
1284 .{
1285 .cpu_arch = .aarch64,
1286 .os_tag = .linux,
1287 .abi = .musl,
1288 },
1289 .{
1290 .cpu_arch = .arm,
1291 .os_tag = .linux,
1292 .abi = .musleabihf,
1293 },
1294 .{
1295 .cpu_arch = .mips,
1296 .os_tag = .linux,
1297 .abi = .musl,
1298 },
1299 .{
1300 .cpu_arch = .riscv64,
1301 .os_tag = .linux,
1302 .abi = .musl,
1303 },
1304 .{
1305 .cpu_arch = .wasm32,
1306 .os_tag = .wasi,
1307 .abi = .musl,
1308 },
1309 .{
1310 .cpu_arch = .powerpc,
1311 .os_tag = .linux,
1312 .abi = .musl,
1313 },
1314 .{
1315 .cpu_arch = .powerpc64le,
1316 .os_tag = .linux,
1317 .abi = .musl,
1318 },
1319};
1320
1321pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool) *build.Step {
1322 const step = b.step("test-c-abi", "Run the C ABI tests");
1323
1324 for (c_abi_targets) |c_abi_target| {
1325 if (skip_non_native and !c_abi_target.isNative())
1326 continue;
1327
1328 const test_step = b.addTest("test/c_abi/main.zig");
1329 test_step.setTarget(c_abi_target);
1330 if (c_abi_target.abi != null and c_abi_target.abi.?.isMusl()) {
1331 // TODO NativeTargetInfo insists on dynamically linking musl
1332 // for some reason?
1333 test_step.target_info.dynamic_linker.max_byte = null;
1334 }
1335 test_step.linkLibC();
1336 test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"});
1337
1338 const triple_prefix = c_abi_target.zigTriple(b.allocator) catch unreachable;
1339 test_step.setNamePrefix(b.fmt("{s}-{s} ", .{
1340 "test-c-abi",
1341 triple_prefix,
1342 }));
1343
1344 test_step.use_stage1 = false;
1345
1346 step.dependOn(&test_step.step);
1347 }
1348 return step;
1349}