master
 1//! Classifies Zig types to follow the C-ABI for Wasm.
 2//! The convention for Wasm's C-ABI can be found at the tool-conventions repo:
 3//! https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
 4//! When not targeting the C-ABI, Zig is allowed to do derail from this convention.
 5//! Note: Above mentioned document is not an official specification, therefore called a convention.
 6
 7const std = @import("std");
 8const Target = std.Target;
 9const assert = std.debug.assert;
10
11const Type = @import("../../Type.zig");
12const Zcu = @import("../../Zcu.zig");
13
14/// Defines how to pass a type as part of a function signature,
15/// both for parameters as well as return values.
16pub const Class = union(enum) {
17    direct: Type,
18    indirect,
19};
20
21/// Classifies a given Zig type to determine how they must be passed
22/// or returned as value within a wasm function.
23pub fn classifyType(ty: Type, zcu: *const Zcu) Class {
24    const ip = &zcu.intern_pool;
25    assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
26    switch (ty.zigTypeTag(zcu)) {
27        .int, .@"enum", .error_set => return .{ .direct = ty },
28        .float => return .{ .direct = ty },
29        .bool => return .{ .direct = ty },
30        .vector => return .{ .direct = ty },
31        .array => return .indirect,
32        .optional => {
33            assert(ty.isPtrLikeOptional(zcu));
34            return .{ .direct = ty };
35        },
36        .pointer => {
37            assert(!ty.isSlice(zcu));
38            return .{ .direct = ty };
39        },
40        .@"struct" => {
41            const struct_type = zcu.typeToStruct(ty).?;
42            if (struct_type.layout == .@"packed") {
43                return .{ .direct = ty };
44            }
45            if (struct_type.field_types.len > 1) {
46                // The struct type is non-scalar.
47                return .indirect;
48            }
49            const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[0]);
50            const explicit_align = struct_type.fieldAlign(ip, 0);
51            if (explicit_align != .none) {
52                if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(zcu)))
53                    return .indirect;
54            }
55            return classifyType(field_ty, zcu);
56        },
57        .@"union" => {
58            const union_obj = zcu.typeToUnion(ty).?;
59            if (union_obj.flagsUnordered(ip).layout == .@"packed") {
60                return .{ .direct = ty };
61            }
62            const layout = ty.unionGetLayout(zcu);
63            assert(layout.tag_size == 0);
64            if (union_obj.field_types.len > 1) return .indirect;
65            const first_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[0]);
66            return classifyType(first_field_ty, zcu);
67        },
68        .error_union,
69        .frame,
70        .@"anyframe",
71        .noreturn,
72        .void,
73        .type,
74        .comptime_float,
75        .comptime_int,
76        .undefined,
77        .null,
78        .@"fn",
79        .@"opaque",
80        .enum_literal,
81        => unreachable,
82    }
83}
84
85pub fn lowerAsDoubleI64(scalar_ty: Type, zcu: *const Zcu) bool {
86    return scalar_ty.bitSize(zcu) > 64;
87}