| 1 | const assert = 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 Context = enum { ret, arg }; |
| 8 | |
| 9 | pub const Class = enum { |
| 10 | none, |
| 11 | double_or_float, |
| 12 | vector, |
| 13 | simple, |
| 14 | simple_aggregate, |
| 15 | pointer, |
| 16 | }; |
| 17 | |
| 18 | pub fn classifyType(ty: Type, context: Context, zcu: *Zcu) Class { |
| 19 | tag: switch (ty.zigTypeTag(zcu)) { |
| 20 | .type, |
| 21 | .comptime_float, |
| 22 | .comptime_int, |
| 23 | .undefined, |
| 24 | .null, |
| 25 | .error_union, |
| 26 | .error_set, |
| 27 | .@"fn", |
| 28 | .@"opaque", |
| 29 | .frame, |
| 30 | .@"anyframe", |
| 31 | .enum_literal, |
| 32 | .spirv, |
| 33 | => unreachable, |
| 34 | .void, .noreturn => return .none, |
| 35 | .bool => return .simple, |
| 36 | .int, .@"enum" => return switch (ty.intInfo(zcu).bits) { |
| 37 | 0 => .none, |
| 38 | 1...64 => .simple, |
| 39 | else => .pointer, |
| 40 | }, |
| 41 | .float => switch (ty.floatBits(zcu.getTarget())) { |
| 42 | else => unreachable, |
| 43 | 16, 32, 64 => return .double_or_float, |
| 44 | 80 => {}, |
| 45 | 128 => return .pointer, |
| 46 | }, |
| 47 | .pointer, .optional => return .simple, |
| 48 | .array => {}, |
| 49 | .@"struct", .@"union" => |tag| switch (ty.containerLayout(zcu)) { |
| 50 | .auto => unreachable, |
| 51 | .@"extern" => switch (context) { |
| 52 | .ret => {}, |
| 53 | .arg => { |
| 54 | var class: Class = .none; |
| 55 | for (0..switch (tag) { |
| 56 | else => unreachable, |
| 57 | .@"struct" => ty.structFieldCount(zcu), |
| 58 | .@"union" => ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu), |
| 59 | }) |field_index| { |
| 60 | switch (tag) { |
| 61 | else => unreachable, |
| 62 | .@"struct" => if (ty.structFieldIsComptime(field_index, zcu)) continue, |
| 63 | .@"union" => {}, |
| 64 | } |
| 65 | const field_class = classifyType(ty.fieldType(field_index, zcu), context, zcu); |
| 66 | if (field_class == .none) continue; |
| 67 | if (class != .none) break :tag; |
| 68 | class = field_class; |
| 69 | } |
| 70 | return class; |
| 71 | }, |
| 72 | }, |
| 73 | .@"packed" => return classifyType(ty.backingIntType(zcu), context, zcu), |
| 74 | }, |
| 75 | .vector => return if (ty.abiSize(zcu) <= 16) .vector else .pointer, |
| 76 | } |
| 77 | return switch (ty.abiSize(zcu)) { |
| 78 | 0 => .none, |
| 79 | 1, 2, 4, 8 => switch (context) { |
| 80 | .ret => .pointer, |
| 81 | .arg => .simple_aggregate, |
| 82 | }, |
| 83 | else => .pointer, |
| 84 | }; |
| 85 | } |