| author | |
| committer | |
| log | fd13c819264007e8731fdb5ae9af211d18c70e9a |
| tree | 17ae59f36e0cc54435a81f185cf33f2a0eabcc7f |
| parent | 0bebd6108e586c5b6e216b4e69c1a06aa07d411d |
| signature |
3 files changed, 66 insertions(+), 14 deletions(-)
src/codegen/wasm/abi.zig+22-14| ... | ... | @@ -71,27 +71,35 @@ pub fn classifyTypeForLlvm(ty: Type, zcu: *const Zcu) LlvmClass { |
| 71 | 71 | }, |
| 72 | 72 | .@"struct" => { |
| 73 | 73 | const struct_type = zcu.typeToStruct(ty).?; |
| 74 | if (struct_type.layout == .@"packed") { | |
| 75 | return .{ .direct = ty }; | |
| 76 | } | |
| 77 | if (struct_type.field_types.len > 1) { | |
| 78 | // The struct type is non-scalar. | |
| 79 | return .indirect; | |
| 74 | switch (struct_type.layout) { | |
| 75 | .auto => unreachable, | |
| 76 | .@"packed" => return .{ .direct = ty }, | |
| 77 | .@"extern" => {}, | |
| 80 | 78 | } |
| 81 | const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[0]); | |
| 82 | const explicit_align = struct_type.field_aligns.getOrNone(ip, 0); | |
| 83 | if (explicit_align != .none) { | |
| 84 | if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(zcu))) | |
| 79 | var opt_single_field_ty: ?Type = null; | |
| 80 | for (struct_type.field_types.get(ip), 0..) |field_ty_index, field_index| { | |
| 81 | const field_ty: Type = .fromInterned(field_ty_index); | |
| 82 | if (!field_ty.hasRuntimeBits(zcu)) continue; | |
| 83 | ||
| 84 | if (opt_single_field_ty != null) { | |
| 85 | 85 | return .indirect; |
| 86 | } | |
| 87 | ||
| 88 | const field_align = struct_type.field_aligns.getOrNone(ip, field_index); | |
| 89 | if (field_align != .none and field_align.compareStrict(.gt, field_ty.abiAlignment(zcu))) { | |
| 90 | return .indirect; | |
| 91 | } | |
| 92 | opt_single_field_ty = field_ty; | |
| 86 | 93 | } |
| 87 | if (field_ty.zigTypeTag(zcu) == .array) { | |
| 88 | switch (field_ty.arrayLenIncludingSentinel(zcu)) { | |
| 94 | const single_field_ty = opt_single_field_ty.?; | |
| 95 | if (single_field_ty.zigTypeTag(zcu) == .array) { | |
| 96 | switch (single_field_ty.arrayLenIncludingSentinel(zcu)) { | |
| 89 | 97 | 0 => unreachable, |
| 90 | 1 => return classifyTypeForLlvm(field_ty.childType(zcu), zcu), | |
| 98 | 1 => return classifyTypeForLlvm(single_field_ty.childType(zcu), zcu), | |
| 91 | 99 | else => {}, |
| 92 | 100 | } |
| 93 | 101 | } |
| 94 | return classifyTypeForLlvm(field_ty, zcu); | |
| 102 | return classifyTypeForLlvm(single_field_ty, zcu); | |
| 95 | 103 | }, |
| 96 | 104 | .@"union" => { |
| 97 | 105 | const union_obj = zcu.typeToUnion(ty).?; |
test/c_abi/cfuncs.c+16| ... | ... | @@ -15194,6 +15194,22 @@ void c_test_struct_f32_f32_f32_f32_f32(void) { |
| 15194 | 15194 | zig_struct_f32_f32_f32_f32_f32((struct Struct_f32_f32_f32_f32_f32){ .a = 6, .b = 7, .c = 8, .d = 9, .e = 10 }, 11); |
| 15195 | 15195 | } |
| 15196 | 15196 | |
| 15197 | struct Struct_f32 zig_ret_struct_void_f32(void); | |
| 15198 | void zig_struct_void_f32(struct Struct_f32, size_t); | |
| 15199 | ||
| 15200 | struct Struct_f32 c_ret_struct_void_f32(void) { | |
| 15201 | return (struct Struct_f32){ .a = 4 }; | |
| 15202 | } | |
| 15203 | void c_struct_void_f32(struct Struct_f32 s, size_t i) { | |
| 15204 | assert_or_panic(s.a == 5); | |
| 15205 | assert_or_panic(i == 6); | |
| 15206 | } | |
| 15207 | void c_test_struct_void_f32(void) { | |
| 15208 | struct Struct_f32 s = zig_ret_struct_void_f32(); | |
| 15209 | assert_or_panic(s.a == 1); | |
| 15210 | zig_struct_void_f32((struct Struct_f32){ .a = 2 }, 3); | |
| 15211 | } | |
| 15212 | ||
| 15197 | 15213 | struct Struct_array_1_f32 { |
| 15198 | 15214 | float a[1]; |
| 15199 | 15215 | }; |
test/c_abi/main.zig+28| ... | ... | @@ -16103,6 +16103,34 @@ test "struct f32, f32, f32, f32, f32" { |
| 16103 | 16103 | c_test_struct_f32_f32_f32_f32_f32(); |
| 16104 | 16104 | } |
| 16105 | 16105 | |
| 16106 | const Struct_void_f32 = extern struct { | |
| 16107 | _: void = {}, | |
| 16108 | a: f32, | |
| 16109 | }; | |
| 16110 | ||
| 16111 | export fn zig_ret_struct_void_f32() Struct_void_f32 { | |
| 16112 | return .{ .a = 1 }; | |
| 16113 | } | |
| 16114 | export fn zig_struct_void_f32(s: Struct_void_f32, i: usize) void { | |
| 16115 | expect(s.a == 2) catch @panic("test failure"); | |
| 16116 | expect(i == 3) catch @panic("test failure"); | |
| 16117 | } | |
| 16118 | ||
| 16119 | extern fn c_ret_struct_void_f32() Struct_void_f32; | |
| 16120 | extern fn c_struct_void_f32(Struct_void_f32, usize) void; | |
| 16121 | extern fn c_test_struct_void_f32() void; | |
| 16122 | ||
| 16123 | test "struct void, f32" { | |
| 16124 | if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; | |
| 16125 | if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; | |
| 16126 | if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; | |
| 16127 | ||
| 16128 | const s = c_ret_struct_void_f32(); | |
| 16129 | try expect(s.a == 4); | |
| 16130 | c_struct_void_f32(.{ .a = 5 }, 6); | |
| 16131 | c_test_struct_void_f32(); | |
| 16132 | } | |
| 16133 | ||
| 16106 | 16134 | const Struct_array_1_f32 = extern struct { |
| 16107 | 16135 | a: [1]f32, |
| 16108 | 16136 | }; |