diff --git a/CMakeLists.txt b/CMakeLists.txt index 66db1ccdbbd09aaa4e3ed28185a123f0c5e081ab..22419aa9fa4c09ed57745598bc1deaacde1d7834 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -549,34 +549,6 @@ set(ZIG_STAGE2_SOURCES src/Value.zig src/Zcu.zig src/Zcu/PerThread.zig - src/arch/riscv64/abi.zig - src/arch/riscv64/bits.zig - src/arch/riscv64/CodeGen.zig - src/arch/riscv64/Emit.zig - src/arch/riscv64/encoding.zig - src/arch/riscv64/Lower.zig - src/arch/riscv64/Mir.zig - src/arch/riscv64/mnem.zig - src/arch/sparc64/CodeGen.zig - src/arch/sparc64/Emit.zig - src/arch/sparc64/Mir.zig - src/arch/sparc64/abi.zig - src/arch/sparc64/bits.zig - src/arch/wasm/CodeGen.zig - src/arch/wasm/Emit.zig - src/arch/wasm/Mir.zig - src/arch/wasm/abi.zig - src/arch/x86/bits.zig - src/arch/x86_64/CodeGen.zig - src/arch/x86_64/Disassembler.zig - src/arch/x86_64/Emit.zig - src/arch/x86_64/Encoding.zig - src/arch/x86_64/Lower.zig - src/arch/x86_64/Mir.zig - src/arch/x86_64/abi.zig - src/arch/x86_64/bits.zig - src/arch/x86_64/encoder.zig - src/arch/x86_64/encodings.zon src/clang.zig src/clang_options.zig src/clang_options_data.zig diff --git a/src/arch/mips/abi.zig b/src/arch/mips/abi.zig deleted file mode 100644 index 02c4c637a4c362ea4b3a826fbd27b72598fcc2cb..0000000000000000000000000000000000000000 --- a/src/arch/mips/abi.zig +++ /dev/null @@ -1,84 +0,0 @@ -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/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 9452066bc511cdc8c69b43406303de5835b4e211..e396f69af358081653f5ce149a3505f238cde916 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -17,7 +17,7 @@ const Compilation = @import("../../Compilation.zig"); const link = @import("../../link.zig"); const Air = @import("../../Air.zig"); const Mir = @import("Mir.zig"); -const abi = @import("abi.zig"); +const abi = @import("../../codegen/wasm/abi.zig"); const Alignment = InternPool.Alignment; const errUnionPayloadOffset = codegen.errUnionPayloadOffset; const errUnionErrorOffset = codegen.errUnionErrorOffset; diff --git a/src/arch/wasm/abi.zig b/src/arch/wasm/abi.zig deleted file mode 100644 index a1fa8126491def2d9e2717faa0ccedcd2ee24805..0000000000000000000000000000000000000000 --- a/src/arch/wasm/abi.zig +++ /dev/null @@ -1,87 +0,0 @@ -//! 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; -} diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 1645a92657e4779965ca0a1884f23d5eebe57032..27092a1de89c9801bd8dab398fc4f50e9cc49c57 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 0000000000000000000000000000000000000000..02c4c637a4c362ea4b3a826fbd27b72598fcc2cb --- /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 0000000000000000000000000000000000000000..a1fa8126491def2d9e2717faa0ccedcd2ee24805 --- /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; +} diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 5f98771dcf5ed0396db0adcdd1c5280a67d6c32c..6c67547a00375070f302f2e94666c018ae386072 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -31,7 +31,7 @@ const mem = std.mem; const Mir = @import("../arch/wasm/Mir.zig"); const CodeGen = @import("../arch/wasm/CodeGen.zig"); -const abi = @import("../arch/wasm/abi.zig"); +const abi = @import("../codegen/wasm/abi.zig"); const Compilation = @import("../Compilation.zig"); const Dwarf = @import("Dwarf.zig"); const InternPool = @import("../InternPool.zig");