diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-07-02 15:01:50 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-07-02 15:01:50 -0700 |
| commit | 5ae2428d52da3211ee7b1577fe01894dc10f0619 (patch) | |
| tree | 1cafa007289566834d110de803788c5c9cb8a908 /src/codegen | |
| parent | a13f0d40eb0109e993d37ef4be9107a57e821bc9 (diff) | |
| download | zig-5ae2428d52da3211ee7b1577fe01894dc10f0619.tar.gz zig-5ae2428d52da3211ee7b1577fe01894dc10f0619.zip | |
compiler: change canonical path for backend ABI source files
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/llvm.zig | 4 | ||||
| -rw-r--r-- | src/codegen/mips/abi.zig | 84 | ||||
| -rw-r--r-- | src/codegen/wasm/abi.zig | 87 |
3 files changed, 173 insertions, 2 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 1645a92657..27092a1de8 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -21,11 +21,11 @@ const Air = @import("../Air.zig"); const Value = @import("../Value.zig"); const Type = @import("../Type.zig"); const x86_64_abi = @import("../arch/x86_64/abi.zig"); -const wasm_c_abi = @import("../arch/wasm/abi.zig"); +const wasm_c_abi = @import("wasm/abi.zig"); const aarch64_c_abi = @import("aarch64/abi.zig"); const arm_c_abi = @import("arm/abi.zig"); const riscv_c_abi = @import("../arch/riscv64/abi.zig"); -const mips_c_abi = @import("../arch/mips/abi.zig"); +const mips_c_abi = @import("mips/abi.zig"); const dev = @import("../dev.zig"); const target_util = @import("../target.zig"); diff --git a/src/codegen/mips/abi.zig b/src/codegen/mips/abi.zig new file mode 100644 index 0000000000..02c4c637a4 --- /dev/null +++ b/src/codegen/mips/abi.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const Type = @import("../../Type.zig"); +const Zcu = @import("../../Zcu.zig"); +const assert = std.debug.assert; + +pub const Class = union(enum) { + memory, + byval, + i32_array: u8, +}; + +pub const Context = enum { ret, arg }; + +pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { + const target = zcu.getTarget(); + std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); + + const max_direct_size = target.ptrBitWidth() * 2; + switch (ty.zigTypeTag(zcu)) { + .@"struct" => { + const bit_size = ty.bitSize(zcu); + if (ty.containerLayout(zcu) == .@"packed") { + if (bit_size > max_direct_size) return .memory; + return .byval; + } + if (bit_size > max_direct_size) return .memory; + // TODO: for bit_size <= 32 using byval is more correct, but that needs inreg argument attribute + const count = @as(u8, @intCast(std.mem.alignForward(u64, bit_size, 32) / 32)); + return .{ .i32_array = count }; + }, + .@"union" => { + const bit_size = ty.bitSize(zcu); + if (ty.containerLayout(zcu) == .@"packed") { + if (bit_size > max_direct_size) return .memory; + return .byval; + } + if (bit_size > max_direct_size) return .memory; + + return .byval; + }, + .bool => return .byval, + .float => return .byval, + .int, .@"enum", .error_set => { + return .byval; + }, + .vector => { + const elem_type = ty.elemType2(zcu); + switch (elem_type.zigTypeTag(zcu)) { + .bool, .int => { + const bit_size = ty.bitSize(zcu); + if (ctx == .ret and bit_size > 128) return .memory; + if (bit_size > 512) return .memory; + // TODO: byval vector arguments with non power of 2 size need inreg attribute + return .byval; + }, + .float => return .memory, + else => unreachable, + } + }, + .optional => { + std.debug.assert(ty.isPtrLikeOptional(zcu)); + return .byval; + }, + .pointer => { + std.debug.assert(!ty.isSlice(zcu)); + return .byval; + }, + .error_union, + .frame, + .@"anyframe", + .noreturn, + .void, + .type, + .comptime_float, + .comptime_int, + .undefined, + .null, + .@"fn", + .@"opaque", + .enum_literal, + .array, + => unreachable, + } +} diff --git a/src/codegen/wasm/abi.zig b/src/codegen/wasm/abi.zig new file mode 100644 index 0000000000..a1fa812649 --- /dev/null +++ b/src/codegen/wasm/abi.zig @@ -0,0 +1,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; +} |
