1const assert = std.debug.assert;
2const std = @import("std");
3const InternPool = @import("../../InternPool.zig");
4const Type = @import("../../Type.zig");
5const Zcu = @import("../../Zcu.zig");
6
7pub const Context = enum { ret, arg };
8
9pub const Class = enum {
10 none,
11 double_or_float,
12 vector,
13 simple,
14 simple_aggregate,
15 pointer,
16};
17
18pub 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}