1const std = @import("std");
2const Type = @import("../../Type.zig");
3const Zcu = @import("../../Zcu.zig");
4const assert = std.debug.assert;
5
6pub const Class = union(enum) {
7 memory,
8 byval,
9 i32_array: u8,
10};
11
12pub const Context = enum { ret, arg };
13
14pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
15 const target = zcu.getTarget();
16 std.debug.assert(ty.hasRuntimeBits(zcu));
17
18 const max_direct_size = target.ptrBitWidth() * 2;
19 switch (ty.zigTypeTag(zcu)) {
20 .@"struct" => {
21 if (ty.containerLayout(zcu) == .@"packed") {
22 if (ty.bitSize(zcu) > max_direct_size) return .memory;
23 return .byval;
24 }
25 const bit_size = ty.abiSize(zcu) * 8;
26 if (bit_size > max_direct_size) return .memory;
27 // TODO: for bit_size <= 32 using byval is more correct, but that needs inreg argument attribute
28 const count = @as(u8, @intCast(std.mem.alignForward(u64, bit_size, 32) / 32));
29 return .{ .i32_array = count };
30 },
31 .@"union" => {
32 if (ty.containerLayout(zcu) == .@"packed") {
33 if (ty.bitSize(zcu) > max_direct_size) return .memory;
34 return .byval;
35 }
36 const bit_size = ty.abiSize(zcu) * 8;
37 if (bit_size > max_direct_size) return .memory;
38 return .byval;
39 },
40 .bool => return .byval,
41 .float => return switch (ty.floatBits(target)) {
42 else => unreachable,
43 16, 32, 64 => .byval,
44 80, 128 => switch (max_direct_size) {
45 else => unreachable,
46 64 => .memory,
47 },
48 },
49 .int, .@"enum", .error_set => {
50 return .byval;
51 },
52 .vector => {
53 const elem_type = ty.childType(zcu);
54 switch (elem_type.zigTypeTag(zcu)) {
55 .bool, .int => {
56 const bit_size = ty.bitSize(zcu);
57 if (ctx == .ret and bit_size > 128) return .memory;
58 if (bit_size > 512) return .memory;
59 // TODO: byval vector arguments with non power of 2 size need inreg attribute
60 return .byval;
61 },
62 .float => return .memory,
63 else => unreachable,
64 }
65 },
66 .optional => {
67 std.debug.assert(ty.isPtrLikeOptional(zcu));
68 return .byval;
69 },
70 .pointer => {
71 std.debug.assert(!ty.isSlice(zcu));
72 return .byval;
73 },
74 .error_union,
75 .frame,
76 .@"anyframe",
77 .noreturn,
78 .void,
79 .type,
80 .comptime_float,
81 .comptime_int,
82 .undefined,
83 .null,
84 .@"fn",
85 .@"opaque",
86 .spirv,
87 .enum_literal,
88 .array,
89 => unreachable,
90 }
91}