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