| 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 | 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 6 | 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 | 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 | 19 | if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none }; |
| 12 | 20 | switch (ty.zigTypeTag()) { |
| 13 | 21 | .Struct => { |
| 14 | 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 | 23 | const bit_size = ty.bitSize(target); |
| 32 | 24 | if (bit_size > 128) return .{ .memory, .none }; |
| 33 | 25 | if (bit_size > 64) return .{ .integer, .integer }; |
| ... | ... | @@ -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 | 126 | const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct { |
| 71 | 127 | pub const callee_preserved_regs = [_]Register{ |
| 72 | 128 | .x20, .x21, .x22, .x23, |
src/codegen/llvm.zig+9-10| ... | ... | @@ -3125,10 +3125,10 @@ pub const DeclGen = struct { |
| 3125 | 3125 | .as_u16 => { |
| 3126 | 3126 | try llvm_params.append(dg.context.intType(16)); |
| 3127 | 3127 | }, |
| 3128 | .float_array => { | |
| 3128 | .float_array => |count| { | |
| 3129 | 3129 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 3130 | const float_ty = try dg.lowerType(param_ty.structFieldType(0)); | |
| 3131 | const field_count = @intCast(c_uint, param_ty.structFieldCount()); | |
| 3130 | const float_ty = try dg.lowerType(aarch64_c_abi.getFloatArrayType(param_ty).?); | |
| 3131 | const field_count = @intCast(c_uint, count); | |
| 3132 | 3132 | const arr_ty = float_ty.arrayType(field_count); |
| 3133 | 3133 | try llvm_params.append(arr_ty); |
| 3134 | 3134 | }, |
| ... | ... | @@ -4801,7 +4801,7 @@ pub const FuncGen = struct { |
| 4801 | 4801 | const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), ""); |
| 4802 | 4802 | try llvm_args.append(casted); |
| 4803 | 4803 | }, |
| 4804 | .float_array => { | |
| 4804 | .float_array => |count| { | |
| 4805 | 4805 | const arg = args[it.zig_index - 1]; |
| 4806 | 4806 | const arg_ty = self.air.typeOf(arg); |
| 4807 | 4807 | var llvm_arg = try self.resolveInst(arg); |
| ... | ... | @@ -4812,9 +4812,8 @@ pub const FuncGen = struct { |
| 4812 | 4812 | llvm_arg = store_inst; |
| 4813 | 4813 | } |
| 4814 | 4814 | |
| 4815 | const float_ty = try self.dg.lowerType(arg_ty.structFieldType(0)); | |
| 4816 | const field_count = @intCast(u32, arg_ty.structFieldCount()); | |
| 4817 | const array_llvm_ty = float_ty.arrayType(field_count); | |
| 4815 | const float_ty = try self.dg.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty).?); | |
| 4816 | const array_llvm_ty = float_ty.arrayType(count); | |
| 4818 | 4817 | |
| 4819 | 4818 | const casted = self.builder.buildBitCast(llvm_arg, array_llvm_ty.pointerType(0), ""); |
| 4820 | 4819 | const alignment = arg_ty.abiAlignment(target); |
| ... | ... | @@ -10214,7 +10213,7 @@ const ParamTypeIterator = struct { |
| 10214 | 10213 | llvm_types_buffer: [8]u16, |
| 10215 | 10214 | byval_attr: bool, |
| 10216 | 10215 | |
| 10217 | const Lowering = enum { | |
| 10216 | const Lowering = union(enum) { | |
| 10218 | 10217 | no_bits, |
| 10219 | 10218 | byval, |
| 10220 | 10219 | byref, |
| ... | ... | @@ -10223,7 +10222,7 @@ const ParamTypeIterator = struct { |
| 10223 | 10222 | multiple_llvm_float, |
| 10224 | 10223 | slice, |
| 10225 | 10224 | as_u16, |
| 10226 | float_array, | |
| 10225 | float_array: u8, | |
| 10227 | 10226 | }; |
| 10228 | 10227 | |
| 10229 | 10228 | pub fn next(it: *ParamTypeIterator) ?Lowering { |
| ... | ... | @@ -10400,7 +10399,7 @@ const ParamTypeIterator = struct { |
| 10400 | 10399 | return .byref; |
| 10401 | 10400 | } |
| 10402 | 10401 | if (classes[0] == .float_array) { |
| 10403 | return .float_array; | |
| 10402 | return Lowering{ .float_array = @enumToInt(classes[1]) }; | |
| 10404 | 10403 | } |
| 10405 | 10404 | if (classes[1] == .none) { |
| 10406 | 10405 | it.llvm_types_len = 1; |
test/c_abi/cfuncs.c+27| ... | ... | @@ -650,3 +650,30 @@ void c_struct_with_array(StructWithArray x) { |
| 650 | 650 | StructWithArray c_ret_struct_with_array() { |
| 651 | 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 | 700 | try std.testing.expect(x.a == 4); |
| 701 | 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 | } |