| 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,27 +71,35 @@ pub fn classifyTypeForLlvm(ty: Type, zcu: *const Zcu) LlvmClass { |
| 71 | }, | 71 | }, |
| 72 | .@"struct" => { | 72 | .@"struct" => { |
| 73 | const struct_type = zcu.typeToStruct(ty).?; | 73 | const struct_type = zcu.typeToStruct(ty).?; |
| 74 | if (struct_type.layout == .@"packed") { | 74 | switch (struct_type.layout) { |
| 75 | return .{ .direct = ty }; | 75 | .auto => unreachable, |
| 76 | } | 76 | .@"packed" => return .{ .direct = ty }, |
| 77 | if (struct_type.field_types.len > 1) { | 77 | .@"extern" => {}, |
| 78 | // The struct type is non-scalar. | ||
| 79 | return .indirect; | ||
| 80 | } | 78 | } |
| 81 | const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[0]); | 79 | var opt_single_field_ty: ?Type = null; |
| 82 | const explicit_align = struct_type.field_aligns.getOrNone(ip, 0); | 80 | for (struct_type.field_types.get(ip), 0..) |field_ty_index, field_index| { |
| 83 | if (explicit_align != .none) { | 81 | const field_ty: Type = .fromInterned(field_ty_index); |
| 84 | if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(zcu))) | 82 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 83 | |||
| 84 | if (opt_single_field_ty != null) { | ||
| 85 | return .indirect; | 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) { | 94 | const single_field_ty = opt_single_field_ty.?; |
| 88 | switch (field_ty.arrayLenIncludingSentinel(zcu)) { | 95 | if (single_field_ty.zigTypeTag(zcu) == .array) { |
| 96 | switch (single_field_ty.arrayLenIncludingSentinel(zcu)) { | ||
| 89 | 0 => unreachable, | 97 | 0 => unreachable, |
| 90 | 1 => return classifyTypeForLlvm(field_ty.childType(zcu), zcu), | 98 | 1 => return classifyTypeForLlvm(single_field_ty.childType(zcu), zcu), |
| 91 | else => {}, | 99 | else => {}, |
| 92 | } | 100 | } |
| 93 | } | 101 | } |
| 94 | return classifyTypeForLlvm(field_ty, zcu); | 102 | return classifyTypeForLlvm(single_field_ty, zcu); |
| 95 | }, | 103 | }, |
| 96 | .@"union" => { | 104 | .@"union" => { |
| 97 | const union_obj = zcu.typeToUnion(ty).?; | 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,6 +15194,22 @@ void c_test_struct_f32_f32_f32_f32_f32(void) { |
| 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); | 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 | struct Struct_array_1_f32 { | 15213 | struct Struct_array_1_f32 { |
| 15198 | float a[1]; | 15214 | float a[1]; |
| 15199 | }; | 15215 | }; |
test/c_abi/main.zig+28| ... | @@ -16103,6 +16103,34 @@ test "struct f32, f32, f32, f32, f32" { | ... | @@ -16103,6 +16103,34 @@ test "struct f32, f32, f32, f32, f32" { |
| 16103 | c_test_struct_f32_f32_f32_f32_f32(); | 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 | const Struct_array_1_f32 = extern struct { | 16134 | const Struct_array_1_f32 = extern struct { |
| 16107 | a: [1]f32, | 16135 | a: [1]f32, |
| 16108 | }; | 16136 | }; |