| author | |
| committer | |
| log | 646d927c792dbdd6db4a5bbee3cf5847283fe861 |
| tree | f285b620485ff0b8e01035ce08b42fd66551a41b |
| parent | 07b6173cb8877ce22fe6cb754cfc17367989b11e |
Closes #11702
Closes #131254 files changed, 142 insertions(+), 27 deletions(-)
src/arch/aarch64/abi.zig+73-17| ... | @@ -5,29 +5,21 @@ const Register = bits.Register; | ... | @@ -5,29 +5,21 @@ const Register = bits.Register; |
| 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 6 | const Type = @import("../../type.zig").Type; | 6 | const Type = @import("../../type.zig").Type; |
| 7 | 7 | ||
| 8 | pub const Class = enum { memory, integer, none, float_array }; | 8 | pub const Class = enum(u8) { memory, integer, none, float_array, _ }; |
| 9 | 9 | ||
| 10 | /// For `float_array` the second element will be the amount of floats. | ||
| 10 | pub fn classifyType(ty: Type, target: std.Target) [2]Class { | 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 | |||
| 18 | fn classifyTypeInner(ty: Type, target: std.Target) [2]Class { | ||
| 11 | if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none }; | 19 | if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none }; |
| 12 | switch (ty.zigTypeTag()) { | 20 | switch (ty.zigTypeTag()) { |
| 13 | .Struct => { | 21 | .Struct => { |
| 14 | if (ty.containerLayout() == .Packed) return .{ .integer, .none }; | 22 | if (ty.containerLayout() == .Packed) return .{ .integer, .none }; |
| 15 | |||
| 16 | if (ty.structFieldCount() <= 4) { | ||
| 17 | const fields = ty.structFields(); | ||
| 18 | var float_size: ?u64 = null; | ||
| 19 | for (fields.values()) |field| { | ||
| 20 | if (field.ty.zigTypeTag() != .Float) break; | ||
| 21 | const field_size = field.ty.bitSize(target); | ||
| 22 | const prev_size = float_size orelse { | ||
| 23 | float_size = field_size; | ||
| 24 | continue; | ||
| 25 | }; | ||
| 26 | if (field_size != prev_size) break; | ||
| 27 | } else { | ||
| 28 | return .{ .float_array, .none }; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | const bit_size = ty.bitSize(target); | 23 | const bit_size = ty.bitSize(target); |
| 32 | if (bit_size > 128) return .{ .memory, .none }; | 24 | if (bit_size > 128) return .{ .memory, .none }; |
| 33 | if (bit_size > 64) return .{ .integer, .integer }; | 25 | if (bit_size > 64) return .{ .integer, .integer }; |
| ... | @@ -67,6 +59,70 @@ pub fn classifyType(ty: Type, target: std.Target) [2]Class { | ... | @@ -67,6 +59,70 @@ pub fn classifyType(ty: Type, target: std.Target) [2]Class { |
| 67 | } | 59 | } |
| 68 | } | 60 | } |
| 69 | 61 | ||
| 62 | 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); | ||
| 65 | switch (ty.zigTypeTag()) { | ||
| 66 | .Union => { | ||
| 67 | const fields = ty.unionFields(); | ||
| 68 | var max_count: u32 = 0; | ||
| 69 | for (fields.values()) |field| { | ||
| 70 | const field_count = countFloats(field.ty, target, maybe_float_bits); | ||
| 71 | if (field_count == invalid) return invalid; | ||
| 72 | if (field_count > max_count) max_count = field_count; | ||
| 73 | if (max_count > sret_float_count) return invalid; | ||
| 74 | } | ||
| 75 | return max_count; | ||
| 76 | }, | ||
| 77 | .Struct => { | ||
| 78 | const fields_len = ty.structFieldCount(); | ||
| 79 | var count: u32 = 0; | ||
| 80 | var i: u32 = 0; | ||
| 81 | while (i < fields_len) : (i += 1) { | ||
| 82 | const field_ty = ty.structFieldType(i); | ||
| 83 | const field_count = countFloats(field_ty, target, maybe_float_bits); | ||
| 84 | if (field_count == invalid) return invalid; | ||
| 85 | count += field_count; | ||
| 86 | if (count > sret_float_count) return invalid; | ||
| 87 | } | ||
| 88 | return count; | ||
| 89 | }, | ||
| 90 | .Float => { | ||
| 91 | const float_bits = maybe_float_bits.* orelse { | ||
| 92 | maybe_float_bits.* = ty.floatBits(target); | ||
| 93 | return 1; | ||
| 94 | }; | ||
| 95 | if (ty.floatBits(target) == float_bits) return 1; | ||
| 96 | return invalid; | ||
| 97 | }, | ||
| 98 | .Void => return 0, | ||
| 99 | else => return invalid, | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | pub fn getFloatArrayType(ty: Type) ?Type { | ||
| 104 | switch (ty.zigTypeTag()) { | ||
| 105 | .Union => { | ||
| 106 | const fields = ty.unionFields(); | ||
| 107 | for (fields.values()) |field| { | ||
| 108 | if (getFloatArrayType(field.ty)) |some| return some; | ||
| 109 | } | ||
| 110 | return null; | ||
| 111 | }, | ||
| 112 | .Struct => { | ||
| 113 | const fields_len = ty.structFieldCount(); | ||
| 114 | var i: u32 = 0; | ||
| 115 | while (i < fields_len) : (i += 1) { | ||
| 116 | const field_ty = ty.structFieldType(i); | ||
| 117 | if (getFloatArrayType(field_ty)) |some| return some; | ||
| 118 | } | ||
| 119 | return null; | ||
| 120 | }, | ||
| 121 | .Float => return ty, | ||
| 122 | else => return null, | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 70 | const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct { | 126 | const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct { |
| 71 | pub const callee_preserved_regs = [_]Register{ | 127 | pub const callee_preserved_regs = [_]Register{ |
| 72 | .x20, .x21, .x22, .x23, | 128 | .x20, .x21, .x22, .x23, |
src/codegen/llvm.zig+9-10| ... | @@ -3125,10 +3125,10 @@ pub const DeclGen = struct { | ... | @@ -3125,10 +3125,10 @@ pub const DeclGen = struct { |
| 3125 | .as_u16 => { | 3125 | .as_u16 => { |
| 3126 | try llvm_params.append(dg.context.intType(16)); | 3126 | try llvm_params.append(dg.context.intType(16)); |
| 3127 | }, | 3127 | }, |
| 3128 | .float_array => { | 3128 | .float_array => |count| { |
| 3129 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 3129 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 3130 | const float_ty = try dg.lowerType(param_ty.structFieldType(0)); | 3130 | const float_ty = try dg.lowerType(aarch64_c_abi.getFloatArrayType(param_ty).?); |
| 3131 | const field_count = @intCast(c_uint, param_ty.structFieldCount()); | 3131 | const field_count = @intCast(c_uint, count); |
| 3132 | const arr_ty = float_ty.arrayType(field_count); | 3132 | const arr_ty = float_ty.arrayType(field_count); |
| 3133 | try llvm_params.append(arr_ty); | 3133 | try llvm_params.append(arr_ty); |
| 3134 | }, | 3134 | }, |
| ... | @@ -4801,7 +4801,7 @@ pub const FuncGen = struct { | ... | @@ -4801,7 +4801,7 @@ pub const FuncGen = struct { |
| 4801 | const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), ""); | 4801 | const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), ""); |
| 4802 | try llvm_args.append(casted); | 4802 | try llvm_args.append(casted); |
| 4803 | }, | 4803 | }, |
| 4804 | .float_array => { | 4804 | .float_array => |count| { |
| 4805 | const arg = args[it.zig_index - 1]; | 4805 | const arg = args[it.zig_index - 1]; |
| 4806 | const arg_ty = self.air.typeOf(arg); | 4806 | const arg_ty = self.air.typeOf(arg); |
| 4807 | var llvm_arg = try self.resolveInst(arg); | 4807 | var llvm_arg = try self.resolveInst(arg); |
| ... | @@ -4812,9 +4812,8 @@ pub const FuncGen = struct { | ... | @@ -4812,9 +4812,8 @@ pub const FuncGen = struct { |
| 4812 | llvm_arg = store_inst; | 4812 | llvm_arg = store_inst; |
| 4813 | } | 4813 | } |
| 4814 | 4814 | ||
| 4815 | const float_ty = try self.dg.lowerType(arg_ty.structFieldType(0)); | 4815 | const float_ty = try self.dg.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty).?); |
| 4816 | const field_count = @intCast(u32, arg_ty.structFieldCount()); | 4816 | const array_llvm_ty = float_ty.arrayType(count); |
| 4817 | const array_llvm_ty = float_ty.arrayType(field_count); | ||
| 4818 | 4817 | ||
| 4819 | const casted = self.builder.buildBitCast(llvm_arg, array_llvm_ty.pointerType(0), ""); | 4818 | const casted = self.builder.buildBitCast(llvm_arg, array_llvm_ty.pointerType(0), ""); |
| 4820 | const alignment = arg_ty.abiAlignment(target); | 4819 | const alignment = arg_ty.abiAlignment(target); |
| ... | @@ -10214,7 +10213,7 @@ const ParamTypeIterator = struct { | ... | @@ -10214,7 +10213,7 @@ const ParamTypeIterator = struct { |
| 10214 | llvm_types_buffer: [8]u16, | 10213 | llvm_types_buffer: [8]u16, |
| 10215 | byval_attr: bool, | 10214 | byval_attr: bool, |
| 10216 | 10215 | ||
| 10217 | const Lowering = enum { | 10216 | const Lowering = union(enum) { |
| 10218 | no_bits, | 10217 | no_bits, |
| 10219 | byval, | 10218 | byval, |
| 10220 | byref, | 10219 | byref, |
| ... | @@ -10223,7 +10222,7 @@ const ParamTypeIterator = struct { | ... | @@ -10223,7 +10222,7 @@ const ParamTypeIterator = struct { |
| 10223 | multiple_llvm_float, | 10222 | multiple_llvm_float, |
| 10224 | slice, | 10223 | slice, |
| 10225 | as_u16, | 10224 | as_u16, |
| 10226 | float_array, | 10225 | float_array: u8, |
| 10227 | }; | 10226 | }; |
| 10228 | 10227 | ||
| 10229 | pub fn next(it: *ParamTypeIterator) ?Lowering { | 10228 | pub fn next(it: *ParamTypeIterator) ?Lowering { |
| ... | @@ -10400,7 +10399,7 @@ const ParamTypeIterator = struct { | ... | @@ -10400,7 +10399,7 @@ const ParamTypeIterator = struct { |
| 10400 | return .byref; | 10399 | return .byref; |
| 10401 | } | 10400 | } |
| 10402 | if (classes[0] == .float_array) { | 10401 | if (classes[0] == .float_array) { |
| 10403 | return .float_array; | 10402 | return Lowering{ .float_array = @enumToInt(classes[1]) }; |
| 10404 | } | 10403 | } |
| 10405 | if (classes[1] == .none) { | 10404 | if (classes[1] == .none) { |
| 10406 | it.llvm_types_len = 1; | 10405 | it.llvm_types_len = 1; |
test/c_abi/cfuncs.c+27| ... | @@ -650,3 +650,30 @@ void c_struct_with_array(StructWithArray x) { | ... | @@ -650,3 +650,30 @@ void c_struct_with_array(StructWithArray x) { |
| 650 | StructWithArray c_ret_struct_with_array() { | 650 | StructWithArray c_ret_struct_with_array() { |
| 651 | return (StructWithArray) { 4, {}, 155 }; | 651 | return (StructWithArray) { 4, {}, 155 }; |
| 652 | } | 652 | } |
| 653 | |||
| 654 | typedef struct { | ||
| 655 | struct Point { | ||
| 656 | double x; | ||
| 657 | double y; | ||
| 658 | } origin; | ||
| 659 | struct Size { | ||
| 660 | double width; | ||
| 661 | double height; | ||
| 662 | } size; | ||
| 663 | } FloatArrayStruct; | ||
| 664 | |||
| 665 | void c_float_array_struct(FloatArrayStruct x) { | ||
| 666 | assert_or_panic(x.origin.x == 5); | ||
| 667 | assert_or_panic(x.origin.y == 6); | ||
| 668 | assert_or_panic(x.size.width == 7); | ||
| 669 | assert_or_panic(x.size.height == 8); | ||
| 670 | } | ||
| 671 | |||
| 672 | FloatArrayStruct c_ret_float_array_struct() { | ||
| 673 | FloatArrayStruct x; | ||
| 674 | x.origin.x = 1; | ||
| 675 | x.origin.y = 2; | ||
| 676 | x.size.width = 3; | ||
| 677 | x.size.height = 4; | ||
| 678 | return x; | ||
| 679 | } |
test/c_abi/main.zig+33| ... | @@ -700,3 +700,36 @@ test "Struct with array as padding." { | ... | @@ -700,3 +700,36 @@ test "Struct with array as padding." { |
| 700 | try std.testing.expect(x.a == 4); | 700 | try std.testing.expect(x.a == 4); |
| 701 | try std.testing.expect(x.b == 155); | 701 | try std.testing.expect(x.b == 155); |
| 702 | } | 702 | } |
| 703 | |||
| 704 | const FloatArrayStruct = extern struct { | ||
| 705 | origin: extern struct { | ||
| 706 | x: f64, | ||
| 707 | y: f64, | ||
| 708 | }, | ||
| 709 | size: extern struct { | ||
| 710 | width: f64, | ||
| 711 | height: f64, | ||
| 712 | }, | ||
| 713 | }; | ||
| 714 | |||
| 715 | extern fn c_float_array_struct(FloatArrayStruct) void; | ||
| 716 | extern fn c_ret_float_array_struct() FloatArrayStruct; | ||
| 717 | |||
| 718 | test "Float array like struct" { | ||
| 719 | c_float_array_struct(.{ | ||
| 720 | .origin = .{ | ||
| 721 | .x = 5, | ||
| 722 | .y = 6, | ||
| 723 | }, | ||
| 724 | .size = .{ | ||
| 725 | .width = 7, | ||
| 726 | .height = 8, | ||
| 727 | }, | ||
| 728 | }); | ||
| 729 | |||
| 730 | var x = c_ret_float_array_struct(); | ||
| 731 | try std.testing.expect(x.origin.x == 1); | ||
| 732 | try std.testing.expect(x.origin.y == 2); | ||
| 733 | try std.testing.expect(x.size.width == 3); | ||
| 734 | try std.testing.expect(x.size.height == 4); | ||
| 735 | } |