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 {...@@ -508,6 +508,7 @@ pub fn build(b: *Builder) !void {
508 b.enable_wasmtime,508 b.enable_wasmtime,
509 b.enable_wine,509 b.enable_wine,
510 ));510 ));
511 test_step.dependOn(tests.addCAbiTests(b, skip_non_native));
511 test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests));512 test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests));
512 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));513 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
513 test_step.dependOn(tests.addCliTests(b, test_filter, modes));514 test_step.dependOn(tests.addCliTests(b, test_filter, modes));
src/arch/aarch64/abi.zig+38-24
...@@ -5,41 +5,54 @@ const Register = bits.Register;...@@ -5,41 +5,54 @@ const Register = bits.Register;
5const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;5const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
6const Type = @import("../../type.zig").Type;6const 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
10/// For `float_array` the second element will be the amount of floats.16/// For `float_array` the second element will be the amount of floats.
11pub fn classifyType(ty: Type, target: std.Target) [2]Class {17pub fn classifyType(ty: Type, target: std.Target) Class {
12 var maybe_float_bits: ?u16 = null;18 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime());
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}
1719
18fn classifyTypeInner(ty: Type, target: std.Target) [2]Class {20 var maybe_float_bits: ?u16 = null;
19 if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none };
20 switch (ty.zigTypeTag()) {21 switch (ty.zigTypeTag()) {
21 .Struct => {22 .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
23 const bit_size = ty.bitSize(target);27 const bit_size = ty.bitSize(target);
24 if (bit_size > 128) return .{ .memory, .none };28 if (bit_size > 128) return .memory;
25 if (bit_size > 64) return .{ .integer, .integer };29 if (bit_size > 64) return .double_integer;
26 return .{ .integer, .none };30 return .integer;
27 },31 },
28 .Union => {32 .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 => {
29 const bit_size = ty.bitSize(target);44 const bit_size = ty.bitSize(target);
30 if (bit_size > 128) return .{ .memory, .none };45 // TODO is this controlled by a cpu feature?
31 if (bit_size > 64) return .{ .integer, .integer };46 if (bit_size > 128) return .memory;
32 return .{ .integer, .none };47 return .byval;
33 },48 },
34 .Int, .Enum, .ErrorSet, .Vector, .Float, .Bool => return .{ .integer, .none },
35 .Array => return .{ .memory, .none },
36 .Optional => {49 .Optional => {
37 std.debug.assert(ty.isPtrLikeOptional());50 std.debug.assert(ty.isPtrLikeOptional());
38 return .{ .integer, .none };51 return .byval;
39 },52 },
40 .Pointer => {53 .Pointer => {
41 std.debug.assert(!ty.isSlice());54 std.debug.assert(!ty.isSlice());
42 return .{ .integer, .none };55 return .byval;
43 },56 },
44 .ErrorUnion,57 .ErrorUnion,
45 .Frame,58 .Frame,
...@@ -55,17 +68,18 @@ fn classifyTypeInner(ty: Type, target: std.Target) [2]Class {...@@ -55,17 +68,18 @@ fn classifyTypeInner(ty: Type, target: std.Target) [2]Class {
55 .Fn,68 .Fn,
56 .Opaque,69 .Opaque,
57 .EnumLiteral,70 .EnumLiteral,
71 .Array,
58 => unreachable,72 => unreachable,
59 }73 }
60}74}
6175
62const sret_float_count = 4;76const sret_float_count = 4;
63fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 {77fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u8 {
64 const invalid = std.math.maxInt(u32);78 const invalid = std.math.maxInt(u8);
65 switch (ty.zigTypeTag()) {79 switch (ty.zigTypeTag()) {
66 .Union => {80 .Union => {
67 const fields = ty.unionFields();81 const fields = ty.unionFields();
68 var max_count: u32 = 0;82 var max_count: u8 = 0;
69 for (fields.values()) |field| {83 for (fields.values()) |field| {
70 const field_count = countFloats(field.ty, target, maybe_float_bits);84 const field_count = countFloats(field.ty, target, maybe_float_bits);
71 if (field_count == invalid) return invalid;85 if (field_count == invalid) return invalid;
...@@ -76,7 +90,7 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 {...@@ -76,7 +90,7 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 {
76 },90 },
77 .Struct => {91 .Struct => {
78 const fields_len = ty.structFieldCount();92 const fields_len = ty.structFieldCount();
79 var count: u32 = 0;93 var count: u8 = 0;
80 var i: u32 = 0;94 var i: u32 = 0;
81 while (i < fields_len) : (i += 1) {95 while (i < fields_len) : (i += 1) {
82 const field_ty = ty.structFieldType(i);96 const field_ty = ty.structFieldType(i);
src/arch/arm/abi.zig+154
...@@ -2,6 +2,160 @@ const std = @import("std");...@@ -2,6 +2,160 @@ const std = @import("std");
2const bits = @import("bits.zig");2const bits = @import("bits.zig");
3const Register = bits.Register;3const Register = bits.Register;
4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;4const 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
6pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };160pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };
7pub const caller_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3 };161pub const caller_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3 };
src/arch/riscv64/abi.zig+69
...@@ -2,6 +2,75 @@ const std = @import("std");...@@ -2,6 +2,75 @@ const std = @import("std");
2const bits = @import("bits.zig");2const bits = @import("bits.zig");
3const Register = bits.Register;3const Register = bits.Register;
4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;4const 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
6pub const callee_preserved_regs = [_]Register{75pub const callee_preserved_regs = [_]Register{
7 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,76 .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 {...@@ -7149,7 +7149,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
71497149
7150 const classes: []const abi.Class = switch (self.target.os.tag) {7150 const classes: []const abi.Class = switch (self.target.os.tag) {
7151 .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)},7151 .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),
7153 };7153 };
7154 if (classes.len > 1) {7154 if (classes.len > 1) {
7155 return self.fail("TODO handle multiple classes per type", .{});7155 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 {...@@ -60,9 +60,11 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
60 }60 }
61}61}
6262
63pub const Context = enum { ret, arg };
64
63/// There are a maximum of 8 possible return slots. Returned values are in65/// There are a maximum of 8 possible return slots. Returned values are in
64/// the beginning of the array; unused slots are filled with .none.66/// 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 {
66 const memory_class = [_]Class{68 const memory_class = [_]Class{
67 .memory, .none, .none, .none,69 .memory, .none, .none, .none,
68 .none, .none, .none, .none,70 .none, .none, .none, .none,
...@@ -134,6 +136,22 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {...@@ -134,6 +136,22 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
134 },136 },
135 .Vector => {137 .Vector => {
136 const elem_ty = ty.childType();138 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 }
137 const bits = elem_ty.bitSize(target) * ty.arrayLen();155 const bits = elem_ty.bitSize(target) * ty.arrayLen();
138 if (bits <= 64) return .{156 if (bits <= 64) return .{
139 .sse, .none, .none, .none,157 .sse, .none, .none, .none,
...@@ -201,7 +219,7 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {...@@ -201,7 +219,7 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
201 }219 }
202 }220 }
203 const field_size = field.ty.abiSize(target);221 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);
205 const field_class = std.mem.sliceTo(&field_class_array, .none);223 const field_class = std.mem.sliceTo(&field_class_array, .none);
206 if (byte_i + field_size <= 8) {224 if (byte_i + field_size <= 8) {
207 // Combine this field with the previous one.225 // Combine this field with the previous one.
...@@ -315,7 +333,7 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {...@@ -315,7 +333,7 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
315 }333 }
316 }334 }
317 // Combine this field with the previous one.335 // Combine this field with the previous one.
318 const field_class = classifySystemV(field.ty, target);336 const field_class = classifySystemV(field.ty, target, .arg);
319 for (result) |*result_item, i| {337 for (result) |*result_item, i| {
320 const field_item = field_class[i];338 const field_item = field_class[i];
321 // "If both classes are equal, this is the resulting class."339 // "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;...@@ -24,6 +24,8 @@ const CType = @import("../type.zig").CType;
24const x86_64_abi = @import("../arch/x86_64/abi.zig");24const x86_64_abi = @import("../arch/x86_64/abi.zig");
25const wasm_c_abi = @import("../arch/wasm/abi.zig");25const wasm_c_abi = @import("../arch/wasm/abi.zig");
26const aarch64_c_abi = @import("../arch/aarch64/abi.zig");26const 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
28const Error = error{ OutOfMemory, CodegenFail };30const Error = error{ OutOfMemory, CodegenFail };
2931
...@@ -1130,6 +1132,25 @@ pub const Object = struct {...@@ -1130,6 +1132,25 @@ pub const Object = struct {
1130 const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");1132 const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
1131 _ = builder.buildStore(param, casted_ptr);1133 _ = 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
1133 if (isByRef(param_ty)) {1154 if (isByRef(param_ty)) {
1134 try args.append(arg_ptr);1155 try args.append(arg_ptr);
1135 } else {1156 } else {
...@@ -2578,6 +2599,8 @@ pub const DeclGen = struct {...@@ -2578,6 +2599,8 @@ pub const DeclGen = struct {
2578 .multiple_llvm_float,2599 .multiple_llvm_float,
2579 .as_u16,2600 .as_u16,
2580 .float_array,2601 .float_array,
2602 .i32_array,
2603 .i64_array,
2581 => continue,2604 => continue,
25822605
2583 .slice => unreachable, // extern functions do not support slice types.2606 .slice => unreachable, // extern functions do not support slice types.
...@@ -3132,6 +3155,11 @@ pub const DeclGen = struct {...@@ -3132,6 +3155,11 @@ pub const DeclGen = struct {
3132 const arr_ty = float_ty.arrayType(field_count);3155 const arr_ty = float_ty.arrayType(field_count);
3133 try llvm_params.append(arr_ty);3156 try llvm_params.append(arr_ty);
3134 },3157 },
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 },
3135 };3163 };
31363164
3137 return llvm.functionType(3165 return llvm.functionType(
...@@ -4822,6 +4850,25 @@ pub const FuncGen = struct {...@@ -4822,6 +4850,25 @@ pub const FuncGen = struct {
4822 load_inst.setAlignment(alignment);4850 load_inst.setAlignment(alignment);
4823 try llvm_args.append(load_inst);4851 try llvm_args.append(load_inst);
4824 },4852 },
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 },
4825 };4872 };
48264873
4827 const call = self.builder.buildCall(4874 const call = self.builder.buildCall(
...@@ -10083,10 +10130,16 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool...@@ -10083,10 +10130,16 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
10083 .mips, .mipsel => return false,10130 .mips, .mipsel => return false,
10084 .x86_64 => switch (target.os.tag) {10131 .x86_64 => switch (target.os.tag) {
10085 .windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory,10132 .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,
10087 },10134 },
10088 .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,10135 .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,
10090 else => return false, // TODO investigate C ABI for other architectures10143 else => return false, // TODO investigate C ABI for other architectures
10091 },10144 },
10092 else => return false,10145 else => return false,
...@@ -10139,7 +10192,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {...@@ -10139,7 +10192,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
10139 if (is_scalar) {10192 if (is_scalar) {
10140 return dg.lowerType(fn_info.return_type);10193 return dg.lowerType(fn_info.return_type);
10141 }10194 }
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);
10143 if (classes[0] == .memory) {10196 if (classes[0] == .memory) {
10144 return dg.context.voidType();10197 return dg.context.voidType();
10145 }10198 }
...@@ -10197,22 +10250,44 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {...@@ -10197,22 +10250,44 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
10197 return dg.context.intType(@intCast(c_uint, abi_size * 8));10250 return dg.context.intType(@intCast(c_uint, abi_size * 8));
10198 },10251 },
10199 .aarch64, .aarch64_be => {10252 .aarch64, .aarch64_be => {
10200 if (is_scalar) {10253 switch (aarch64_c_abi.classifyType(fn_info.return_type, target)) {
10201 return dg.lowerType(fn_info.return_type);10254 .memory => return dg.context.voidType(),
10202 }10255 .float_array => return dg.lowerType(fn_info.return_type),
10203 const classes = aarch64_c_abi.classifyType(fn_info.return_type, target);10256 .byval => return dg.lowerType(fn_info.return_type),
10204 if (classes[0] == .memory or classes[0] == .none) {10257 .integer => {
10205 return dg.context.voidType();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),
10206 }10262 }
10207 if (classes[0] == .float_array) {10263 },
10208 return dg.lowerType(fn_info.return_type);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),
10209 }10273 }
10210 if (classes[1] == .none) {10274 },
10211 const bit_size = fn_info.return_type.bitSize(target);10275 .riscv32, .riscv64 => {
10212 return dg.context.intType(@intCast(c_uint, bit_size));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),
10213 }10290 }
10214
10215 return dg.context.intType(64).arrayType(2);
10216 },10291 },
10217 // TODO investigate C ABI for other architectures10292 // TODO investigate C ABI for other architectures
10218 else => return dg.lowerType(fn_info.return_type),10293 else => return dg.lowerType(fn_info.return_type),
...@@ -10242,6 +10317,8 @@ const ParamTypeIterator = struct {...@@ -10242,6 +10317,8 @@ const ParamTypeIterator = struct {
10242 slice,10317 slice,
10243 as_u16,10318 as_u16,
10244 float_array: u8,10319 float_array: u8,
10320 i32_array: u8,
10321 i64_array: u8,
10245 };10322 };
1024610323
10247 pub fn next(it: *ParamTypeIterator) ?Lowering {10324 pub fn next(it: *ParamTypeIterator) ?Lowering {
...@@ -10288,15 +10365,6 @@ const ParamTypeIterator = struct {...@@ -10288,15 +10365,6 @@ const ParamTypeIterator = struct {
10288 .C => {10365 .C => {
10289 const is_scalar = isScalar(ty);10366 const is_scalar = isScalar(ty);
10290 switch (it.target.cpu.arch) {10367 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 },
10300 .mips, .mipsel => {10368 .mips, .mipsel => {
10301 it.zig_index += 1;10369 it.zig_index += 1;
10302 it.llvm_index += 1;10370 it.llvm_index += 1;
...@@ -10334,18 +10402,18 @@ const ParamTypeIterator = struct {...@@ -10334,18 +10402,18 @@ const ParamTypeIterator = struct {
10334 else => unreachable,10402 else => unreachable,
10335 },10403 },
10336 else => {10404 else => {
10337 if (is_scalar) {10405 const classes = x86_64_abi.classifySystemV(ty, it.target, .arg);
10338 it.zig_index += 1;
10339 it.llvm_index += 1;
10340 return .byval;
10341 }
10342 const classes = x86_64_abi.classifySystemV(ty, it.target);
10343 if (classes[0] == .memory) {10406 if (classes[0] == .memory) {
10344 it.zig_index += 1;10407 it.zig_index += 1;
10345 it.llvm_index += 1;10408 it.llvm_index += 1;
10346 it.byval_attr = true;10409 it.byval_attr = true;
10347 return .byref;10410 return .byref;
10348 }10411 }
10412 if (is_scalar) {
10413 it.zig_index += 1;
10414 it.llvm_index += 1;
10415 return .byval;
10416 }
10349 var llvm_types_buffer: [8]u16 = undefined;10417 var llvm_types_buffer: [8]u16 = undefined;
10350 var llvm_types_index: u32 = 0;10418 var llvm_types_index: u32 = 0;
10351 for (classes) |class| {10419 for (classes) |class| {
...@@ -10383,11 +10451,6 @@ const ParamTypeIterator = struct {...@@ -10383,11 +10451,6 @@ const ParamTypeIterator = struct {
10383 it.llvm_index += 1;10451 it.llvm_index += 1;
10384 return .abi_sized_int;10452 return .abi_sized_int;
10385 }10453 }
10386 if (classes[0] == .sse and classes[1] == .none) {
10387 it.zig_index += 1;
10388 it.llvm_index += 1;
10389 return .byval;
10390 }
10391 it.llvm_types_buffer = llvm_types_buffer;10454 it.llvm_types_buffer = llvm_types_buffer;
10392 it.llvm_types_len = llvm_types_index;10455 it.llvm_types_len = llvm_types_index;
10393 it.llvm_index += llvm_types_index;10456 it.llvm_index += llvm_types_index;
...@@ -10410,24 +10473,45 @@ const ParamTypeIterator = struct {...@@ -10410,24 +10473,45 @@ const ParamTypeIterator = struct {
10410 .aarch64, .aarch64_be => {10473 .aarch64, .aarch64_be => {
10411 it.zig_index += 1;10474 it.zig_index += 1;
10412 it.llvm_index += 1;10475 it.llvm_index += 1;
10413 if (is_scalar) {10476 switch (aarch64_c_abi.classifyType(ty, it.target)) {
10414 return .byval;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 },
10415 }10486 }
10416 const classes = aarch64_c_abi.classifyType(ty, it.target);10487 },
10417 if (classes[0] == .memory) {10488 .arm, .armeb => {
10418 return .byref;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 },
10419 }10499 }
10420 if (classes[0] == .float_array) {10500 },
10421 return Lowering{ .float_array = @enumToInt(classes[1]) };10501 .riscv32, .riscv64 => {
10502 it.zig_index += 1;
10503 it.llvm_index += 1;
10504 if (ty.tag() == .f16) {
10505 return .as_u16;
10422 }10506 }
10423 if (classes[1] == .none) {10507 switch (riscv_c_abi.classifyType(ty, it.target)) {
10424 it.llvm_types_len = 1;10508 .memory => {
10425 } else {10509 return .byref;
10426 it.llvm_types_len = 2;10510 },
10511 .byval => return .byval,
10512 .integer => return .abi_sized_int,
10513 .double_integer => return Lowering{ .i64_array = 2 },
10427 }10514 }
10428 it.llvm_types_buffer[0] = 64;
10429 it.llvm_types_buffer[1] = 64;
10430 return .multiple_llvm_ints;
10431 },10515 },
10432 // TODO investigate C ABI for other architectures10516 // TODO investigate C ABI for other architectures
10433 else => {10517 else => {
...@@ -10475,8 +10559,16 @@ fn ccAbiPromoteInt(...@@ -10475,8 +10559,16 @@ fn ccAbiPromoteInt(
10475 };10559 };
10476 if (int_info.bits <= 16) return int_info.signedness;10560 if (int_info.bits <= 16) return int_info.signedness;
10477 switch (target.cpu.arch) {10561 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 },
10478 .sparc64,10571 .sparc64,
10479 .riscv64,
10480 .powerpc64,10572 .powerpc64,
10481 .powerpc64le,10573 .powerpc64le,
10482 => {10574 => {
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,8 +1,8 @@
1#include <complex.h>
1#include <inttypes.h>2#include <inttypes.h>
2#include <stdlib.h>
3#include <stdbool.h>3#include <stdbool.h>
4#include <stdlib.h>
4#include <string.h>5#include <string.h>
5#include <complex.h>
66
7void zig_panic();7void zig_panic();
88
...@@ -12,6 +12,14 @@ static void assert_or_panic(bool ok) {...@@ -12,6 +12,14 @@ static void assert_or_panic(bool ok) {
12 }12 }
13}13}
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
15#ifdef __i386__23#ifdef __i386__
16# define ZIG_NO_I12824# define ZIG_NO_I128
17#endif25#endif
...@@ -24,6 +32,14 @@ static void assert_or_panic(bool ok) {...@@ -24,6 +32,14 @@ static void assert_or_panic(bool ok) {
24# define ZIG_NO_I12832# define ZIG_NO_I128
25#endif33#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
27#ifdef __i386__43#ifdef __i386__
28# define ZIG_NO_COMPLEX44# define ZIG_NO_COMPLEX
29#endif45#endif
...@@ -32,6 +48,18 @@ static void assert_or_panic(bool ok) {...@@ -32,6 +48,18 @@ static void assert_or_panic(bool ok) {
32# define ZIG_NO_COMPLEX48# define ZIG_NO_COMPLEX
33#endif49#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
35#ifndef ZIG_NO_I12863#ifndef ZIG_NO_I128
36struct i128 {64struct i128 {
37 __int128 value;65 __int128 value;
...@@ -206,7 +234,7 @@ void run_c_tests(void) {...@@ -206,7 +234,7 @@ void run_c_tests(void) {
206 zig_longdouble(12.34l);234 zig_longdouble(12.34l);
207 zig_five_floats(1.0f, 2.0f, 3.0f, 4.0f, 5.0f);235 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
211 zig_bool(true);239 zig_bool(true);
212240
...@@ -249,14 +277,15 @@ void run_c_tests(void) {...@@ -249,14 +277,15 @@ void run_c_tests(void) {
249 }277 }
250#endif278#endif
251279
252#if !defined __mips__ && !defined __riscv280#if !defined __mips__ && !defined ZIG_PPC32
253 {281 {
254 struct BigStruct s = {1, 2, 3, 4, 5};282 struct BigStruct s = {1, 2, 3, 4, 5};
255 zig_big_struct(s);283 zig_big_struct(s);
256 }284 }
257#endif285#endif
258286
259#if !defined __i386__ && !defined __arm__ && !defined __mips__ && !defined __riscv287#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
288 !defined ZIG_PPC32 && !defined _ARCH_PPC64
260 {289 {
261 struct SmallStructInts s = {1, 2, 3, 4};290 struct SmallStructInts s = {1, 2, 3, 4};
262 zig_small_struct_ints(s);291 zig_small_struct_ints(s);
...@@ -281,28 +310,30 @@ void run_c_tests(void) {...@@ -281,28 +310,30 @@ void run_c_tests(void) {
281 zig_small_packed_struct(s);310 zig_small_packed_struct(s);
282 }311 }
283312
284#if !defined __i386__ && !defined __arm__ && !defined __mips__ && !defined __riscv313#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
314 !defined ZIG_PPC32 && !defined _ARCH_PPC64
285 {315 {
286 struct SplitStructInts s = {1234, 100, 1337};316 struct SplitStructInts s = {1234, 100, 1337};
287 zig_split_struct_ints(s);317 zig_split_struct_ints(s);
288 }318 }
289#endif319#endif
290320
291#if !defined __arm__ && !defined __riscv321#if !defined __arm__ && !defined ZIG_PPC32 && !defined _ARCH_PPC64
292 {322 {
293 struct MedStructMixed s = {1234, 100.0f, 1337.0f};323 struct MedStructMixed s = {1234, 100.0f, 1337.0f};
294 zig_med_struct_mixed(s);324 zig_med_struct_mixed(s);
295 }325 }
296#endif326#endif
297327
298#if !defined __i386__ && !defined __arm__ && !defined __mips__ && !defined __riscv328#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
329 !defined ZIG_PPC32 && !defined _ARCH_PPC64
299 {330 {
300 struct SplitStructMixed s = {1234, 100, 1337.0f};331 struct SplitStructMixed s = {1234, 100, 1337.0f};
301 zig_split_struct_mixed(s);332 zig_split_struct_mixed(s);
302 }333 }
303#endif334#endif
304335
305#if !defined __mips__ && !defined __riscv336#if !defined __mips__ && !defined ZIG_PPC32
306 {337 {
307 struct BigStruct s = {30, 31, 32, 33, 34};338 struct BigStruct s = {30, 31, 32, 33, 34};
308 struct BigStruct res = zig_big_struct_both(s);339 struct BigStruct res = zig_big_struct_both(s);
...@@ -314,7 +345,7 @@ void run_c_tests(void) {...@@ -314,7 +345,7 @@ void run_c_tests(void) {
314 }345 }
315#endif346#endif
316347
317#ifndef __riscv348#if !defined ZIG_PPC32 && !defined _ARCH_PPC64
318 {349 {
319 struct Rect r1 = {1, 21, 16, 4};350 struct Rect r1 = {1, 21, 16, 4};
320 struct Rect r2 = {178, 189, 21, 15};351 struct Rect r2 = {178, 189, 21, 15};
...@@ -322,7 +353,7 @@ void run_c_tests(void) {...@@ -322,7 +353,7 @@ void run_c_tests(void) {
322 }353 }
323#endif354#endif
324355
325#if !defined __mips__ && !defined __riscv356#if !defined __mips__ && !defined ZIG_PPC32
326 {357 {
327 struct FloatRect r1 = {1, 21, 16, 4};358 struct FloatRect r1 = {1, 21, 16, 4};
328 struct FloatRect r2 = {178, 189, 21, 15};359 struct FloatRect r2 = {178, 189, 21, 15};
...@@ -335,9 +366,7 @@ void run_c_tests(void) {...@@ -335,9 +366,7 @@ void run_c_tests(void) {
335366
336 assert_or_panic(zig_ret_u8() == 0xff);367 assert_or_panic(zig_ret_u8() == 0xff);
337 assert_or_panic(zig_ret_u16() == 0xffff);368 assert_or_panic(zig_ret_u16() == 0xffff);
338#ifndef __riscv
339 assert_or_panic(zig_ret_u32() == 0xffffffff);369 assert_or_panic(zig_ret_u32() == 0xffffffff);
340#endif
341 assert_or_panic(zig_ret_u64() == 0xffffffffffffffff);370 assert_or_panic(zig_ret_u64() == 0xffffffffffffffff);
342371
343 assert_or_panic(zig_ret_i8() == -1);372 assert_or_panic(zig_ret_i8() == -1);
...@@ -404,7 +433,7 @@ void c_long_double(long double x) {...@@ -404,7 +433,7 @@ void c_long_double(long double x) {
404}433}
405434
406void c_ptr(void *x) {435void c_ptr(void *x) {
407 assert_or_panic(x == (void*)0xdeadbeefL);436 assert_or_panic(x == (void *)0xdeadbeefL);
408}437}
409438
410void c_bool(bool x) {439void c_bool(bool x) {
...@@ -672,7 +701,7 @@ void c_struct_with_array(StructWithArray x) {...@@ -672,7 +701,7 @@ void c_struct_with_array(StructWithArray x) {
672}701}
673702
674StructWithArray c_ret_struct_with_array() {703StructWithArray c_ret_struct_with_array() {
675 return (StructWithArray) { 4, {}, 155 };704 return (StructWithArray){4, {}, 155};
676}705}
677706
678typedef struct {707typedef struct {
...@@ -701,3 +730,43 @@ FloatArrayStruct c_ret_float_array_struct() {...@@ -701,3 +730,43 @@ FloatArrayStruct c_ret_float_array_struct() {
701 x.size.height = 4;730 x.size.height = 4;
702 return x;731 return x;
703}732}
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");...@@ -3,7 +3,7 @@ const builtin = @import("builtin");
3const print = std.debug.print;3const print = std.debug.print;
4const expect = std.testing.expect;4const expect = std.testing.expect;
5const has_i128 = builtin.cpu.arch != .i386 and !builtin.cpu.arch.isARM() and5const 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
8extern fn run_c_tests() void;8extern fn run_c_tests() void;
99
...@@ -112,6 +112,9 @@ test "C ABI floats" {...@@ -112,6 +112,9 @@ test "C ABI floats" {
112}112}
113113
114test "C ABI long double" {114test "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
115 c_long_double(12.34);118 c_long_double(12.34);
116}119}
117120
...@@ -167,7 +170,8 @@ extern fn c_cmultd_comp(a_r: f64, a_i: f64, b_r: f64, b_i: f64) ComplexDouble;...@@ -167,7 +170,8 @@ extern fn c_cmultd_comp(a_r: f64, a_i: f64, b_r: f64, b_i: f64) ComplexDouble;
167extern fn c_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat;170extern fn c_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat;
168extern fn c_cmultd(a: ComplexDouble, b: ComplexDouble) ComplexDouble;171extern 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
172test "C ABI complex float" {176test "C ABI complex float" {
173 if (!complex_abi_compatible) return error.SkipZigTest;177 if (!complex_abi_compatible) return error.SkipZigTest;
...@@ -177,8 +181,8 @@ test "C ABI complex float" {...@@ -177,8 +181,8 @@ test "C ABI complex float" {
177 const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };181 const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };
178182
179 const z = c_cmultf(a, b);183 const z = c_cmultf(a, b);
180 expect(z.real == 1.5) catch @panic("test failure: zig_complex_float 1");184 try expect(z.real == 1.5);
181 expect(z.imag == 13.5) catch @panic("test failure: zig_complex_float 2");185 try expect(z.imag == 13.5);
182}186}
183187
184test "C ABI complex float by component" {188test "C ABI complex float by component" {
...@@ -188,8 +192,8 @@ test "C ABI complex float by component" {...@@ -188,8 +192,8 @@ test "C ABI complex float by component" {
188 const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };192 const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };
189193
190 const z2 = c_cmultf_comp(a.real, a.imag, b.real, b.imag);194 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");195 try expect(z2.real == 1.5);
192 expect(z2.imag == 13.5) catch @panic("test failure: zig_complex_float 4");196 try expect(z2.imag == 13.5);
193}197}
194198
195test "C ABI complex double" {199test "C ABI complex double" {
...@@ -199,8 +203,8 @@ test "C ABI complex double" {...@@ -199,8 +203,8 @@ test "C ABI complex double" {
199 const b = ComplexDouble{ .real = 11.3, .imag = -1.5 };203 const b = ComplexDouble{ .real = 11.3, .imag = -1.5 };
200204
201 const z = c_cmultd(a, b);205 const z = c_cmultd(a, b);
202 expect(z.real == 1.5) catch @panic("test failure: zig_complex_double 1");206 try expect(z.real == 1.5);
203 expect(z.imag == 13.5) catch @panic("test failure: zig_complex_double 2");207 try expect(z.imag == 13.5);
204}208}
205209
206test "C ABI complex double by component" {210test "C ABI complex double by component" {
...@@ -210,8 +214,8 @@ test "C ABI complex double by component" {...@@ -210,8 +214,8 @@ test "C ABI complex double by component" {
210 const b = ComplexDouble{ .real = 11.3, .imag = -1.5 };214 const b = ComplexDouble{ .real = 11.3, .imag = -1.5 };
211215
212 const z = c_cmultd_comp(a.real, a.imag, b.real, b.imag);216 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");217 try expect(z.real == 1.5);
214 expect(z.imag == 13.5) catch @panic("test failure: zig_complex_double 4");218 try expect(z.imag == 13.5);
215}219}
216220
217export fn zig_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat {221export fn zig_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat {
...@@ -261,7 +265,7 @@ extern fn c_big_struct(BigStruct) void;...@@ -261,7 +265,7 @@ extern fn c_big_struct(BigStruct) void;
261265
262test "C ABI big struct" {266test "C ABI big struct" {
263 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;267 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
266 var s = BigStruct{270 var s = BigStruct{
267 .a = 1,271 .a = 1,
...@@ -287,7 +291,7 @@ const BigUnion = extern union {...@@ -287,7 +291,7 @@ const BigUnion = extern union {
287extern fn c_big_union(BigUnion) void;291extern fn c_big_union(BigUnion) void;
288292
289test "C ABI big union" {293test "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
292 var x = BigUnion{296 var x = BigUnion{
293 .a = BigStruct{297 .a = BigStruct{
...@@ -320,9 +324,9 @@ extern fn c_ret_med_struct_mixed() MedStructMixed;...@@ -320,9 +324,9 @@ extern fn c_ret_med_struct_mixed() MedStructMixed;
320324
321test "C ABI medium struct of ints and floats" {325test "C ABI medium struct of ints and floats" {
322 if (builtin.cpu.arch == .i386) return error.SkipZigTest;326 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
323 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
324 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;327 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
327 var s = MedStructMixed{331 var s = MedStructMixed{
328 .a = 1234,332 .a = 1234,
...@@ -331,9 +335,9 @@ test "C ABI medium struct of ints and floats" {...@@ -331,9 +335,9 @@ test "C ABI medium struct of ints and floats" {
331 };335 };
332 c_med_struct_mixed(s);336 c_med_struct_mixed(s);
333 var s2 = c_ret_med_struct_mixed();337 var s2 = c_ret_med_struct_mixed();
334 expect(s2.a == 1234) catch @panic("test failure");338 try expect(s2.a == 1234);
335 expect(s2.b == 100.0) catch @panic("test failure");339 try expect(s2.b == 100.0);
336 expect(s2.c == 1337.0) catch @panic("test failure");340 try expect(s2.c == 1337.0);
337}341}
338342
339export fn zig_med_struct_mixed(x: MedStructMixed) void {343export fn zig_med_struct_mixed(x: MedStructMixed) void {
...@@ -353,9 +357,9 @@ extern fn c_ret_small_struct_ints() SmallStructInts;...@@ -353,9 +357,9 @@ extern fn c_ret_small_struct_ints() SmallStructInts;
353357
354test "C ABI small struct of ints" {358test "C ABI small struct of ints" {
355 if (builtin.cpu.arch == .i386) return error.SkipZigTest;359 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
356 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
357 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;360 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
360 var s = SmallStructInts{364 var s = SmallStructInts{
361 .a = 1,365 .a = 1,
...@@ -365,10 +369,10 @@ test "C ABI small struct of ints" {...@@ -365,10 +369,10 @@ test "C ABI small struct of ints" {
365 };369 };
366 c_small_struct_ints(s);370 c_small_struct_ints(s);
367 var s2 = c_ret_small_struct_ints();371 var s2 = c_ret_small_struct_ints();
368 expect(s2.a == 1) catch @panic("test failure");372 try expect(s2.a == 1);
369 expect(s2.b == 2) catch @panic("test failure");373 try expect(s2.b == 2);
370 expect(s2.c == 3) catch @panic("test failure");374 try expect(s2.c == 3);
371 expect(s2.d == 4) catch @panic("test failure");375 try expect(s2.d == 4);
372}376}
373377
374export fn zig_small_struct_ints(x: SmallStructInts) void {378export fn zig_small_struct_ints(x: SmallStructInts) void {
...@@ -435,9 +439,9 @@ extern fn c_split_struct_ints(SplitStructInt) void;...@@ -435,9 +439,9 @@ extern fn c_split_struct_ints(SplitStructInt) void;
435439
436test "C ABI split struct of ints" {440test "C ABI split struct of ints" {
437 if (builtin.cpu.arch == .i386) return error.SkipZigTest;441 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
438 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
439 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;442 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
442 var s = SplitStructInt{446 var s = SplitStructInt{
443 .a = 1234,447 .a = 1234,
...@@ -463,9 +467,9 @@ extern fn c_ret_split_struct_mixed() SplitStructMixed;...@@ -463,9 +467,9 @@ extern fn c_ret_split_struct_mixed() SplitStructMixed;
463467
464test "C ABI split struct of ints and floats" {468test "C ABI split struct of ints and floats" {
465 if (builtin.cpu.arch == .i386) return error.SkipZigTest;469 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
466 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
467 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;470 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
470 var s = SplitStructMixed{474 var s = SplitStructMixed{
471 .a = 1234,475 .a = 1234,
...@@ -474,9 +478,9 @@ test "C ABI split struct of ints and floats" {...@@ -474,9 +478,9 @@ test "C ABI split struct of ints and floats" {
474 };478 };
475 c_split_struct_mixed(s);479 c_split_struct_mixed(s);
476 var s2 = c_ret_split_struct_mixed();480 var s2 = c_ret_split_struct_mixed();
477 expect(s2.a == 1234) catch @panic("test failure");481 try expect(s2.a == 1234);
478 expect(s2.b == 100) catch @panic("test failure");482 try expect(s2.b == 100);
479 expect(s2.c == 1337.0) catch @panic("test failure");483 try expect(s2.c == 1337.0);
480}484}
481485
482export fn zig_split_struct_mixed(x: SplitStructMixed) void {486export fn zig_split_struct_mixed(x: SplitStructMixed) void {
...@@ -492,7 +496,7 @@ extern fn c_multiple_struct_floats(FloatRect, FloatRect) void;...@@ -492,7 +496,7 @@ extern fn c_multiple_struct_floats(FloatRect, FloatRect) void;
492496
493test "C ABI sret and byval together" {497test "C ABI sret and byval together" {
494 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;498 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
497 var s = BigStruct{501 var s = BigStruct{
498 .a = 1,502 .a = 1,
...@@ -543,9 +547,9 @@ const Vector5 = extern struct {...@@ -543,9 +547,9 @@ const Vector5 = extern struct {
543extern fn c_big_struct_floats(Vector5) void;547extern fn c_big_struct_floats(Vector5) void;
544548
545test "C ABI structs of floats as parameter" {549test "C ABI structs of floats as parameter" {
546 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
547 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;550 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
550 var v3 = Vector3{554 var v3 = Vector3{
551 .x = 3.0,555 .x = 3.0,
...@@ -584,7 +588,8 @@ export fn zig_multiple_struct_ints(x: Rect, y: Rect) void {...@@ -584,7 +588,8 @@ export fn zig_multiple_struct_ints(x: Rect, y: Rect) void {
584}588}
585589
586test "C ABI structs of ints as multiple parameters" {590test "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
589 var r1 = Rect{594 var r1 = Rect{
590 .left = 1,595 .left = 1,
...@@ -621,7 +626,7 @@ export fn zig_multiple_struct_floats(x: FloatRect, y: FloatRect) void {...@@ -621,7 +626,7 @@ export fn zig_multiple_struct_floats(x: FloatRect, y: FloatRect) void {
621626
622test "C ABI structs of floats as multiple parameters" {627test "C ABI structs of floats as multiple parameters" {
623 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;628 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
626 var r1 = FloatRect{631 var r1 = FloatRect{
627 .left = 1,632 .left = 1,
...@@ -725,15 +730,15 @@ extern fn c_ret_struct_with_array() StructWithArray;...@@ -725,15 +730,15 @@ extern fn c_ret_struct_with_array() StructWithArray;
725730
726test "Struct with array as padding." {731test "Struct with array as padding." {
727 if (builtin.cpu.arch == .i386) return error.SkipZigTest;732 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
728 if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest;
729 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;733 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
732 c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2 });737 c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2 });
733738
734 var x = c_ret_struct_with_array();739 var x = c_ret_struct_with_array();
735 try std.testing.expect(x.a == 4);740 try expect(x.a == 4);
736 try std.testing.expect(x.b == 155);741 try expect(x.b == 155);
737}742}
738743
739const FloatArrayStruct = extern struct {744const FloatArrayStruct = extern struct {
...@@ -752,7 +757,7 @@ extern fn c_ret_float_array_struct() FloatArrayStruct;...@@ -752,7 +757,7 @@ extern fn c_ret_float_array_struct() FloatArrayStruct;
752757
753test "Float array like struct" {758test "Float array like struct" {
754 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;759 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
757 c_float_array_struct(.{762 c_float_array_struct(.{
758 .origin = .{763 .origin = .{
...@@ -766,8 +771,63 @@ test "Float array like struct" {...@@ -766,8 +771,63 @@ test "Float array like struct" {
766 });771 });
767772
768 var x = c_ret_float_array_struct();773 var x = c_ret_float_array_struct();
769 try std.testing.expect(x.origin.x == 1);774 try expect(x.origin.x == 1);
770 try std.testing.expect(x.origin.y == 2);775 try expect(x.origin.y == 2);
771 try std.testing.expect(x.size.width == 3);776 try expect(x.size.width == 3);
772 try std.testing.expect(x.size.height == 4);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);
773}833}
test/standalone.zig-17
...@@ -44,23 +44,6 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -44,23 +44,6 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
44 if (builtin.os.tag != .wasi) {44 if (builtin.os.tag != .wasi) {
45 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{});45 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{});
46 }46 }
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
65 cases.addBuildFile("test/standalone/c_compiler/build.zig", .{48 cases.addBuildFile("test/standalone/c_compiler/build.zig", .{
66 .build_modes = true,49 .build_modes = true,
test/tests.zig+79
...@@ -1268,3 +1268,82 @@ fn printInvocation(args: []const []const u8) void {...@@ -1268,3 +1268,82 @@ fn printInvocation(args: []const []const u8) void {
1268 }1268 }
1269 std.debug.print("\n", .{});1269 std.debug.print("\n", .{});
1270}1270}
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}