| author | |
| committer | |
| log | 04472af328632d80ea9ea089cfd5de8fac6dd039 |
| tree | 7b8d46635c0a0accc82277a6209a87e4d4b9d13b |
| parent | a3033c7bd9ec26abd2f831cf75eb85f06590deed |
| parent | f2a7aba586157482131611c57a283f3b4cfee98d |
| signature |
implement ARM C ABI, separate C ABI tests from standalone tests13 files changed, 694 insertions(+), 201 deletions(-)
build.zig+1| ... | ... | @@ -508,6 +508,7 @@ pub fn build(b: *Builder) !void { |
| 508 | 508 | b.enable_wasmtime, |
| 509 | 509 | b.enable_wine, |
| 510 | 510 | )); |
| 511 | test_step.dependOn(tests.addCAbiTests(b, skip_non_native)); | |
| 511 | 512 | test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests)); |
| 512 | 513 | test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes)); |
| 513 | 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 | 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 6 | 6 | const Type = @import("../../type.zig").Type; |
| 7 | 7 | |
| 8 | pub const Class = enum(u8) { memory, integer, none, float_array, _ }; | |
| 8 | pub const Class = union(enum) { | |
| 9 | memory, | |
| 10 | byval, | |
| 11 | integer, | |
| 12 | double_integer, | |
| 13 | float_array: u8, | |
| 14 | }; | |
| 9 | 15 | |
| 10 | 16 | /// For `float_array` the second element will be the amount of floats. |
| 11 | pub 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 | } | |
| 17 | pub fn classifyType(ty: Type, target: std.Target) Class { | |
| 18 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime()); | |
| 17 | 19 | |
| 18 | fn classifyTypeInner(ty: Type, target: std.Target) [2]Class { | |
| 19 | if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none }; | |
| 20 | var maybe_float_bits: ?u16 = null; | |
| 20 | 21 | switch (ty.zigTypeTag()) { |
| 21 | 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 | 27 | 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; | |
| 27 | 31 | }, |
| 28 | 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 | 44 | 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; | |
| 33 | 48 | }, |
| 34 | .Int, .Enum, .ErrorSet, .Vector, .Float, .Bool => return .{ .integer, .none }, | |
| 35 | .Array => return .{ .memory, .none }, | |
| 36 | 49 | .Optional => { |
| 37 | 50 | std.debug.assert(ty.isPtrLikeOptional()); |
| 38 | return .{ .integer, .none }; | |
| 51 | return .byval; | |
| 39 | 52 | }, |
| 40 | 53 | .Pointer => { |
| 41 | 54 | std.debug.assert(!ty.isSlice()); |
| 42 | return .{ .integer, .none }; | |
| 55 | return .byval; | |
| 43 | 56 | }, |
| 44 | 57 | .ErrorUnion, |
| 45 | 58 | .Frame, |
| ... | ... | @@ -55,17 +68,18 @@ fn classifyTypeInner(ty: Type, target: std.Target) [2]Class { |
| 55 | 68 | .Fn, |
| 56 | 69 | .Opaque, |
| 57 | 70 | .EnumLiteral, |
| 71 | .Array, | |
| 58 | 72 | => unreachable, |
| 59 | 73 | } |
| 60 | 74 | } |
| 61 | 75 | |
| 62 | 76 | const sret_float_count = 4; |
| 63 | fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 { | |
| 64 | const invalid = std.math.maxInt(u32); | |
| 77 | fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u8 { | |
| 78 | const invalid = std.math.maxInt(u8); | |
| 65 | 79 | switch (ty.zigTypeTag()) { |
| 66 | 80 | .Union => { |
| 67 | 81 | const fields = ty.unionFields(); |
| 68 | var max_count: u32 = 0; | |
| 82 | var max_count: u8 = 0; | |
| 69 | 83 | for (fields.values()) |field| { |
| 70 | 84 | const field_count = countFloats(field.ty, target, maybe_float_bits); |
| 71 | 85 | if (field_count == invalid) return invalid; |
| ... | ... | @@ -76,7 +90,7 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 { |
| 76 | 90 | }, |
| 77 | 91 | .Struct => { |
| 78 | 92 | const fields_len = ty.structFieldCount(); |
| 79 | var count: u32 = 0; | |
| 93 | var count: u8 = 0; | |
| 80 | 94 | var i: u32 = 0; |
| 81 | 95 | while (i < fields_len) : (i += 1) { |
| 82 | 96 | const field_ty = ty.structFieldType(i); |
src/arch/arm/abi.zig+154| ... | ... | @@ -2,6 +2,160 @@ const std = @import("std"); |
| 2 | 2 | const bits = @import("bits.zig"); |
| 3 | 3 | const Register = bits.Register; |
| 4 | 4 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 5 | const Type = @import("../../type.zig").Type; | |
| 6 | ||
| 7 | pub 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 | ||
| 23 | pub const Context = enum { ret, arg }; | |
| 24 | ||
| 25 | pub 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 | ||
| 117 | const byval_float_count = 4; | |
| 118 | fn 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 | } | |
| 5 | 159 | |
| 6 | 160 | pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 }; |
| 7 | 161 | pub const caller_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3 }; |
src/arch/riscv64/abi.zig+69| ... | ... | @@ -2,6 +2,75 @@ const std = @import("std"); |
| 2 | 2 | const bits = @import("bits.zig"); |
| 3 | 3 | const Register = bits.Register; |
| 4 | 4 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 5 | const Type = @import("../../type.zig").Type; | |
| 6 | ||
| 7 | pub const Class = enum { memory, byval, integer, double_integer }; | |
| 8 | ||
| 9 | pub 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 | } | |
| 5 | 74 | |
| 6 | 75 | pub const callee_preserved_regs = [_]Register{ |
| 7 | 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 | 7149 | |
| 7150 | 7150 | const classes: []const abi.Class = switch (self.target.os.tag) { |
| 7151 | 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 | 7154 | if (classes.len > 1) { |
| 7155 | 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 | 60 | } |
| 61 | 61 | } |
| 62 | 62 | |
| 63 | pub const Context = enum { ret, arg }; | |
| 64 | ||
| 63 | 65 | /// There are a maximum of 8 possible return slots. Returned values are in |
| 64 | 66 | /// the beginning of the array; unused slots are filled with .none. |
| 65 | pub fn classifySystemV(ty: Type, target: Target) [8]Class { | |
| 67 | pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | |
| 66 | 68 | const memory_class = [_]Class{ |
| 67 | 69 | .memory, .none, .none, .none, |
| 68 | 70 | .none, .none, .none, .none, |
| ... | ... | @@ -134,6 +136,22 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 134 | 136 | }, |
| 135 | 137 | .Vector => { |
| 136 | 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 | 155 | const bits = elem_ty.bitSize(target) * ty.arrayLen(); |
| 138 | 156 | if (bits <= 64) return .{ |
| 139 | 157 | .sse, .none, .none, .none, |
| ... | ... | @@ -201,7 +219,7 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 201 | 219 | } |
| 202 | 220 | } |
| 203 | 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 | 223 | const field_class = std.mem.sliceTo(&field_class_array, .none); |
| 206 | 224 | if (byte_i + field_size <= 8) { |
| 207 | 225 | // Combine this field with the previous one. |
| ... | ... | @@ -315,7 +333,7 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 315 | 333 | } |
| 316 | 334 | } |
| 317 | 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 | 337 | for (result) |*result_item, i| { |
| 320 | 338 | const field_item = field_class[i]; |
| 321 | 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 | 24 | const x86_64_abi = @import("../arch/x86_64/abi.zig"); |
| 25 | 25 | const wasm_c_abi = @import("../arch/wasm/abi.zig"); |
| 26 | 26 | const aarch64_c_abi = @import("../arch/aarch64/abi.zig"); |
| 27 | const arm_c_abi = @import("../arch/arm/abi.zig"); | |
| 28 | const riscv_c_abi = @import("../arch/riscv64/abi.zig"); | |
| 27 | 29 | |
| 28 | 30 | const Error = error{ OutOfMemory, CodegenFail }; |
| 29 | 31 | |
| ... | ... | @@ -1130,6 +1132,25 @@ pub const Object = struct { |
| 1130 | 1132 | const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), ""); |
| 1131 | 1133 | _ = builder.buildStore(param, casted_ptr); |
| 1132 | 1134 | |
| 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 | 1154 | if (isByRef(param_ty)) { |
| 1134 | 1155 | try args.append(arg_ptr); |
| 1135 | 1156 | } else { |
| ... | ... | @@ -2578,6 +2599,8 @@ pub const DeclGen = struct { |
| 2578 | 2599 | .multiple_llvm_float, |
| 2579 | 2600 | .as_u16, |
| 2580 | 2601 | .float_array, |
| 2602 | .i32_array, | |
| 2603 | .i64_array, | |
| 2581 | 2604 | => continue, |
| 2582 | 2605 | |
| 2583 | 2606 | .slice => unreachable, // extern functions do not support slice types. |
| ... | ... | @@ -3132,6 +3155,11 @@ pub const DeclGen = struct { |
| 3132 | 3155 | const arr_ty = float_ty.arrayType(field_count); |
| 3133 | 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 | }; |
| 3136 | 3164 | |
| 3137 | 3165 | return llvm.functionType( |
| ... | ... | @@ -4822,6 +4850,25 @@ pub const FuncGen = struct { |
| 4822 | 4850 | load_inst.setAlignment(alignment); |
| 4823 | 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 | }; |
| 4826 | 4873 | |
| 4827 | 4874 | const call = self.builder.buildCall( |
| ... | ... | @@ -10083,10 +10130,16 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool |
| 10083 | 10130 | .mips, .mipsel => return false, |
| 10084 | 10131 | .x86_64 => switch (target.os.tag) { |
| 10085 | 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 | 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 | 10143 | else => return false, // TODO investigate C ABI for other architectures |
| 10091 | 10144 | }, |
| 10092 | 10145 | else => return false, |
| ... | ... | @@ -10139,7 +10192,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10139 | 10192 | if (is_scalar) { |
| 10140 | 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 | 10196 | if (classes[0] == .memory) { |
| 10144 | 10197 | return dg.context.voidType(); |
| 10145 | 10198 | } |
| ... | ... | @@ -10197,22 +10250,44 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10197 | 10250 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10198 | 10251 | }, |
| 10199 | 10252 | .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), | |
| 10206 | 10262 | } |
| 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), | |
| 10209 | 10273 | } |
| 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), | |
| 10213 | 10290 | } |
| 10214 | ||
| 10215 | return dg.context.intType(64).arrayType(2); | |
| 10216 | 10291 | }, |
| 10217 | 10292 | // TODO investigate C ABI for other architectures |
| 10218 | 10293 | else => return dg.lowerType(fn_info.return_type), |
| ... | ... | @@ -10242,6 +10317,8 @@ const ParamTypeIterator = struct { |
| 10242 | 10317 | slice, |
| 10243 | 10318 | as_u16, |
| 10244 | 10319 | float_array: u8, |
| 10320 | i32_array: u8, | |
| 10321 | i64_array: u8, | |
| 10245 | 10322 | }; |
| 10246 | 10323 | |
| 10247 | 10324 | pub fn next(it: *ParamTypeIterator) ?Lowering { |
| ... | ... | @@ -10288,15 +10365,6 @@ const ParamTypeIterator = struct { |
| 10288 | 10365 | .C => { |
| 10289 | 10366 | const is_scalar = isScalar(ty); |
| 10290 | 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 | 10368 | .mips, .mipsel => { |
| 10301 | 10369 | it.zig_index += 1; |
| 10302 | 10370 | it.llvm_index += 1; |
| ... | ... | @@ -10334,18 +10402,18 @@ const ParamTypeIterator = struct { |
| 10334 | 10402 | else => unreachable, |
| 10335 | 10403 | }, |
| 10336 | 10404 | 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); | |
| 10343 | 10406 | if (classes[0] == .memory) { |
| 10344 | 10407 | it.zig_index += 1; |
| 10345 | 10408 | it.llvm_index += 1; |
| 10346 | 10409 | it.byval_attr = true; |
| 10347 | 10410 | return .byref; |
| 10348 | 10411 | } |
| 10412 | if (is_scalar) { | |
| 10413 | it.zig_index += 1; | |
| 10414 | it.llvm_index += 1; | |
| 10415 | return .byval; | |
| 10416 | } | |
| 10349 | 10417 | var llvm_types_buffer: [8]u16 = undefined; |
| 10350 | 10418 | var llvm_types_index: u32 = 0; |
| 10351 | 10419 | for (classes) |class| { |
| ... | ... | @@ -10383,11 +10451,6 @@ const ParamTypeIterator = struct { |
| 10383 | 10451 | it.llvm_index += 1; |
| 10384 | 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 | 10454 | it.llvm_types_buffer = llvm_types_buffer; |
| 10392 | 10455 | it.llvm_types_len = llvm_types_index; |
| 10393 | 10456 | it.llvm_index += llvm_types_index; |
| ... | ... | @@ -10410,24 +10473,45 @@ const ParamTypeIterator = struct { |
| 10410 | 10473 | .aarch64, .aarch64_be => { |
| 10411 | 10474 | it.zig_index += 1; |
| 10412 | 10475 | 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 }, | |
| 10415 | 10486 | } |
| 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 }, | |
| 10419 | 10499 | } |
| 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; | |
| 10422 | 10506 | } |
| 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 }, | |
| 10427 | 10514 | } |
| 10428 | it.llvm_types_buffer[0] = 64; | |
| 10429 | it.llvm_types_buffer[1] = 64; | |
| 10430 | return .multiple_llvm_ints; | |
| 10431 | 10515 | }, |
| 10432 | 10516 | // TODO investigate C ABI for other architectures |
| 10433 | 10517 | else => { |
| ... | ... | @@ -10475,8 +10559,16 @@ fn ccAbiPromoteInt( |
| 10475 | 10559 | }; |
| 10476 | 10560 | if (int_info.bits <= 16) return int_info.signedness; |
| 10477 | 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 | 10571 | .sparc64, |
| 10479 | .riscv64, | |
| 10480 | 10572 | .powerpc64, |
| 10481 | 10573 | .powerpc64le, |
| 10482 | 10574 | => { |
test/c_abi/build.zig deleted-22| ... | ... | @@ -1,22 +0,0 @@ |
| 1 | const Builder = @import("std").build.Builder; | |
| 2 | ||
| 3 | pub 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 @@ |
| 1 | const std = @import("std"); | |
| 2 | const Builder = std.build.Builder; | |
| 3 | ||
| 4 | pub 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> | |
| 1 | 2 | #include <inttypes.h> |
| 2 | #include <stdlib.h> | |
| 3 | 3 | #include <stdbool.h> |
| 4 | #include <stdlib.h> | |
| 4 | 5 | #include <string.h> |
| 5 | #include <complex.h> | |
| 6 | 6 | |
| 7 | 7 | void zig_panic(); |
| 8 | 8 | |
| ... | ... | @@ -12,6 +12,14 @@ static void assert_or_panic(bool ok) { |
| 12 | 12 | } |
| 13 | 13 | } |
| 14 | 14 | |
| 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 | 23 | #ifdef __i386__ |
| 16 | 24 | # define ZIG_NO_I128 |
| 17 | 25 | #endif |
| ... | ... | @@ -24,6 +32,14 @@ static void assert_or_panic(bool ok) { |
| 24 | 32 | # define ZIG_NO_I128 |
| 25 | 33 | #endif |
| 26 | 34 | |
| 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 | 43 | #ifdef __i386__ |
| 28 | 44 | # define ZIG_NO_COMPLEX |
| 29 | 45 | #endif |
| ... | ... | @@ -32,6 +48,18 @@ static void assert_or_panic(bool ok) { |
| 32 | 48 | # define ZIG_NO_COMPLEX |
| 33 | 49 | #endif |
| 34 | 50 | |
| 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 | 63 | #ifndef ZIG_NO_I128 |
| 36 | 64 | struct i128 { |
| 37 | 65 | __int128 value; |
| ... | ... | @@ -206,7 +234,7 @@ void run_c_tests(void) { |
| 206 | 234 | zig_longdouble(12.34l); |
| 207 | 235 | zig_five_floats(1.0f, 2.0f, 3.0f, 4.0f, 5.0f); |
| 208 | 236 | |
| 209 | zig_ptr((void*)0xdeadbeefL); | |
| 237 | zig_ptr((void *)0xdeadbeefL); | |
| 210 | 238 | |
| 211 | 239 | zig_bool(true); |
| 212 | 240 | |
| ... | ... | @@ -249,14 +277,15 @@ void run_c_tests(void) { |
| 249 | 277 | } |
| 250 | 278 | #endif |
| 251 | 279 | |
| 252 | #if !defined __mips__ && !defined __riscv | |
| 280 | #if !defined __mips__ && !defined ZIG_PPC32 | |
| 253 | 281 | { |
| 254 | 282 | struct BigStruct s = {1, 2, 3, 4, 5}; |
| 255 | 283 | zig_big_struct(s); |
| 256 | 284 | } |
| 257 | 285 | #endif |
| 258 | 286 | |
| 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 | |
| 260 | 289 | { |
| 261 | 290 | struct SmallStructInts s = {1, 2, 3, 4}; |
| 262 | 291 | zig_small_struct_ints(s); |
| ... | ... | @@ -281,28 +310,30 @@ void run_c_tests(void) { |
| 281 | 310 | zig_small_packed_struct(s); |
| 282 | 311 | } |
| 283 | 312 | |
| 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 | |
| 285 | 315 | { |
| 286 | 316 | struct SplitStructInts s = {1234, 100, 1337}; |
| 287 | 317 | zig_split_struct_ints(s); |
| 288 | 318 | } |
| 289 | 319 | #endif |
| 290 | 320 | |
| 291 | #if !defined __arm__ && !defined __riscv | |
| 321 | #if !defined __arm__ && !defined ZIG_PPC32 && !defined _ARCH_PPC64 | |
| 292 | 322 | { |
| 293 | 323 | struct MedStructMixed s = {1234, 100.0f, 1337.0f}; |
| 294 | 324 | zig_med_struct_mixed(s); |
| 295 | 325 | } |
| 296 | 326 | #endif |
| 297 | 327 | |
| 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 | |
| 299 | 330 | { |
| 300 | 331 | struct SplitStructMixed s = {1234, 100, 1337.0f}; |
| 301 | 332 | zig_split_struct_mixed(s); |
| 302 | 333 | } |
| 303 | 334 | #endif |
| 304 | 335 | |
| 305 | #if !defined __mips__ && !defined __riscv | |
| 336 | #if !defined __mips__ && !defined ZIG_PPC32 | |
| 306 | 337 | { |
| 307 | 338 | struct BigStruct s = {30, 31, 32, 33, 34}; |
| 308 | 339 | struct BigStruct res = zig_big_struct_both(s); |
| ... | ... | @@ -314,7 +345,7 @@ void run_c_tests(void) { |
| 314 | 345 | } |
| 315 | 346 | #endif |
| 316 | 347 | |
| 317 | #ifndef __riscv | |
| 348 | #if !defined ZIG_PPC32 && !defined _ARCH_PPC64 | |
| 318 | 349 | { |
| 319 | 350 | struct Rect r1 = {1, 21, 16, 4}; |
| 320 | 351 | struct Rect r2 = {178, 189, 21, 15}; |
| ... | ... | @@ -322,7 +353,7 @@ void run_c_tests(void) { |
| 322 | 353 | } |
| 323 | 354 | #endif |
| 324 | 355 | |
| 325 | #if !defined __mips__ && !defined __riscv | |
| 356 | #if !defined __mips__ && !defined ZIG_PPC32 | |
| 326 | 357 | { |
| 327 | 358 | struct FloatRect r1 = {1, 21, 16, 4}; |
| 328 | 359 | struct FloatRect r2 = {178, 189, 21, 15}; |
| ... | ... | @@ -335,9 +366,7 @@ void run_c_tests(void) { |
| 335 | 366 | |
| 336 | 367 | assert_or_panic(zig_ret_u8() == 0xff); |
| 337 | 368 | assert_or_panic(zig_ret_u16() == 0xffff); |
| 338 | #ifndef __riscv | |
| 339 | 369 | assert_or_panic(zig_ret_u32() == 0xffffffff); |
| 340 | #endif | |
| 341 | 370 | assert_or_panic(zig_ret_u64() == 0xffffffffffffffff); |
| 342 | 371 | |
| 343 | 372 | assert_or_panic(zig_ret_i8() == -1); |
| ... | ... | @@ -404,7 +433,7 @@ void c_long_double(long double x) { |
| 404 | 433 | } |
| 405 | 434 | |
| 406 | 435 | void c_ptr(void *x) { |
| 407 | assert_or_panic(x == (void*)0xdeadbeefL); | |
| 436 | assert_or_panic(x == (void *)0xdeadbeefL); | |
| 408 | 437 | } |
| 409 | 438 | |
| 410 | 439 | void c_bool(bool x) { |
| ... | ... | @@ -672,7 +701,7 @@ void c_struct_with_array(StructWithArray x) { |
| 672 | 701 | } |
| 673 | 702 | |
| 674 | 703 | StructWithArray c_ret_struct_with_array() { |
| 675 | return (StructWithArray) { 4, {}, 155 }; | |
| 704 | return (StructWithArray){4, {}, 155}; | |
| 676 | 705 | } |
| 677 | 706 | |
| 678 | 707 | typedef struct { |
| ... | ... | @@ -701,3 +730,43 @@ FloatArrayStruct c_ret_float_array_struct() { |
| 701 | 730 | x.size.height = 4; |
| 702 | 731 | return x; |
| 703 | 732 | } |
| 733 | ||
| 734 | typedef uint32_t SmallVec __attribute__((vector_size(2 * sizeof(uint32_t)))); | |
| 735 | ||
| 736 | void c_small_vec(SmallVec vec) { | |
| 737 | assert_or_panic(vec[0] == 1); | |
| 738 | assert_or_panic(vec[1] == 2); | |
| 739 | } | |
| 740 | ||
| 741 | SmallVec c_ret_small_vec(void) { | |
| 742 | return (SmallVec){3, 4}; | |
| 743 | } | |
| 744 | ||
| 745 | typedef size_t BigVec __attribute__((vector_size(8 * sizeof(size_t)))); | |
| 746 | ||
| 747 | void 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 | ||
| 758 | BigVec c_ret_big_vec(void) { | |
| 759 | return (BigVec){9, 10, 11, 12, 13, 14, 15, 16}; | |
| 760 | } | |
| 761 | ||
| 762 | typedef struct { | |
| 763 | float x, y; | |
| 764 | } Vector2; | |
| 765 | ||
| 766 | void c_ptr_size_float_struct(Vector2 vec) { | |
| 767 | assert_or_panic(vec.x == 1); | |
| 768 | assert_or_panic(vec.y == 2); | |
| 769 | } | |
| 770 | Vector2 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 | 3 | const print = std.debug.print; |
| 4 | 4 | const expect = std.testing.expect; |
| 5 | 5 | const 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(); | |
| 7 | 7 | |
| 8 | 8 | extern fn run_c_tests() void; |
| 9 | 9 | |
| ... | ... | @@ -112,6 +112,9 @@ test "C ABI floats" { |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | 114 | test "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 | 118 | c_long_double(12.34); |
| 116 | 119 | } |
| 117 | 120 | |
| ... | ... | @@ -167,7 +170,8 @@ extern fn c_cmultd_comp(a_r: f64, a_i: f64, b_r: f64, b_i: f64) ComplexDouble; |
| 167 | 170 | extern fn c_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat; |
| 168 | 171 | extern fn c_cmultd(a: ComplexDouble, b: ComplexDouble) ComplexDouble; |
| 169 | 172 | |
| 170 | const complex_abi_compatible = builtin.cpu.arch != .i386 and !builtin.cpu.arch.isMIPS(); | |
| 173 | const 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(); | |
| 171 | 175 | |
| 172 | 176 | test "C ABI complex float" { |
| 173 | 177 | if (!complex_abi_compatible) return error.SkipZigTest; |
| ... | ... | @@ -177,8 +181,8 @@ test "C ABI complex float" { |
| 177 | 181 | const b = ComplexFloat{ .real = 11.3, .imag = -1.5 }; |
| 178 | 182 | |
| 179 | 183 | 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); | |
| 182 | 186 | } |
| 183 | 187 | |
| 184 | 188 | test "C ABI complex float by component" { |
| ... | ... | @@ -188,8 +192,8 @@ test "C ABI complex float by component" { |
| 188 | 192 | const b = ComplexFloat{ .real = 11.3, .imag = -1.5 }; |
| 189 | 193 | |
| 190 | 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"); | |
| 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); | |
| 193 | 197 | } |
| 194 | 198 | |
| 195 | 199 | test "C ABI complex double" { |
| ... | ... | @@ -199,8 +203,8 @@ test "C ABI complex double" { |
| 199 | 203 | const b = ComplexDouble{ .real = 11.3, .imag = -1.5 }; |
| 200 | 204 | |
| 201 | 205 | 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); | |
| 204 | 208 | } |
| 205 | 209 | |
| 206 | 210 | test "C ABI complex double by component" { |
| ... | ... | @@ -210,8 +214,8 @@ test "C ABI complex double by component" { |
| 210 | 214 | const b = ComplexDouble{ .real = 11.3, .imag = -1.5 }; |
| 211 | 215 | |
| 212 | 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"); | |
| 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); | |
| 215 | 219 | } |
| 216 | 220 | |
| 217 | 221 | export fn zig_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat { |
| ... | ... | @@ -261,7 +265,7 @@ extern fn c_big_struct(BigStruct) void; |
| 261 | 265 | |
| 262 | 266 | test "C ABI big struct" { |
| 263 | 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; | |
| 265 | 269 | |
| 266 | 270 | var s = BigStruct{ |
| 267 | 271 | .a = 1, |
| ... | ... | @@ -287,7 +291,7 @@ const BigUnion = extern union { |
| 287 | 291 | extern fn c_big_union(BigUnion) void; |
| 288 | 292 | |
| 289 | 293 | test "C ABI big union" { |
| 290 | if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest; | |
| 294 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; | |
| 291 | 295 | |
| 292 | 296 | var x = BigUnion{ |
| 293 | 297 | .a = BigStruct{ |
| ... | ... | @@ -320,9 +324,9 @@ extern fn c_ret_med_struct_mixed() MedStructMixed; |
| 320 | 324 | |
| 321 | 325 | test "C ABI medium struct of ints and floats" { |
| 322 | 326 | if (builtin.cpu.arch == .i386) return error.SkipZigTest; |
| 323 | if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest; | |
| 324 | 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; | |
| 326 | 330 | |
| 327 | 331 | var s = MedStructMixed{ |
| 328 | 332 | .a = 1234, |
| ... | ... | @@ -331,9 +335,9 @@ test "C ABI medium struct of ints and floats" { |
| 331 | 335 | }; |
| 332 | 336 | c_med_struct_mixed(s); |
| 333 | 337 | 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); | |
| 337 | 341 | } |
| 338 | 342 | |
| 339 | 343 | export fn zig_med_struct_mixed(x: MedStructMixed) void { |
| ... | ... | @@ -353,9 +357,9 @@ extern fn c_ret_small_struct_ints() SmallStructInts; |
| 353 | 357 | |
| 354 | 358 | test "C ABI small struct of ints" { |
| 355 | 359 | if (builtin.cpu.arch == .i386) return error.SkipZigTest; |
| 356 | if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest; | |
| 357 | 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; | |
| 359 | 363 | |
| 360 | 364 | var s = SmallStructInts{ |
| 361 | 365 | .a = 1, |
| ... | ... | @@ -365,10 +369,10 @@ test "C ABI small struct of ints" { |
| 365 | 369 | }; |
| 366 | 370 | c_small_struct_ints(s); |
| 367 | 371 | 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); | |
| 372 | 376 | } |
| 373 | 377 | |
| 374 | 378 | export fn zig_small_struct_ints(x: SmallStructInts) void { |
| ... | ... | @@ -435,9 +439,9 @@ extern fn c_split_struct_ints(SplitStructInt) void; |
| 435 | 439 | |
| 436 | 440 | test "C ABI split struct of ints" { |
| 437 | 441 | if (builtin.cpu.arch == .i386) return error.SkipZigTest; |
| 438 | if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest; | |
| 439 | 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; | |
| 441 | 445 | |
| 442 | 446 | var s = SplitStructInt{ |
| 443 | 447 | .a = 1234, |
| ... | ... | @@ -463,9 +467,9 @@ extern fn c_ret_split_struct_mixed() SplitStructMixed; |
| 463 | 467 | |
| 464 | 468 | test "C ABI split struct of ints and floats" { |
| 465 | 469 | if (builtin.cpu.arch == .i386) return error.SkipZigTest; |
| 466 | if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest; | |
| 467 | 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; | |
| 469 | 473 | |
| 470 | 474 | var s = SplitStructMixed{ |
| 471 | 475 | .a = 1234, |
| ... | ... | @@ -474,9 +478,9 @@ test "C ABI split struct of ints and floats" { |
| 474 | 478 | }; |
| 475 | 479 | c_split_struct_mixed(s); |
| 476 | 480 | 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); | |
| 480 | 484 | } |
| 481 | 485 | |
| 482 | 486 | export fn zig_split_struct_mixed(x: SplitStructMixed) void { |
| ... | ... | @@ -492,7 +496,7 @@ extern fn c_multiple_struct_floats(FloatRect, FloatRect) void; |
| 492 | 496 | |
| 493 | 497 | test "C ABI sret and byval together" { |
| 494 | 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; | |
| 496 | 500 | |
| 497 | 501 | var s = BigStruct{ |
| 498 | 502 | .a = 1, |
| ... | ... | @@ -543,9 +547,9 @@ const Vector5 = extern struct { |
| 543 | 547 | extern fn c_big_struct_floats(Vector5) void; |
| 544 | 548 | |
| 545 | 549 | test "C ABI structs of floats as parameter" { |
| 546 | if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest; | |
| 547 | 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; | |
| 549 | 553 | |
| 550 | 554 | var v3 = Vector3{ |
| 551 | 555 | .x = 3.0, |
| ... | ... | @@ -584,7 +588,8 @@ export fn zig_multiple_struct_ints(x: Rect, y: Rect) void { |
| 584 | 588 | } |
| 585 | 589 | |
| 586 | 590 | test "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; | |
| 588 | 593 | |
| 589 | 594 | var r1 = Rect{ |
| 590 | 595 | .left = 1, |
| ... | ... | @@ -621,7 +626,7 @@ export fn zig_multiple_struct_floats(x: FloatRect, y: FloatRect) void { |
| 621 | 626 | |
| 622 | 627 | test "C ABI structs of floats as multiple parameters" { |
| 623 | 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; | |
| 625 | 630 | |
| 626 | 631 | var r1 = FloatRect{ |
| 627 | 632 | .left = 1, |
| ... | ... | @@ -725,15 +730,15 @@ extern fn c_ret_struct_with_array() StructWithArray; |
| 725 | 730 | |
| 726 | 731 | test "Struct with array as padding." { |
| 727 | 732 | if (builtin.cpu.arch == .i386) return error.SkipZigTest; |
| 728 | if (comptime builtin.cpu.arch.isARM()) return error.SkipZigTest; | |
| 729 | 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; | |
| 731 | 736 | |
| 732 | 737 | c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2 }); |
| 733 | 738 | |
| 734 | 739 | 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); | |
| 737 | 742 | } |
| 738 | 743 | |
| 739 | 744 | const FloatArrayStruct = extern struct { |
| ... | ... | @@ -752,7 +757,7 @@ extern fn c_ret_float_array_struct() FloatArrayStruct; |
| 752 | 757 | |
| 753 | 758 | test "Float array like struct" { |
| 754 | 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; | |
| 756 | 761 | |
| 757 | 762 | c_float_array_struct(.{ |
| 758 | 763 | .origin = .{ |
| ... | ... | @@ -766,8 +771,63 @@ test "Float array like struct" { |
| 766 | 771 | }); |
| 767 | 772 | |
| 768 | 773 | 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 | ||
| 780 | const SmallVec = @Vector(2, u32); | |
| 781 | ||
| 782 | extern fn c_small_vec(SmallVec) void; | |
| 783 | extern fn c_ret_small_vec() SmallVec; | |
| 784 | ||
| 785 | test "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 | ||
| 796 | const BigVec = @Vector(8, usize); | |
| 797 | ||
| 798 | extern fn c_big_vec(BigVec) void; | |
| 799 | extern fn c_ret_big_vec() BigVec; | |
| 800 | ||
| 801 | test "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 | ||
| 817 | const Vector2 = extern struct { x: f32, y: f32 }; | |
| 818 | ||
| 819 | extern fn c_ptr_size_float_struct(Vector2) void; | |
| 820 | extern fn c_ret_ptr_size_float_struct() Vector2; | |
| 821 | ||
| 822 | test "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 | 44 | if (builtin.os.tag != .wasi) { |
| 45 | 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 | }); | |
| 64 | 47 | |
| 65 | 48 | cases.addBuildFile("test/standalone/c_compiler/build.zig", .{ |
| 66 | 49 | .build_modes = true, |
test/tests.zig+79| ... | ... | @@ -1268,3 +1268,82 @@ fn printInvocation(args: []const []const u8) void { |
| 1268 | 1268 | } |
| 1269 | 1269 | std.debug.print("\n", .{}); |
| 1270 | 1270 | } |
| 1271 | ||
| 1272 | const 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 | ||
| 1321 | pub 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 | } |