blob dcd192da (5360B) - Raw
1 const assert = @import("std").debug.assert; 2 const std = @import("std"); 3 const InternPool = @import("../../InternPool.zig"); 4 const Type = @import("../../Type.zig"); 5 const Zcu = @import("../../Zcu.zig"); 6 7 pub const Class = union(enum) { 8 memory, 9 byval, 10 integer, 11 double_integer, 12 float_array: u8, 13 }; 14 15 /// For `float_array` the second element will be the amount of floats. 16 pub fn classifyType(ty: Type, zcu: *Zcu) Class { 17 assert(ty.hasRuntimeBits(zcu)); 18 19 switch (ty.zigTypeTag(zcu)) { 20 .@"struct" => { 21 if (ty.containerLayout(zcu) == .@"packed") return .byval; 22 if (countFloats(ty, zcu)) |float| return .{ .float_array = float.count }; 23 24 const bit_size = ty.abiSize(zcu) * 8; 25 if (bit_size > 128) return .memory; 26 if (bit_size > 64) return .double_integer; 27 return .integer; 28 }, 29 .@"union" => { 30 if (ty.containerLayout(zcu) == .@"packed") return .byval; 31 if (countFloats(ty, zcu)) |float| return .{ .float_array = float.count }; 32 33 const bit_size = ty.abiSize(zcu) * 8; 34 if (bit_size > 128) return .memory; 35 if (bit_size > 64) return .double_integer; 36 return .integer; 37 }, 38 .int, .@"enum", .error_set, .float, .bool => return .byval, 39 .vector => { 40 const bit_size = ty.bitSize(zcu); 41 // TODO is this controlled by a cpu feature? 42 if (bit_size > 128) return .memory; 43 return .byval; 44 }, 45 .optional => { 46 assert(ty.isPtrLikeOptional(zcu)); 47 return .byval; 48 }, 49 .pointer => { 50 assert(!ty.isSlice(zcu)); 51 return .byval; 52 }, 53 .error_union, 54 .frame, 55 .@"anyframe", 56 .noreturn, 57 .void, 58 .type, 59 .comptime_float, 60 .comptime_int, 61 .undefined, 62 .null, 63 .@"fn", 64 .@"opaque", 65 .spirv, 66 .enum_literal, 67 .array, 68 => unreachable, 69 } 70 } 71 72 const CountFloatsResult = struct { 73 ty: Type, 74 count: std.math.IntFittingRange(0, max_count), 75 76 const none: CountFloatsResult = .{ .ty = .void, .count = 0 }; 77 78 const max_count = 4; 79 }; 80 fn countFloats(ty: Type, zcu: *Zcu) ?CountFloatsResult { 81 const ip = &zcu.intern_pool; 82 if (!ty.hasRuntimeBits(zcu)) return .none; 83 switch (ty.zigTypeTag(zcu)) { 84 .@"union" => { 85 const loaded_union = zcu.typeToUnion(ty).?; 86 var result: CountFloatsResult = .none; 87 for (loaded_union.field_types.get(ip)) |field_ty| { 88 const float = countFloats(Type.fromInterned(field_ty), zcu) orelse return null; 89 if (result.ty.toIntern() == .void_type) { 90 result.ty = float.ty; 91 } else if (result.ty.bitSize(zcu) != float.ty.bitSize(zcu)) return null; 92 result.count = @max(result.count, float.count); 93 } 94 if (ty.abiSize(zcu) != result.ty.abiSize(zcu) * result.count) return null; 95 return result; 96 }, 97 .@"struct" => { 98 var result: CountFloatsResult = .none; 99 var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (zcu.typeToStruct(ty)) |loaded_struct| 100 loaded_struct.iterateRuntimeOrder(ip) 101 else 102 .{ .runtime_order = null, .fields_len = ty.structFieldCount(zcu), .next_index = 0 }; 103 while (field_it.next()) |field_index| { 104 if (ty.structFieldOffset(field_index, zcu) != result.ty.abiSize(zcu) * result.count) return null; 105 const field_ty = ty.fieldType(field_index, zcu); 106 const float = countFloats(field_ty, zcu) orelse return null; 107 if (result.ty.toIntern() == .void_type) { 108 result.ty = float.ty; 109 } else if (result.ty.bitSize(zcu) != float.ty.bitSize(zcu)) return null; 110 if (float.count > CountFloatsResult.max_count - result.count) return null; 111 result.count += float.count; 112 } 113 if (ty.abiSize(zcu) != result.ty.abiSize(zcu) * result.count) return null; 114 return result; 115 }, 116 .float => return .{ .ty = ty, .count = 1 }, 117 else => return null, 118 } 119 } 120 121 pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type { 122 const ip = &zcu.intern_pool; 123 switch (ty.zigTypeTag(zcu)) { 124 .@"union" => { 125 const loaded_union = zcu.typeToUnion(ty).?; 126 for (loaded_union.field_types.get(ip)) |field_ty| { 127 if (getFloatArrayType(Type.fromInterned(field_ty), zcu)) |some| return some; 128 } 129 return null; 130 }, 131 .@"struct" => { 132 var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (zcu.typeToStruct(ty)) |loaded_struct| 133 loaded_struct.iterateRuntimeOrder(ip) 134 else 135 .{ .runtime_order = null, .fields_len = ty.structFieldCount(zcu), .next_index = 0 }; 136 while (field_it.next()) |field_index| { 137 const field_ty = ty.fieldType(field_index, zcu); 138 if (getFloatArrayType(field_ty, zcu)) |some| return some; 139 } 140 return null; 141 }, 142 .float => return ty, 143 else => return null, 144 } 145 }