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}