diff --git a/.forgejo/workflows/ci.yaml b/.forgejo/workflows/ci.yaml index de5070160d7a9a3554fd80e59cb07fe32a08c124..74d401cdead06e0f9f8ee3b6f4197a9ebdec09e8 100644 --- a/.forgejo/workflows/ci.yaml +++ b/.forgejo/workflows/ci.yaml @@ -153,7 +153,7 @@ jobs: fetch-depth: 0 - name: Build and Test run: sh ci/s390x-linux-debug.sh - timeout-minutes: 420 + timeout-minutes: 480 s390x-linux-release: runs-on: [self-hosted, s390x-linux] steps: @@ -174,7 +174,7 @@ jobs: fetch-depth: 0 - name: Build and Test run: sh ci/x86_64-freebsd-debug.sh - timeout-minutes: 120 + timeout-minutes: 1440 x86_64-freebsd-release: runs-on: [self-hosted, x86_64-freebsd] steps: @@ -184,7 +184,7 @@ jobs: fetch-depth: 0 - name: Build and Test run: sh ci/x86_64-freebsd-release.sh - timeout-minutes: 120 + timeout-minutes: 1440 x86_64-linux-debug: runs-on: [self-hosted, x86_64-linux] diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f144cd68374ec7c0ec8c7ba7964cde06943d88a..ce1289ceecfab1a3fc063e923c73400bac030020 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -358,6 +358,8 @@ set(ZIG_STAGE2_SOURCES src/codegen/c/type/render_defs.zig src/codegen/llvm.zig src/codegen/llvm/bindings.zig + src/codegen/loongarch/abi.zig + src/codegen/s390x/abi.zig src/crash_report.zig src/dev.zig src/libs/freebsd.zig @@ -600,24 +602,17 @@ if(MSVC) set(ZIG2_COMPILE_FLAGS "/Od") set(ZIG2_LINK_FLAGS "/STACK:16777216 /FORCE:MULTIPLE") else() - set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") - set(ZIG1_COMPILE_FLAGS "-std=c99 -Os -fno-strict-aliasing") - set(ZIG2_COMPILE_FLAGS "-std=c99 -O0 -fno-sanitize=undefined -fno-stack-protector -fno-strict-aliasing") + set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99") + set(ZIG1_COMPILE_FLAGS "-std=c99 -Oz -fno-strict-aliasing") + set(ZIG2_COMPILE_FLAGS "-std=c99 -Oz -fno-sanitize=undefined -fno-stack-protector -fno-strict-aliasing") + if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND ZIG_HOST_TARGET_ARCH STREQUAL "s390x") + string(REPLACE -Oz -O0 ZIG2_COMPILE_FLAGS "${ZIG2_COMPILE_FLAGS}") # llvm 22 assertion failure + endif() # Must match the condition in build.zig. if(ZIG_HOST_TARGET_ARCH MATCHES "^(arm|thumb)(eb)?$" OR ZIG_HOST_TARGET_ARCH EQUAL "hexagon" OR ZIG_HOST_TARGET_ARCH MATCHES "^powerpc(64)?(le)?$") set(ZIG1_COMPILE_FLAGS "${ZIG1_COMPILE_FLAGS} -ffunction-sections -fdata-sections") set(ZIG2_COMPILE_FLAGS "${ZIG2_COMPILE_FLAGS} -ffunction-sections -fdata-sections") endif() - if(APPLE) - set(ZIG2_LINK_FLAGS "-Wl,-stack_size,0x10000000") - elseif(MINGW) - set(ZIG2_LINK_FLAGS "-Wl,--stack,0x10000000") - # Solaris/illumos ld(1) does not provide a --stack-size option. - elseif(CMAKE_HOST_SOLARIS) - unset(ZIG2_LINK_FLAGS) - else() - set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") - endif() if (CMAKE_C_COMPILER_ID STREQUAL "GNU") # Prevent GCC from miscompiling 'zig2.c'. See also 'GCC_BUG_119085_PRESENT' workaround details in 'bootstrap.c'. if ( diff --git a/bootstrap.c b/bootstrap.c index 50297f34fdc429cdc75f1f338c4a9cd7d5aea5ab..e75e1c42ef0c8d59df5afb827d173ac755f60e18 100644 --- a/bootstrap.c +++ b/bootstrap.c @@ -56,7 +56,7 @@ static void panic(const char *reason) { #define GCC_BUG_119085_PRESENT 0 #endif -#if defined(__WIN32__) +#if defined(_WIN32) #error TODO write the functionality for executing child process into this build script #else @@ -99,7 +99,7 @@ static void print_and_run(const char **argv) { static const char *get_host_os(void) { const char *host_os = getenv("ZIG_HOST_TARGET_OS"); if (host_os != NULL) return host_os; -#if defined(__WIN32__) +#if defined(_WIN32) return "windows"; #elif defined(__APPLE__) return "macos"; diff --git a/build.zig b/build.zig index 385d4d5b7e0288d79a07c4c2c314cb7e6bc30c5d..3c019d38171015207279d3fd6a535e77ea99f6b0 100644 --- a/build.zig +++ b/build.zig @@ -207,7 +207,7 @@ pub fn build(b: *std.Build) !void { const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: { if (strip == true) break :blk @as(u32, 0); - if (optimize != .Debug) break :blk 0; + if (optimize != .debug) break :blk 0; break :blk 4; }; @@ -256,7 +256,7 @@ pub fn build(b: *std.Build) !void { exe.root_module.link_libc = true; } - const is_debug = optimize == .Debug; + const is_debug = optimize == .debug; const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug; const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug; @@ -403,8 +403,8 @@ pub fn build(b: *std.Build) !void { if (tracy) |tracy_dir| { const tracy_mod = b.createModule(.{ .target = target, - // Always build Tracy in ReleaseFast so that it doesn't make Debug compiler builds unusable. - .optimize = .ReleaseFast, + // Always build Tracy in ReleaseFast so that it doesn't make -Odebug compiler builds unusable. + .optimize = .fast, .root_source_file = null, .link_libc = true, .link_libcpp = true, @@ -434,19 +434,19 @@ pub fn build(b: *std.Build) !void { var chosen_opt_modes_buf: [4]std.lang.OptimizeMode = undefined; var chosen_mode_index: usize = 0; if (!skip_debug) { - chosen_opt_modes_buf[chosen_mode_index] = .Debug; + chosen_opt_modes_buf[chosen_mode_index] = .debug; chosen_mode_index += 1; } if (!skip_release_safe) { - chosen_opt_modes_buf[chosen_mode_index] = .ReleaseSafe; + chosen_opt_modes_buf[chosen_mode_index] = .safe; chosen_mode_index += 1; } if (!skip_release_fast) { - chosen_opt_modes_buf[chosen_mode_index] = .ReleaseFast; + chosen_opt_modes_buf[chosen_mode_index] = .fast; chosen_mode_index += 1; } if (!skip_release_small) { - chosen_opt_modes_buf[chosen_mode_index] = .ReleaseSmall; + chosen_opt_modes_buf[chosen_mode_index] = .small; chosen_mode_index += 1; } const optimize_modes = chosen_opt_modes_buf[0..chosen_mode_index]; @@ -622,7 +622,7 @@ pub fn build(b: *std.Build) !void { .use_llvm = use_llvm, .use_lld = use_llvm, .zig_lib_dir = b.path("lib"), - .max_rss = 2_700_000_000, + .max_rss = 3_000_000_000, }); if (link_libc) { unit_tests.root_module.link_libc = true; @@ -763,9 +763,8 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { .optimize = .ReleaseSmall, .target = b.resolveTargetQuery(std.Target.Query.parse(.{ .arch_os_abi = "wasm32-wasi", - // * `extended_const` is not supported by the `wasm-opt` version in CI. // * `nontrapping_bulk_memory_len0` is supported by `wasm2c`. - .cpu_features = "baseline-extended_const+nontrapping_bulk_memory_len0", + .cpu_features = "baseline+nontrapping_bulk_memory_len0", }) catch unreachable), }); @@ -809,6 +808,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { "-Oz", "--enable-bulk-memory", "--enable-mutable-globals", + "--enable-extended-const", "--enable-nontrapping-float-to-int", "--enable-sign-ext", }); diff --git a/ci/x86_64-freebsd-debug.sh b/ci/x86_64-freebsd-debug.sh index c67c7bbe4d50bdd2448a83e0479ff61b65cc5a62..5266970f1c184067753df726fd8921b87fdd76be 100755 --- a/ci/x86_64-freebsd-debug.sh +++ b/ci/x86_64-freebsd-debug.sh @@ -46,13 +46,7 @@ export ZIG_LIB_DIR="$PWD/../lib" stage3-debug/bin/zig build test docs \ --maxrss ${ZSF_MAX_RSS:-0} \ -Dstatic-llvm \ - -Dskip-spirv \ - -Dskip-wasm \ - -Dskip-linux \ - -Dskip-netbsd \ - -Dskip-openbsd \ - -Dskip-windows \ - -Dskip-darwin \ + -Dskip-non-native \ --search-prefix "$PREFIX" \ --test-timeout 2m diff --git a/ci/x86_64-freebsd-release.sh b/ci/x86_64-freebsd-release.sh index 83c88ef5aae163deee3cebd40c1b2b1f01047930..9425420cc083a13cf9974640d239d2c65bf99b2f 100755 --- a/ci/x86_64-freebsd-release.sh +++ b/ci/x86_64-freebsd-release.sh @@ -46,13 +46,7 @@ export ZIG_LIB_DIR="$PWD/../lib" stage3-release/bin/zig build test docs \ --maxrss ${ZSF_MAX_RSS:-0} \ -Dstatic-llvm \ - -Dskip-spirv \ - -Dskip-wasm \ - -Dskip-linux \ - -Dskip-netbsd \ - -Dskip-openbsd \ - -Dskip-windows \ - -Dskip-darwin \ + -Dskip-non-native \ --search-prefix "$PREFIX" \ --test-timeout 2m diff --git a/ci/x86_64-linux-debug.sh b/ci/x86_64-linux-debug.sh index 0316d3bef37f4058d256c97b62ae0e212160aead..91f6291d90b345139f394f4ee0c26bbe80a5ac57 100755 --- a/ci/x86_64-linux-debug.sh +++ b/ci/x86_64-linux-debug.sh @@ -44,7 +44,7 @@ ninja install # Must be done after zig cc is finished. export ZIG_LIB_DIR="$PWD/../lib" -export ZIG_DEBUG_MAKER=1 +export ZIG_DEBUG_CMD=1 # simultaneously test building self-hosted without LLVM and with 32-bit arm stage3-debug/bin/zig build \ diff --git a/doc/langref.html.in b/doc/langref.html.in index 9be898fc0499bc091f9020bd053ad3f4a2a1e851..d1c14d15f744c99e4cf6c951bdaed77ac0ba7f3b 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -1119,6 +1119,10 @@ otherwise the optimizer figures out all the values at compile-time, which operates in strict mode.

{#code|float_mode_exe.zig#} + {#shell_samp#}$ zig build-exe float_mode_exe.zig float_mode_obj.o -O fast +$ ./float_mode_exe +optimized = 0.001 +strict = 0.0009765625{#end_shell_samp#} {#see_also|@setFloatMode|Division by Zero#} {#header_close#} @@ -5848,7 +5852,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val {#header_open|@Union#}
{#syntax#}@Union(
     comptime layout: std.lang.Type.ContainerLayout,
-    /// Either the integer tag type, or the integer backing type, depending on `layout`.
+    /// Either the enum tag type, or the integer backing type, depending on `layout`.
     comptime ArgType: ?type,
     comptime field_names: []const []const u8,
     comptime field_types: *const [field_names.len]type,
@@ -7499,7 +7503,7 @@ fn readU32Be() u32 {}
             
{#syntax#}errdefer{#endsyntax#}
- {#syntax#}errdefer{#endsyntax#} will execute an expression when control flow leaves the current block if the function returns an error, the errdefer expression can capture the unwrapped value. + {#syntax#}errdefer{#endsyntax#} will execute an expression when control flow leaves the current block if the function returns an error. diff --git a/doc/langref/test_packed_structs.zig b/doc/langref/test_packed_structs.zig index 1fe918eefa23500a409d6228fbe789768de21564..eec2f58b10a10e4f7964a839d0b4b86e7b35da26 100644 --- a/doc/langref/test_packed_structs.zig +++ b/doc/langref/test_packed_structs.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const native_endian = @import("builtin").target.cpu.arch.endian(); const expectEqual = std.testing.expectEqual; const Full = packed struct { diff --git a/lib/build-web/time_report.zig b/lib/build-web/time_report.zig index f6e641432c93f7c2dc60cc710903ee907f25c626..042919e301b27d9c0705ed50ef057ad2f15b0d96 100644 --- a/lib/build-web/time_report.zig +++ b/lib/build-web/time_report.zig @@ -84,7 +84,7 @@ pub fn compileResultMessage(msg_bytes: []u8) error{ OutOfMemory, WriteFailed }!v defer gpa.free(slowest_decls); for (slowest_files) |*file_out| { - const i = std.mem.indexOfScalar(u8, trailing, 0) orelse @panic("malformed CompileResult message"); + const i = std.mem.findScalar(u8, trailing, 0) orelse @panic("malformed CompileResult message"); file_out.* = .{ .name = trailing[0..i], .ns_sema = 0, @@ -95,7 +95,7 @@ pub fn compileResultMessage(msg_bytes: []u8) error{ OutOfMemory, WriteFailed }!v } for (slowest_decls) |*decl_out| { - const i = std.mem.indexOfScalar(u8, trailing, 0) orelse @panic("malformed CompileResult message"); + const i = std.mem.findScalar(u8, trailing, 0) orelse @panic("malformed CompileResult message"); const file_idx = std.mem.readInt(u32, trailing[i..][1..5], .little); const sema_count = std.mem.readInt(u32, trailing[i..][5..9], .little); const sema_ns = std.mem.readInt(u64, trailing[i..][9..17], .little); @@ -258,7 +258,7 @@ pub fn runTestResultMessage(msg_bytes: []u8) error{OutOfMemory}!void { defer table_html.deinit(gpa); for (durations) |test_ns| { - const test_name_len = std.mem.indexOfScalar(u8, trailing[offset..], 0) orelse @panic("malformed RunTestResult message"); + const test_name_len = std.mem.findScalar(u8, trailing[offset..], 0) orelse @panic("malformed RunTestResult message"); const test_name = trailing[offset..][0..test_name_len]; offset += test_name_len + 1; try table_html.print(gpa, "{f}", .{fmtEscapeHtml(test_name)}); diff --git a/lib/c/malloc.zig b/lib/c/malloc.zig index 69f56641d0a26a9f4b68bbe75cc26de9203c6f1d..b9ba905440726fecbe7204ecd4e2d42bad198579 100644 --- a/lib/c/malloc.zig +++ b/lib/c/malloc.zig @@ -59,8 +59,8 @@ const Header = packed struct(u64) { } const safety = switch (builtin.mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, + .debug, .safe => true, + .fast, .small => false, }; const max_addr_bits = switch (safety) { true => 48, // Ensures space for Canary bits. diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index 8b7c9a23edf2701ae1a84f45525d8bccf2a7a1f0..ea2a05c1bb8e19b598e899ef3107348bd0e70da9 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -11,6 +11,7 @@ const File = std.Io.File; const Io = std.Io; const Dir = std.Io.Dir; const Path = std.Build.Cache.Path; +const Reader = std.Io.Reader; const Writer = std.Io.Writer; const assert = std.debug.assert; const fatal = std.process.fatal; @@ -19,6 +20,8 @@ const log = std.log; const mem = std.mem; const process = std.process; const Color = std.zig.Color; +const Client = std.zig.Client; +const Server = std.zig.Server; const EnvVar = std.zig.EnvVar; const default_local_zig_cache_basename = std.zig.default_local_zig_cache_basename; const stringToEnum = std.meta.stringToEnum; @@ -51,10 +54,14 @@ max_rss_mutex: Io.Mutex, skip_oom_steps: bool, unit_test_timeout_ns: ?u64, watch: bool, +protocol_server: ?*AvoidableServer, +protocol_server_mutex: Io.Mutex, web_server: ?*AvoidableWebServer, /// Allocated into `gpa`. memory_blocked_steps: std.ArrayList(Configuration.Step.Index), /// Allocated into `gpa`. +initial_steps: std.array_hash_map.Auto(Configuration.Step.Index, void), +/// Allocated into `gpa`. step_stack: std.array_hash_map.Auto(Configuration.Step.Index, void), pkg_config: PkgConfig, @@ -67,12 +74,13 @@ var stdio_buffer_allocation: [256]u8 = undefined; var stdout_writer_allocation: Io.File.Writer = undefined; var debug_maker_leaks: bool = false; +const AvoidableServer = if (builtin.single_threaded) void else Server; const AvoidableWebServer = if (builtin.single_threaded) void else WebServer; -const is_debug_mode = builtin.mode == .Debug; +const is_debug_mode = builtin.mode == .debug; const use_safe_allocator = switch (builtin.mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, + .debug, .safe => true, + .fast, .small => false, }; const InstallPaths = struct { @@ -216,6 +224,7 @@ pub fn main(init: process.Init.Minimal) !void { var watch = false; var fuzz: ?Fuzz.Mode = null; var debounce_interval_ms: u16 = 50; + var listen: bool = false; var webui_listen: ?Io.net.IpAddress = null; var debug_pkg_config = false; var run_args: ?[]const []const u8 = null; @@ -242,6 +251,12 @@ pub fn main(init: process.Init.Minimal) !void { } } + if (EnvVar.ZIG_BUILD_SUMMARY.get(&graph.environ_map)) |str| { + if (stringToEnum(Summary, str)) |value| { + summary = value; + } + } + try configure_argv.ensureUnusedCapacity(arena, 16); try cached_passthru_configure.ensureUnusedCapacity(arena, 16); @@ -416,6 +431,8 @@ pub fn main(init: process.Init.Minimal) !void { next_arg, err, }); }; + } else if (mem.eql(u8, arg, "--listen=-")) { + listen = true; } else if (mem.eql(u8, arg, "--webui")) { if (webui_listen == null) webui_listen = .{ .ip6 = .loopback(0) }; } else if (mem.startsWith(u8, arg, "--webui=")) { @@ -553,7 +570,7 @@ pub fn main(init: process.Init.Minimal) !void { } const early_exit_mode = fetch_only or help_menu or steps_menu or print_configuration != .none; - const server_mode = !early_exit_mode and (watch or webui_listen != null or fuzz != null); + const server_mode = !early_exit_mode and (watch or webui_listen != null or fuzz != null or listen); process.raiseFileDescriptorLimit(); @@ -631,20 +648,31 @@ pub fn main(init: process.Init.Minimal) !void { .sub_path = "zig-out", }; - const install_lib_path: Path = if (override_lib_dir) |cwd_relative| .{ - .root_dir = .cwd(), - .sub_path = cwd_relative, - } else try install_prefix_path.join(arena, "lib"); + // These three overrides are meant to be relative to the install prefix, + // not current working directory, unless absolute paths are used. + const install_lib_path: Path = if (override_lib_dir) |lib_dir| + if (Dir.path.isAbsolute(lib_dir)) .{ + .root_dir = .cwd(), + .sub_path = lib_dir, + } else try install_prefix_path.join(arena, lib_dir) + else + try install_prefix_path.join(arena, "lib"); - const install_bin_path: Path = if (override_bin_dir) |cwd_relative| .{ - .root_dir = .cwd(), - .sub_path = cwd_relative, - } else try install_prefix_path.join(arena, "bin"); + const install_bin_path: Path = if (override_bin_dir) |bin_dir| + if (Dir.path.isAbsolute(bin_dir)) .{ + .root_dir = .cwd(), + .sub_path = bin_dir, + } else try install_prefix_path.join(arena, bin_dir) + else + try install_prefix_path.join(arena, "bin"); - const install_include_path: Path = if (override_include_dir) |cwd_relative| .{ - .root_dir = .cwd(), - .sub_path = cwd_relative, - } else try install_prefix_path.join(arena, "include"); + const install_include_path: Path = if (override_include_dir) |include_dir| + if (Dir.path.isAbsolute(include_dir)) .{ + .root_dir = .cwd(), + .sub_path = include_dir, + } else try install_prefix_path.join(arena, include_dir) + else + try install_prefix_path.join(arena, "include"); const now = Io.Clock.Timestamp.now(io, .awake); @@ -661,6 +689,25 @@ pub fn main(init: process.Init.Minimal) !void { break :ws &web_server_allocation; } else null; + var stdin_buffer: [256]u8 = undefined; + var stdout_buffer: [256]u8 = undefined; + var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer); + var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); + + var protocol_server_allocation: AvoidableServer = undefined; + const protocol_server: ?*AvoidableServer = if (listen) s: { + if (builtin.single_threaded) fatal("--listen is not yet supported on single-threaded hosts", .{}); + if (watch) fatal("using '--watch' and '--listen' together is not supported", .{}); + if (fuzz != null) fatal("using '--fuzz' and '--listen' together is not supported", .{}); + if (step_names.items.len > 0) fatal("build steps must be provided over the protocol instead of using CLI arguments", .{}); + protocol_server_allocation = .{ + .in = &stdin_reader.interface, + .out = &stdout_writer.interface, + }; + try serveBSPHandshake(&protocol_server_allocation); + break :s &protocol_server_allocation; + } else null; + while (true) { // If this fails, we can still start the server and wait for user // to request a rebuild. If it returns error.FailedButCacheIntact @@ -731,16 +778,25 @@ pub fn main(init: process.Init.Minimal) !void { .watch = watch, .web_server = web_server, + .protocol_server = protocol_server, + .protocol_server_mutex = .init, .memory_blocked_steps = .empty, + .initial_steps = .empty, .step_stack = .empty, .pkg_config = .{ .debug = debug_pkg_config }, .error_style = error_style, .multiline_errors = multiline_errors, - .summary = summary orelse if (watch or webui_listen != null) .new else .failures, + .summary = summary orelse if (listen) + .none + else if (watch or webui_listen != null) + .new + else + .failures, }; defer { maker.memory_blocked_steps.deinit(gpa); + maker.initial_steps.deinit(gpa); maker.step_stack.deinit(gpa); } @@ -749,7 +805,91 @@ pub fn main(init: process.Init.Minimal) !void { maker.max_rss_is_default = true; } - maker.prepare(step_names.items) catch |err| switch (err) { + if (protocol_server) |s| { + try s.serveStringMessage(.bsp_configuration, try arena.print("{f}", .{scanned_config.path})); + + var w: ?Watch = null; + + const Event = union(enum) { + message: Reader.Error!Client.Message.Header, + fs_event: if (Watch.have_impl) @typeInfo(@TypeOf(Watch.wait)).@"fn".return_type.? else noreturn, + }; + + var select_buffer: [2]Event = undefined; + var select: Io.Select(Event) = .init(io, &select_buffer); + defer select.cancelDiscard(); + + try select.concurrent(.message, Server.receiveMessage, .{s}); + + var in_debounce = false; + loop: switch (try select.await()) { + .message => |payload| { + const header: Client.Message.Header = try payload; + switch (header.tag) { + .exit => { + cleanExit(io, &scanned_config); + process.exit(0); + }, + .bsp_build_steps => { + // Cancel existing file watching + select.cancelDiscard(); + in_debounce = false; + + const body = try s.in.takeStruct(Client.Message.BuildSteps, .little); + const steps = try s.in.readSliceEndianAlloc(gpa, Configuration.Step.Index, body.step_count, .little); + defer gpa.free(steps); + if (body.flags.watch and !Watch.have_impl) fatal("file watching is unavailable", .{}); + + try select.concurrent(.message, Server.receiveMessage, .{s}); + + maker.watch = body.flags.watch; + maker.prepare(steps) catch |err| switch (err) { + error.DependencyLoopDetected, error.InsufficientMemory => { + // TODO handle DependencyLoopDetected as error.FailedButCacheIntact + // and handle InsufficientMemory as error.AlreadyReported + _ = io.lockStderr(&.{}, graph.stderr_mode) catch {}; + process.exit(1); + }, + else => |e| return e, + }; + + try maker.makeSteps(main_progress_node, null); + + if (body.flags.watch) { + if (!Watch.have_impl) unreachable; + if (w == null) w = try .init(&maker); + + try w.?.update(maker.step_stack.keys()); + try select.concurrent(.fs_event, Watch.wait, .{ &w.?, if (in_debounce) .{ .ms = debounce_interval_ms } else .none }); + } + + continue :loop try select.await(); + }, + else => fatal("unsupported message: {t}", .{header.tag}), + } + }, + .fs_event => |payload| { + if (!Watch.have_impl) unreachable; + switch (try payload) { + .timeout => { + assert(in_debounce); + markFailedStepsDirty(&maker); + try maker.makeSteps(main_progress_node, null); + in_debounce = false; + }, + .dirty => in_debounce = true, + .clean => {}, + } + try select.concurrent(.fs_event, Watch.wait, .{ &w.?, if (in_debounce) .{ .ms = debounce_interval_ms } else .none }); + continue :loop try select.await(); + }, + } + } + + const initial_steps = try maker.resolveTopLevelSteps(step_names.items); + defer gpa.free(initial_steps); + + maker.prepare(initial_steps) catch |err| switch (err) { error.DependencyLoopDetected, error.InsufficientMemory => { // TODO handle DependencyLoopDetected as error.FailedButCacheIntact // and handle InsufficientMemory as error.AlreadyReported @@ -774,18 +914,7 @@ pub fn main(init: process.Init.Minimal) !void { error.WriteFailed => return stderr.file_writer.err.?, }; }) { - if (web_server) |ws| ws.startBuild(); - - try maker.makeStepNames(step_names.items, main_progress_node, fuzz); - - if (web_server) |ws| { - if (fuzz) |mode| if (mode != .forever) fatal( - "error: limited fuzzing is not implemented yet for --webui", - .{}, - ); - - ws.finishBuild(.{ .fuzz = fuzz != null }); - } + try maker.makeSteps(main_progress_node, fuzz); if (web_server) |ws| { const c = &scanned_config.configuration; @@ -850,6 +979,9 @@ pub fn main(init: process.Init.Minimal) !void { _ = io.lockStderr(&.{}, graph.stderr_mode) catch {}; process.exit(1); } + if (protocol_server != null) { + fatal("(zig build system) TODO send error messages to client when build.zig compilation fails", .{}); + } if (watch and can_fs_watch) { fatal("(zig build system) TODO set up fs watching even when build.zig compilation fails", .{}); } else { @@ -1330,7 +1462,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { if (config_man) |man| for (configuration.path_deps) |path_dep| { switch (path_dep.flags.mode) { .directory => {}, // TODO - .contents => try man.addPathPost(confPathDepToCachePath(graph, &configuration, path_dep)), + .contents => try man.addPathPost(try confPathDepToCachePath(arena, graph, &configuration, path_dep)), .metadata => {}, // TODO } }; @@ -1433,7 +1565,6 @@ fn cmdFetch(gpa: Allocator, graph: *Graph, args: []const []const u8) !void { const color: Color = Color.settingFromEnvironment(environ_map); var opt_path_or_url: ?[]const u8 = null; - var override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map); var override_local_cache_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_CACHE_DIR.get(environ_map); var override_pkg_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_PKG_DIR.get(environ_map); var debug_hash: bool = false; @@ -1449,8 +1580,6 @@ fn cmdFetch(gpa: Allocator, graph: *Graph, args: []const []const u8) !void { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { try Io.File.stdout().writeStreamingAll(io, usage_fetch); return process.cleanExit(io); - } else if (mem.eql(u8, arg, "--global-cache-dir")) { - override_global_cache_dir = nextArgOrFatal(args, &arg_i); } else if (mem.eql(u8, arg, "--cache-dir")) { override_local_cache_dir = nextArgOrFatal(args, &arg_i); } else if (mem.eql(u8, arg, "--pkg-dir")) { @@ -1730,7 +1859,6 @@ const usage_fetch = \\ \\Options: \\ -h, --help Print this help and exit - \\ --global-cache-dir [path] Override path to global Zig cache directory \\ --cache-dir [path] Override path to local cache directory \\ --pkg-dir [path] Override path to local package directory \\ --debug-hash Print verbose hash information to stdout @@ -1991,7 +2119,7 @@ fn markFailedStepsDirty(maker: *Maker) void { for (all_steps) |step_index| { const step = maker.stepByIndex(step_index); switch (step.state) { - .dependency_failure, .failure, .skipped => _ = maker.invalidateResult(step), + .dependency_failure, .dependency_skipped, .failure, .skipped => _ = maker.invalidateResult(step), else => continue, } } @@ -2020,11 +2148,37 @@ pub fn stepByIndex(maker: *const Maker, i: Configuration.Step.Index) *Step { return &maker.steps[@backingInt(i)]; } -fn prepare(maker: *Maker, step_names: []const []const u8) !void { +fn resolveTopLevelSteps(maker: *Maker, step_names: []const []const u8) ![]const Configuration.Step.Index { + const gpa = maker.gpa; + const c = &maker.scanned_config.configuration; + + if (step_names.len == 0) { + return try gpa.dupe(Configuration.Step.Index, &.{c.default_step}); + } + + var result: std.array_hash_map.Auto(Configuration.Step.Index, void) = .empty; + defer result.deinit(gpa); + + try result.ensureTotalCapacity(gpa, step_names.len); + + for (0..step_names.len) |i| { + const step_name = step_names[step_names.len - i - 1]; + const s = maker.scanned_config.top_level_steps.get(step_name) orelse { + log.info("to list available steps: zig build -l", .{}); + fatal("no such step: {s}", .{step_name}); + }; + result.putAssumeCapacity(s, {}); + } + + return try gpa.dupe(Configuration.Step.Index, result.keys()); +} + +fn prepare(maker: *Maker, step_indices: []const Configuration.Step.Index) !void { const gpa = maker.gpa; const graph = maker.graph; const arena = graph.arena; const seed: u32 = graph.random_seed; + const initial_steps = &maker.initial_steps; const step_stack = &maker.step_stack; const c = &maker.scanned_config.configuration; @@ -2033,18 +2187,15 @@ fn prepare(maker: *Maker, step_names: []const []const u8) !void { step.* = .{ .extended = .init(step_index.ptr(c).flags(c).tag) }; } - if (step_names.len == 0) { - try step_stack.put(gpa, c.default_step, {}); - } else { - try step_stack.ensureUnusedCapacity(gpa, step_names.len); - for (0..step_names.len) |i| { - const step_name = step_names[step_names.len - i - 1]; - const s = maker.scanned_config.top_level_steps.get(step_name) orelse { - log.info("to list available steps: zig build -l", .{}); - fatal("no such step: {s}", .{step_name}); - }; - step_stack.putAssumeCapacity(s, {}); - } + try initial_steps.ensureUnusedCapacity(gpa, step_indices.len); + try step_stack.ensureUnusedCapacity(gpa, step_indices.len); + + initial_steps.clearRetainingCapacity(); + step_stack.clearRetainingCapacity(); + + for (step_indices) |step| { + initial_steps.putAssumeCapacity(step, {}); + step_stack.putAssumeCapacity(step, {}); } const starting_steps = try arena.dupe(Configuration.Step.Index, step_stack.keys()); @@ -2085,6 +2236,7 @@ fn prepare(maker: *Maker, step_names: []const []const u8) !void { } } if (any_problems) { + log.info("use --skip-oom-steps to proceed, skipping memory limited steps", .{}); if (maker.max_rss_is_default) { log.info("use --maxrss {d} to proceed, risking system memory exhaustion", .{max_needed}); } @@ -2093,9 +2245,8 @@ fn prepare(maker: *Maker, step_names: []const []const u8) !void { } } -fn makeStepNames( +fn makeSteps( maker: *Maker, - step_names: []const []const u8, parent_progress_node: std.Progress.Node, fuzz: ?Fuzz.Mode, ) !void { @@ -2106,6 +2257,12 @@ fn makeStepNames( const top_level_steps = &maker.scanned_config.top_level_steps; const c = &maker.scanned_config.configuration; + if (maker.web_server) |ws| ws.startBuild(); + + if (maker.protocol_server) |s| { + try s.serveBodylessMessage(.bsp_build_started); + } + { // Collect the initial set of tasks (those with no outstanding dependencies) into a buffer, // then spawn them. The buffer is so that we don't race with `makeStep` and end up thinking @@ -2131,6 +2288,19 @@ fn makeStepNames( try group.await(io); } + if (maker.web_server) |ws| { + if (fuzz) |mode| if (mode != .forever) fatal( + "error: limited fuzzing is not implemented yet for --webui", + .{}, + ); + + ws.finishBuild(.{ .fuzz = fuzz != null }); + } + + if (maker.protocol_server) |s| { + try s.serveBodylessMessage(.bsp_build_completed); + } + assert(maker.memory_blocked_steps.items.len == 0); var test_pass_count: usize = 0; @@ -2164,7 +2334,7 @@ fn makeStepNames( .precheck_unstarted => unreachable, .precheck_started => unreachable, .precheck_done => unreachable, - .dependency_failure => pending_count += 1, + .dependency_failure, .dependency_skipped => pending_count += 1, .success => success_count += 1, .skipped, .skipped_oom => skipped_count += 1, .failure => { @@ -2283,7 +2453,7 @@ fn makeStepNames( defer step_stack_copy.deinit(gpa); var print_node: PrintNode = .{ .parent = null }; - if (step_names.len == 0) { + if (maker.initial_steps.count() == 0) { print_node.last = true; printTreeStep(maker, c.default_step, t, &print_node, &step_stack_copy) catch |err| switch (err) { error.Canceled => |e| return e, @@ -2291,10 +2461,10 @@ fn makeStepNames( }; } else { const last_index = if (maker.summary == .all) top_level_steps.count() else blk: { - var i: usize = step_names.len; + var i: usize = maker.initial_steps.count(); while (i > 0) { i -= 1; - const step_index = top_level_steps.get(step_names[i]).?; + const step_index = maker.initial_steps.keys()[i]; const step = maker.stepByIndex(step_index); const found = switch (maker.summary) { .all, .line, .none => unreachable, @@ -2305,8 +2475,7 @@ fn makeStepNames( } break :blk top_level_steps.count(); }; - for (step_names, 0..) |step_name, i| { - const step_index = top_level_steps.get(step_name).?; + for (maker.initial_steps.keys(), 0..) |step_index, i| { print_node.last = i + 1 == last_index; printTreeStep(maker, step_index, t, &print_node, &step_stack_copy) catch |err| switch (err) { error.Canceled => |e| return e, @@ -2317,7 +2486,7 @@ fn makeStepNames( w.writeByte('\n') catch {}; } - if (maker.watch or maker.web_server != null) return; + if (maker.watch or maker.web_server != null or maker.protocol_server != null) return; const code: u8 = code: { if (failure_count == 0) break :code 0; // success @@ -2392,6 +2561,15 @@ fn makeStep( defer step_prog_node.end(); if (maker.web_server) |ws| ws.updateStepStatus(step_index, .wip); + if (maker.protocol_server) |s| { + maker.protocol_server_mutex.lockUncancelable(io); + defer maker.protocol_server_mutex.unlock(io); + + s.serveU32Message( + .bsp_step_started, + @backingInt(step_index), + ) catch @panic("TODO propagate error when failing to send protocol message"); + } const new_state: Step.State = for (deps) |dep_index| { const dep_make_step = maker.stepByIndex(dep_index); @@ -2402,10 +2580,14 @@ fn makeStep( .failure, .dependency_failure, - .skipped_oom, => break .dependency_failure, - .success, .skipped => {}, + .dependency_skipped, + .skipped_oom, + .skipped, + => break .dependency_skipped, + + .success => {}, } } else if (Step.make(step_index, maker, step_prog_node)) state: { break :state .success; @@ -2417,25 +2599,46 @@ fn makeStep( @atomicStore(Step.State, &make_step.state, new_state, .monotonic); - switch (new_state) { + const success = switch (new_state) { .precheck_unstarted => unreachable, .precheck_started => unreachable, .precheck_done => unreachable, .failure, .dependency_failure, + .dependency_skipped, .skipped_oom, - => { - if (maker.web_server) |ws| ws.updateStepStatus(step_index, .failure); - std.Progress.setStatus(.failure_working); - }, - - .success, .skipped, - => { - if (maker.web_server) |ws| ws.updateStepStatus(step_index, .success); - }, + => false, + + .success, + => true, + }; + + if (maker.web_server) |ws| { + ws.updateStepStatus(step_index, if (success) .success else .failure); } + if (maker.protocol_server != null) { + maker.protocol_server_mutex.lockUncancelable(io); + defer maker.protocol_server_mutex.unlock(io); + + const status: Server.Message.BuildStepCompleted.Status = switch (new_state) { + .precheck_unstarted => unreachable, + .precheck_started => unreachable, + .precheck_done => unreachable, + .success => .success, + .failure, .dependency_failure => .failure, + .dependency_skipped, .skipped => .skipped, + .skipped_oom => .skipped_oom, + }; + serveBuildStepCompleted( + maker, + step_index, + status, + ) catch |err| std.debug.panic("TODO propagate error when failing to send protocol message: {t}", .{err}); + } + + if (!success) std.Progress.setStatus(.failure_working); } // No matter the result, we want to display error/warning messages. @@ -2468,7 +2671,7 @@ fn makeStep( maker.available_rss += max_rss; dispatch_set.ensureUnusedCapacity(gpa, maker.memory_blocked_steps.items.len) catch @panic("TODO eliminate memory allocation here"); - while (maker.memory_blocked_steps.getLast()) |candidate_index| { + while (maker.memory_blocked_steps.last()) |candidate_index| { const candidate_max_rss = candidate_index.ptr(c).max_rss.toBytes(); if (maker.available_rss < candidate_max_rss) break; assert(maker.memory_blocked_steps.pop() == candidate_index); @@ -2579,6 +2782,12 @@ fn printStepStatus(maker: *Maker, step_index: Configuration.Step.Index, stderr: try stderr.setColor(.reset); }, + .dependency_skipped => { + try stderr.setColor(.dim); + try writer.writeAll(" transitive skip\n"); + try stderr.setColor(.reset); + }, + .success => { try stderr.setColor(.green); if (s.result_cached) { @@ -2825,6 +3034,7 @@ fn constructGraphAndCheckForDependencyLoop( // These don't happen until we actually run the step graph. .dependency_failure => unreachable, + .dependency_skipped => unreachable, .success => unreachable, .failure => unreachable, .skipped => unreachable, @@ -2912,7 +3122,7 @@ pub fn printErrorMessages( try stderr.setColor(.red); try writer.writeAll("error:"); try stderr.setColor(.reset); - if (std.mem.indexOfScalar(u8, msg, '\n') == null) { + if (std.mem.findScalar(u8, msg, '\n') == null) { try writer.print(" {s}\n", .{msg}); } else switch (multiline_errors) { .indent => { @@ -2990,6 +3200,50 @@ fn cleanTmpFiles(maker: *Maker, steps: []const Configuration.Step.Index) void { } } +fn serveBSPHandshake(s: *const std.zig.Server) !void { + const handshake_header: Server.Message.Handshake = .{ + .version = Server.build_system_version, + .flags = .{ + .file_system_watch_supported = Watch.have_impl, + }, + }; + try s.serveMessageHeader(.{ + .tag = .bsp_handshake, + .bytes_len = @sizeOf(Server.Message.Handshake), + }); + try s.out.writeStruct(handshake_header, .little); + try s.out.flush(); +} + +fn serveBuildStepCompleted( + maker: *Maker, + step_index: Configuration.Step.Index, + status: Server.Message.BuildStepCompleted.Status, +) !void { + const s: *Server = maker.protocol_server.?; + const step = maker.stepByIndex(step_index); + const error_bundle = step.result_error_bundle; + + const body: Server.Message.BuildStepCompleted = .{ + .step_index = step_index, + .status = status, + .error_bundle = .{ + .extra_len = @intCast(error_bundle.extra.len), + .string_bytes_len = @intCast(error_bundle.string_bytes.len), + }, + }; + const eb_bytes_len = @sizeOf(u32) * error_bundle.extra.len + error_bundle.string_bytes.len; + const bytes_len = @sizeOf(Server.Message.BuildStepCompleted) + eb_bytes_len; + try s.serveMessageHeader(.{ + .tag = .bsp_step_completed, + .bytes_len = @intCast(bytes_len), + }); + try s.out.writeStruct(body, .little); + try s.out.writeSliceEndian(u32, error_bundle.extra, .little); + try s.out.writeAll(error_bundle.string_bytes); + try s.out.flush(); +} + fn initStdoutWriter(io: Io) *Writer { stdout_writer_allocation = Io.File.stdout().writerStreaming(io, &stdio_buffer_allocation); return &stdout_writer_allocation.interface; @@ -3071,17 +3325,19 @@ pub fn packagePath( ) Allocator.Error!Path { const c = &maker.scanned_config.configuration; const graph = maker.graph; - const package = package_index.get(c) orelse return .{ + + if (package_index == .root) return .{ .root_dir = graph.build_root_directory, .sub_path = sub_path, }; + // Currently, neither configurer nor Maker is aware of the standard zig // package path, and the root path is stored as a bare string rather than // relative to a known base directory. Without changing that, we must // construct a cwd relative path here. return .{ .root_dir = .cwd(), - .sub_path = try Dir.path.join(arena, &.{ package.root_path.slice(c), sub_path }), + .sub_path = try Dir.path.join(arena, &.{ package_index.ptr(c).root_path.slice(c), sub_path }), }; } @@ -3687,7 +3943,12 @@ const Templates = struct { } }; -fn confPathDepToCachePath(graph: *const Graph, c: *const Configuration, path_dep: Configuration.PathDep) Path { +fn confPathDepToCachePath( + arena: Allocator, + graph: *const Graph, + c: *const Configuration, + path_dep: Configuration.PathDep, +) Allocator.Error!Path { const sub_path = path_dep.sub.slice(c); return switch (path_dep.flags.base) { .cwd => .{ @@ -3703,11 +3964,11 @@ fn confPathDepToCachePath(graph: *const Graph, c: *const Configuration, path_dep .sub_path = sub_path, }, .build_root => .{ - .root_dir = switch (path_dep.pkg.unwrap().?) { - .root => graph.build_root_directory, - _ => @panic("TODO"), + .root_dir = graph.build_root_directory, + .sub_path = switch (path_dep.pkg.unwrap().?) { + .root => sub_path, + else => |index| try Dir.path.join(arena, &.{ index.ptr(c).root_path.slice(c), sub_path }), }, - .sub_path = sub_path, }, .zig_lib => .{ .root_dir = graph.zig_lib_directory, diff --git a/lib/compiler/Maker/Fetch.zig b/lib/compiler/Maker/Fetch.zig index 5b5c6f7ff4385ca7cb4d45adcd0233feb24e1bff..13a6cd08c00b72fbf9493ff5acea1631d2542d6a 100644 --- a/lib/compiler/Maker/Fetch.zig +++ b/lib/compiler/Maker/Fetch.zig @@ -1164,7 +1164,7 @@ const FileType = enum { if (cd_header[value_start] != '=') return null; value_start += 1; - var value_end = std.mem.indexOfPos(u8, cd_header, value_start, ";") orelse cd_header.len; + var value_end = std.mem.findPos(u8, cd_header, value_start, ";") orelse cd_header.len; if (cd_header[value_end - 1] == '\"') { value_end -= 1; } @@ -1344,7 +1344,7 @@ fn unpackResource( return f.fail(f.location_tok, try eb.addString("missing 'Content-Type' header")); // Extract the MIME type, ignoring charset and boundary directives - const mime_type_end = std.mem.indexOf(u8, content_type, ";") orelse content_type.len; + const mime_type_end = std.mem.find(u8, content_type, ";") orelse content_type.len; const mime_type = content_type[0..mime_type_end]; if (ascii.eqlIgnoreCase(mime_type, "application/x-tar")) @@ -1455,7 +1455,7 @@ fn unpackTarball(f: *Fetch, out_dir: Io.Dir, reader: *Io.Reader) RunError!Unpack var diagnostics: std.tar.Diagnostics = .{ .allocator = arena }; - std.tar.pipeToFileSystem(io, out_dir, reader, .{ + std.tar.extract(io, out_dir, reader, .{ .diagnostics = &diagnostics, .strip_components = 0, .mode_mode = .ignore, diff --git a/lib/compiler/Maker/Fetch/git.zig b/lib/compiler/Maker/Fetch/git.zig index 2e040a81fe68c09eede82fac6ece736efe44cc60..89f5bb6d86f4ef592bb42bbe7584fb2e06863da4 100644 --- a/lib/compiler/Maker/Fetch/git.zig +++ b/lib/compiler/Maker/Fetch/git.zig @@ -336,7 +336,7 @@ pub const Repository = struct { fn next(iterator: *TreeIterator) !?Entry { if (iterator.pos == iterator.data.len) return null; - const mode_end = mem.indexOfScalarPos(u8, iterator.data, iterator.pos, ' ') orelse return error.InvalidTree; + const mode_end = mem.findScalarPos(u8, iterator.data, iterator.pos, ' ') orelse return error.InvalidTree; const mode: packed struct { permission: u9, unused: u3, @@ -351,7 +351,7 @@ pub const Repository = struct { }; iterator.pos = mode_end + 1; - const name_end = mem.indexOfScalarPos(u8, iterator.data, iterator.pos, 0) orelse return error.InvalidTree; + const name_end = mem.findScalarPos(u8, iterator.data, iterator.pos, 0) orelse return error.InvalidTree; const name = iterator.data[iterator.pos..name_end :0]; iterator.pos = name_end + 1; @@ -823,7 +823,7 @@ pub const Session = struct { value: ?[]const u8 = null, fn parse(data: []const u8) Capability { - return if (mem.indexOfScalar(u8, data, '=')) |separator_pos| + return if (mem.findScalar(u8, data, '=')) |separator_pos| .{ .key = data[0..separator_pos], .value = data[separator_pos + 1 ..] } else .{ .key = data }; @@ -941,17 +941,17 @@ pub const Session = struct { .flush => return null, .data => |data| { const ref_data = Packet.normalizeText(data); - const oid_sep_pos = mem.indexOfScalar(u8, ref_data, ' ') orelse return error.InvalidRefPacket; + const oid_sep_pos = mem.findScalar(u8, ref_data, ' ') orelse return error.InvalidRefPacket; const oid = Oid.parse(it.format, data[0..oid_sep_pos]) catch return error.InvalidRefPacket; - const name_sep_pos = mem.indexOfScalarPos(u8, ref_data, oid_sep_pos + 1, ' ') orelse ref_data.len; + const name_sep_pos = mem.findScalarPos(u8, ref_data, oid_sep_pos + 1, ' ') orelse ref_data.len; const name = ref_data[oid_sep_pos + 1 .. name_sep_pos]; var symref_target: ?[]const u8 = null; var peeled: ?Oid = null; var last_sep_pos = name_sep_pos; while (last_sep_pos < ref_data.len) { - const next_sep_pos = mem.indexOfScalarPos(u8, ref_data, last_sep_pos + 1, ' ') orelse ref_data.len; + const next_sep_pos = mem.findScalarPos(u8, ref_data, last_sep_pos + 1, ' ') orelse ref_data.len; const attribute = ref_data[last_sep_pos + 1 .. next_sep_pos]; if (mem.startsWith(u8, attribute, "symref-target:")) { symref_target = attribute["symref-target:".len..]; diff --git a/lib/compiler/Maker/PkgConfig.zig b/lib/compiler/Maker/PkgConfig.zig index 5ef34a8fbce44001dc822d37d55f11fd1a636e48..a16efae4bd60b0bf89cddef23fd99e9af304e5b6 100644 --- a/lib/compiler/Maker/PkgConfig.zig +++ b/lib/compiler/Maker/PkgConfig.zig @@ -63,6 +63,8 @@ pub fn run( } } + step.clearFailedCommand(maker.gpa); + return parsed; } diff --git a/lib/compiler/Maker/ScannedConfig.zig b/lib/compiler/Maker/ScannedConfig.zig index ead8acf064021af8ad3f4a344657189f4977fb14..168ae8b7f61ec27abf36a4d46c2e675e982b0061 100644 --- a/lib/compiler/Maker/ScannedConfig.zig +++ b/lib/compiler/Maker/ScannedConfig.zig @@ -12,10 +12,6 @@ top_level_steps: std.array_hash_map.String(Configuration.Step.Index), path: std.Build.Cache.Path, pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void { - std.log.err("TODO also print paths", .{}); - std.log.err("TODO also print unlazy deps", .{}); - std.log.err("TODO also print system integrations", .{}); - std.log.err("TODO also print available options", .{}); const c = &sc.configuration; var serializer: Serializer = .{ .writer = w }; var s = try serializer.beginStruct(.{}); @@ -45,6 +41,69 @@ pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void { try tf.end(); } + { + var tf = try s.beginTupleField("path_deps", .{}); + for (c.path_deps) |path_dep| { + var sf = try tf.beginStructField(.{}); + try sf.field("base", @tagName(path_dep.flags.base), .{}); + try sf.field("sub", path_dep.sub.slice(c), .{}); + try sf.end(); + } + try tf.end(); + } + + { + var tf = try s.beginTupleField("unlazy_deps", .{}); + for (c.unlazy_deps) |dep| { + try tf.field(dep.slice(c), .{}); + } + try tf.end(); + } + + { + var tf = try s.beginTupleField("system_integrations", .{}); + for (c.system_integrations) |opt| { + var sf = try tf.beginStructField(.{}); + try sf.field("name", opt.name.slice(c), .{}); + try sf.field("status", opt.status, .{}); + try sf.end(); + } + try tf.end(); + } + + { + var tf = try s.beginTupleField("available_options", .{}); + for (c.available_options) |opt| { + var sf = try tf.beginStructField(.{}); + try sf.field("name", opt.name.slice(c), .{}); + try sf.field("description", opt.description.slice(c), .{}); + try sf.field("type", @tagName(opt.type), .{}); + try sf.end(); + } + try tf.end(); + } + + { + var tf = try s.beginTupleField("packages", .{}); + for (c.packages) |package| { + var sf = try tf.beginStructField(.{}); + try sf.field("dep_prefix", package.dep_prefix.slice(c), .{}); + try sf.field("hash", package.hash.slice(c), .{}); + try sf.field("root_path", package.root_path.slice(c), .{}); + + var dtf = try sf.beginTupleField("deps", .{}); + for (package.deps.slice(c)) |dep| { + var dsf = try dtf.beginStructField(.{}); + try sc.printStruct(&dsf, Configuration.Package.Dep, dep); + try dsf.end(); + } + try dtf.end(); + + try sf.end(); + } + try tf.end(); + } + try s.end(); } @@ -341,7 +400,6 @@ pub fn printUsage(sc: *const ScannedConfig, graph: *Graph, w: *Writer) !void { \\ --error-limit [num] Set the maximum amount of distinct error values \\ --build-file [file] Override path to build.zig \\ --cache-dir [path] Override path to local Zig cache directory - \\ --global-cache-dir [path] Override path to global Zig cache directory \\ --zig-lib=[arg] Override path to Zig lib directory \\ --seed [integer] For shuffling dependency traversal order (default: random) \\ --cache-poison[=mode] Override configuration caching behavior diff --git a/lib/compiler/Maker/Step.zig b/lib/compiler/Maker/Step.zig index 812613928eaa9134dd249e4fc2ece38065cad01c..181cdf2bd75fc678fc45d72cbab16a9e9bbeecd1 100644 --- a/lib/compiler/Maker/Step.zig +++ b/lib/compiler/Maker/Step.zig @@ -163,6 +163,9 @@ pub const State = enum { /// be re-evaluated. precheck_done, dependency_failure, + /// Handled exactly the same as `dependency_failure` except communicates + /// that the dependency didn't fail but rather was skipped. + dependency_skipped, success, failure, /// This state indicates that the step did not complete, however, it also did not fail, @@ -561,24 +564,26 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi var result: ?Path = null; var eos_err: error{EndOfStream}!void = {}; - const stdout = zp.multi_reader.fileReader(0); + var client: std.zig.Client = .{ + .in = zp.multi_reader.reader(0), + .out = undefined, + }; while (true) { - const Header = std.zig.Server.Message.Header; - const header = stdout.interface.takeStruct(Header, .little) catch |err| switch (err) { - error.EndOfStream => break, - error.ReadFailed => return stdout.err.?, - }; - const body = stdout.interface.take(header.bytes_len) catch |err| switch (err) { + const header = client.receiveMessageWithMultiReader(&zp.multi_reader, .none) catch |err| switch (err) { + error.Timeout => unreachable, error.EndOfStream => |e| { + if (client.in.bufferedLen() == 0) break; // Better to report the crash with stderr below, but we set // this in case the child exits successfully while violating // this protocol. eos_err = e; break; }, - error.ReadFailed => return stdout.err.?, + else => |e| return e, }; + const body = client.in.take(header.bytes_len) catch unreachable; + switch (header.tag) { .zig_version => { if (!std.mem.eql(u8, builtin.zig_version_string, body)) { diff --git a/lib/compiler/Maker/Step/Compile.zig b/lib/compiler/Maker/Step/Compile.zig index adf88b9f1baef3712b1d6ca707d4bed7db25e700..c487966999ca178d88b83332b0f953baa410a52e 100644 --- a/lib/compiler/Maker/Step/Compile.zig +++ b/lib/compiler/Maker/Step/Compile.zig @@ -215,8 +215,8 @@ fn lowerZigArgs( try addBool(gpa, zig_args, "-ffuzz", fuzz); { - var is_linking_libc = conf_comp.flags3.is_linking_libc; - var is_linking_libcpp = conf_comp.flags3.is_linking_libcpp; + var is_linking_libc = false; + var is_linking_libcpp = false; // Stores system libraries that have already been seen for at least one // module, along with any C compiler arguments that need to be passed diff --git a/lib/compiler/Maker/Step/ConfigHeader.zig b/lib/compiler/Maker/Step/ConfigHeader.zig index 2863ced63f5f96def9a22d8870f35e999a021a7f..20152955fe469b751648032e54152a7aa2b53f67 100644 --- a/lib/compiler/Maker/Step/ConfigHeader.zig +++ b/lib/compiler/Maker/Step/ConfigHeader.zig @@ -93,6 +93,32 @@ pub fn make( else => |e| return e, }; }, + .meson => { + const tf = template_file.?; + const contents = tf.root_dir.handle.readFileAlloc( + io, + tf.sub_path, + arena, + input_size_limit, + ) catch |err| return step.fail( + maker, + "unable to read meson input file {f}: {t}", + .{ tf, err }, + ); + + renderMeson( + maker, + step, + contents, + &aw, + value_pairs, + &value_map, + tf, + ) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + else => |e| return e, + }; + }, .blank => { renderBlank(conf, &aw.writer, value_pairs, &value_map, include_path, include_guard_override) catch |err| switch (err) { error.WriteFailed => return error.OutOfMemory, @@ -370,6 +396,62 @@ fn renderCmake( if (any_errors) return error.MakeFailed; } +fn renderMeson( + maker: *Maker, + step: *Step, + contents: []const u8, + aw: *Writer.Allocating, + value_pairs: []const Value.Pair, + value_map: *const ValueMap, + src_path: Path, +) !void { + const w = &aw.writer; + const conf = &maker.scanned_config.configuration; + const newline = detectNewline(contents); + + try w.writeAll(c_generated_line); + try w.writeAll(newline); + + var any_errors = false; + var line_index: u32 = 0; + var line_it = std.mem.splitScalar(u8, contents, '\n'); + // https://mesonbuild.com/Configuration.html + while (line_it.next()) |raw_line| : (line_index += 1) { + const last_line = line_it.index == line_it.buffer.len; + const line = std.mem.trimEnd(u8, raw_line, "\r"); + + const old_len = aw.written().len; + expandVariablesMeson(w, conf, line, value_pairs, value_map) catch |err| switch (err) { + error.MissingToken => { + try step.addError(maker, "{f}:{d}: error: missing define name", .{ src_path, line_index + 1 }); + any_errors = true; + continue; + }, + error.MissingValue => { + const name = aw.written()[old_len..]; + defer aw.shrinkRetainingCapacity(old_len); + + try step.addError(maker, "{f}:{d}: error: unspecified config header value: {q}", .{ + src_path, line_index + 1, name, + }); + any_errors = true; + continue; + }, + else => { + try step.addError(maker, "{f}:{d}: unable to substitute variable: error: {t}", .{ + src_path, line_index + 1, err, + }); + any_errors = true; + continue; + }, + }; + if (!last_line) try w.writeAll(newline); + } + + try ensureAllValuesUsed(maker, step, value_map, src_path); + if (any_errors) return error.MakeFailed; +} + fn renderBlank( conf: *const Configuration, w: *Writer, @@ -432,6 +514,28 @@ fn renderValueC(conf: *const Configuration, w: *Writer, newline: []const u8, nam } } +fn renderValueMeson( + conf: *const Configuration, + w: *Writer, + name: []const u8, + value: Value.Index, +) !void { + switch (value.unpack(conf)) { + .undef => try w.print("/* #undef {s} */", .{name}), + .defined => try w.print("#define {s}", .{name}), + .bool => |b| { + if (b) { + try w.print("#define {s}", .{name}); + } else { + try w.print("#undef {s}", .{name}); + } + }, + inline .u64, .i64 => |int| try w.print("#define {s} {d}", .{ name, int }), + .ident => |ident| try w.print("#define {s} {s}", .{ name, ident }), + .string => |string| try w.print("#define {s} \"{f}\"", .{ name, std.zig.fmtString(string) }), + } +} + fn renderValueCIdent(w: *Writer, newline: []const u8, name: []const u8, ident: []const u8) Writer.Error!void { try w.print("#define {s}", .{name}); if (ident.len > 0) { @@ -628,3 +732,36 @@ fn expandVariablesCmake( return result.toOwnedSliceAssert(); } + +fn expandVariablesMeson( + w: *Writer, + conf: *const Configuration, + line: []const u8, + value_pairs: []const Value.Pair, + value_map: *const ValueMap, +) !void { + const mesondefine = "#mesondefine"; + if (std.mem.startsWith(u8, line, mesondefine)) { + const line_offset = mesondefine.len + 1; + if (line_offset > line.len) return error.MissingToken; + + var it = std.mem.tokenizeAny(u8, line[line_offset..], " \t\r"); + const name = it.next() orelse return error.MissingToken; + + const index = value_map.getIndex(name) orelse { + // Report the missing key to the caller. + try w.writeAll(name); + return error.MissingValue; + }; + + const value = value_pairs[index].index; + value_map.values()[index] = true; // Mark as used. + + try renderValueMeson(conf, w, name, value); + + // comments/any other text passthrough unaffected + return try w.writeAll(line[line_offset + name.len ..]); + } + + try expandVariablesAutoconfAt(w, line, conf, value_pairs, value_map); +} diff --git a/lib/compiler/Maker/Step/Run.zig b/lib/compiler/Maker/Step/Run.zig index b6fc911f01f8d25a27cf2f3829118accfe2f58ea..85087be4d06ff29c71eabebd303e9ba6077dd1f9 100644 --- a/lib/compiler/Maker/Step/Run.zig +++ b/lib/compiler/Maker/Step/Run.zig @@ -64,9 +64,9 @@ pub fn make( } } - for (conf_run.preopen_names.slice, conf_run.preopen_paths.slice) |name, path| { - man.hash.addBytesZ(name.slice(conf)); - const cwd_path = try maker.resolveLazyPathIndex(arena, path, run_index); + for (conf_run.preopens.slice) |preopen| { + man.hash.addBytesZ(preopen.name.slice(conf)); + const cwd_path = try maker.resolveLazyPathIndex(arena, preopen.path, run_index); man.hash.addBytes(try cwd_path.toString(arena)); } @@ -187,6 +187,11 @@ pub fn make( man.hash.addListOfBytes(run_args); } }, + .enable_darling => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_darling, arg.prefix.value, arg.suffix.value), + .enable_qemu => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_qemu, arg.prefix.value, arg.suffix.value), + .enable_rosetta => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_rosetta, arg.prefix.value, arg.suffix.value), + .enable_wasmtime => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_wasmtime, arg.prefix.value, arg.suffix.value), + .enable_wine => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value), } } @@ -351,6 +356,29 @@ pub fn make( step.clearFailedCommand(gpa); } +fn thirdPartyToggle( + man_hash: ?*Cache.HashHelper, + argv_list: *std.ArrayList([]const u8), + conf: *const Configuration, + setting: bool, + enable: ?Configuration.String, + disable: ?Configuration.String, +) void { + if (setting) { + if (enable) |string| { + const slice = string.slice(conf); + if (man_hash) |h| h.addBytesZ(slice); + argv_list.appendAssumeCapacity(slice); + } + } else { + if (disable) |string| { + const slice = string.slice(conf); + if (man_hash) |h| h.addBytesZ(slice); + argv_list.appendAssumeCapacity(slice); + } + } +} + /// Reads stdout of a Zig test process until a termination condition is reached: /// * A write fails, indicating the child unexpectedly closed stdin /// * A test (or a response from the test runner) times out @@ -384,13 +412,23 @@ fn waitZigTest( var sub_prog_node: ?std.Progress.Node = null; defer if (sub_prog_node) |n| n.end(); + const stdout = multi_reader.reader(0); + const stderr = multi_reader.reader(1); + + var stdin_writer = child.stdin.?.writerStreaming(io, &.{}); + + var client: std.zig.Client = .{ + .in = stdout, + .out = &stdin_writer.interface, + }; + if (opt_metadata.*) |*md| { // Previous unit test process died or was killed; we're continuing where it left off - requestNextTest(io, child.stdin.?, md, &sub_prog_node) catch |err| return .{ .write_failed = err }; + requestNextTest(&client, md, &sub_prog_node) catch |err| return .{ .write_failed = err }; } else { // Running unit tests normally run.fuzz_tests.clearRetainingCapacity(); - sendMessage(io, child.stdin.?, .query_test_metadata) catch |err| return .{ .write_failed = err }; + client.serveBodylessMessage(.query_test_metadata) catch |err| return .{ .write_failed = err }; } var active_test_index: ?u32 = null; @@ -410,10 +448,6 @@ fn waitZigTest( .raw = .fromNanoseconds(ns), } else null; - const stdout = multi_reader.reader(0); - const stderr = multi_reader.reader(1); - const Header = std.zig.Server.Message.Header; - while (true) { const timeout: Io.Timeout = t: { const opt_duration = if (active_test_index == null) response_timeout else test_timeout; @@ -421,46 +455,20 @@ fn waitZigTest( break :t .{ .deadline = last_update.addDuration(duration) }; }; - // This block is exited when `stdout` contains enough bytes for a `Header`. - header_ready: { - if (stdout.buffered().len >= @sizeOf(Header)) { - // We already have one, no need to poll! - break :header_ready; - } - - multi_reader.fill(64, timeout) catch |err| switch (err) { - error.Timeout => return .{ .timeout = .{ - .active_test_index = active_test_index, - .ns_elapsed = @intCast(last_update.untilNow(io).raw.nanoseconds), - } }, - error.EndOfStream => return .{ .no_poll = .{ - .active_test_index = active_test_index, - .ns_elapsed = @intCast(last_update.untilNow(io).raw.nanoseconds), - } }, - else => |e| return e, - }; - - continue; - } - // There is definitely a header available now -- read it. - const header = stdout.takeStruct(Header, .little) catch unreachable; - - while (stdout.buffered().len < header.bytes_len) { - multi_reader.fill(64, timeout) catch |err| switch (err) { - error.Timeout => return .{ .timeout = .{ - .active_test_index = active_test_index, - .ns_elapsed = @intCast(last_update.untilNow(io).raw.nanoseconds), - } }, - error.EndOfStream => return .{ .no_poll = .{ - .active_test_index = active_test_index, - .ns_elapsed = @intCast(last_update.untilNow(io).raw.nanoseconds), - } }, - else => |e| return e, - }; - } - - const body = stdout.take(header.bytes_len) catch unreachable; + const header = client.receiveMessageWithMultiReader(multi_reader, timeout) catch |err| switch (err) { + error.Timeout => return .{ .timeout = .{ + .active_test_index = active_test_index, + .ns_elapsed = @intCast(last_update.untilNow(io).raw.nanoseconds), + } }, + error.EndOfStream => return .{ .no_poll = .{ + .active_test_index = active_test_index, + .ns_elapsed = @intCast(last_update.untilNow(io).raw.nanoseconds), + } }, + else => |e| return e, + }; + const body = client.in.take(header.bytes_len) catch unreachable; var body_r: std.Io.Reader = .fixed(body); + switch (header.tag) { .zig_version => { if (!std.mem.eql(u8, builtin.zig_version_string, body)) return step.fail( @@ -500,7 +508,7 @@ fn waitZigTest( active_test_index = null; last_update = .now(io, .awake); - requestNextTest(io, child.stdin.?, &opt_metadata.*.?, &sub_prog_node) catch |err| return .{ .write_failed = err }; + requestNextTest(&client, &opt_metadata.*.?, &sub_prog_node) catch |err| return .{ .write_failed = err }; }, .test_started => { active_test_index = opt_metadata.*.?.next_index - 1; @@ -551,7 +559,7 @@ fn waitZigTest( md.ns_per_test[tr_hdr.index] = @intCast(last_update.durationTo(now).raw.nanoseconds); last_update = now; - requestNextTest(io, child.stdin.?, md, &sub_prog_node) catch |err| return .{ .write_failed = err }; + requestNextTest(&client, md, &sub_prog_node) catch |err| return .{ .write_failed = err }; }, else => {}, // ignore other messages } @@ -575,7 +583,7 @@ const FuzzTestRunner = struct { const Instance = struct { child: process.Child, - message: std.ArrayListAligned(u8, .@"4"), + message: std.array_list.Aligned(u8, .@"4"), broadcast_written: usize, stderr: std.ArrayList(u8), stdin_vec: [1][]u8, @@ -697,17 +705,18 @@ const FuzzTestRunner = struct { for (0.., f.instances) |id, *instance| { const id32: u32 = @intCast(id); + var writer = instance.child.stdin.?.writerStreaming(io, &.{}); + const client: std.zig.Client = .{ + .in = undefined, + .out = &writer.interface, + }; (switch (f.ctx.fuzz.mode) { - .forever => sendRunFuzzTestMessage( - io, - instance.child.stdin.?, + .forever => client.serveRunFuzzTestMessage( run.fuzz_tests.items, .forever, id32, ), - .limit => |limit| sendRunFuzzTestMessage( - io, - instance.child.stdin.?, + .limit => |limit| client.serveRunFuzzTestMessage( run.fuzz_tests.items, .iterations, limit.amount, @@ -1315,7 +1324,7 @@ pub const CachedTestMetadata = struct { } }; -fn requestNextTest(io: Io, in: Io.File, metadata: *TestMetadata, sub_prog_node: *?std.Progress.Node) !void { +fn requestNextTest(client: *std.zig.Client, metadata: *TestMetadata, sub_prog_node: *?std.Progress.Node) !void { while (metadata.next_index < metadata.names.len) { const i = metadata.next_index; metadata.next_index += 1; @@ -1326,76 +1335,11 @@ fn requestNextTest(io: Io, in: Io.File, metadata: *TestMetadata, sub_prog_node: if (sub_prog_node.*) |n| n.end(); sub_prog_node.* = metadata.prog_node.start(name, 0); - try sendRunTestMessage(io, in, .run_test, i); + try client.serveRunTest(i); return; } else { metadata.next_index = std.math.maxInt(u32); // indicate that all tests are done - try sendMessage(io, in, .exit); - } -} - -fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void { - const header: std.zig.Client.Message.Header = .{ - .tag = tag, - .bytes_len = 0, - }; - var w = file.writerStreaming(io, &.{}); - w.interface.writeStruct(header, .little) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; -} - -fn sendRunTestMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag, index: u32) !void { - const header: std.zig.Client.Message.Header = .{ - .tag = tag, - .bytes_len = 4, - }; - var w = file.writerStreaming(io, &.{}); - w.interface.writeStruct(header, .little) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; - w.interface.writeInt(u32, index, .little) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; -} - -fn sendRunFuzzTestMessage( - io: Io, - file: Io.File, - test_names: []const []const u8, - kind: std.Build.abi.fuzz.LimitKind, - amount_or_instance: u64, -) !void { - const header: std.zig.Client.Message.Header = .{ - .tag = .start_fuzzing, - .bytes_len = 1 + 8 + 4 + count: { - var c: u32 = @intCast(test_names.len * 4); - for (test_names) |name| { - c += @intCast(name.len); - } - break :count c; - }, - }; - var w = file.writerStreaming(io, &.{}); - w.interface.writeStruct(header, .little) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; - w.interface.writeByte(@backingInt(kind)) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; - w.interface.writeInt(u64, amount_or_instance, .little) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; - w.interface.writeInt(u32, @intCast(test_names.len), .little) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; - for (test_names) |test_name| { - w.interface.writeInt(u32, @intCast(test_name.len), .little) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; - w.interface.writeAll(test_name) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; + try client.serveBodylessMessage(.exit); } } @@ -1619,6 +1563,11 @@ pub fn rerunInFuzzMode( .output_file => unreachable, .output_directory => unreachable, .passthru => unreachable, + .enable_darling => thirdPartyToggle(null, &argv_list, conf, graph.enable_darling, arg.prefix.value, arg.suffix.value), + .enable_qemu => thirdPartyToggle(null, &argv_list, conf, graph.enable_qemu, arg.prefix.value, arg.suffix.value), + .enable_rosetta => thirdPartyToggle(null, &argv_list, conf, graph.enable_rosetta, arg.prefix.value, arg.suffix.value), + .enable_wasmtime => thirdPartyToggle(null, &argv_list, conf, graph.enable_wasmtime, arg.prefix.value, arg.suffix.value), + .enable_wine => thirdPartyToggle(null, &argv_list, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value), } } @@ -1917,14 +1866,14 @@ fn runCommand( }, .wasmtime => |bin_name| { if (graph.enable_wasmtime) { - try interp_argv.ensureUnusedCapacity(arena, 3 + argv.len + conf_run.preopen_names.slice.len); + try interp_argv.ensureUnusedCapacity(arena, 3 + argv.len + conf_run.preopens.slice.len); interp_argv.appendAssumeCapacity(bin_name); interp_argv.appendAssumeCapacity("--dir=."); - for (conf_run.preopen_names.slice, conf_run.preopen_paths.slice) |name, lazy_path| { - const path = try maker.resolveLazyPath(arena, lazy_path.get(conf), run_index); + for (conf_run.preopens.slice) |preopen| { + const path = try maker.resolveLazyPath(arena, preopen.path.get(conf), run_index); path.root_dir.handle.createDirPath(io, path.subPathOrDot()) catch |e| return step.fail(maker, "failed creating directory {f}: {t}", .{ path, e }); - interp_argv.appendAssumeCapacity(try arena.print("--dir={f}::{s}", .{ path, name.slice(conf) })); + interp_argv.appendAssumeCapacity(try arena.print("--dir={f}::{s}", .{ path, preopen.name.slice(conf) })); } // Wasmtime doeesn't inherit environment variables from the parent process // by default. '-S inherit-env' was added in Wasmtime version 20. @@ -2204,7 +2153,7 @@ fn fmtSnapshotIndicatorLine(buf: []const u8, index: usize) std.fmt.Alt( } fn snapshotIndicatorLine(line: FmtIndicatorLine, w: *std.Io.Writer) std.Io.Writer.Error!void { - const line_begin_index = if (std.mem.lastIndexOfScalar(u8, line.buf[0..line.index], '\n')) |line_begin| + const line_begin_index = if (std.mem.findScalarLast(u8, line.buf[0..line.index], '\n')) |line_begin| line_begin + 1 else 0; @@ -2285,25 +2234,35 @@ fn spawnChildAndCollect( assert(conf_run.flags.stdio != .inherit); break :s .pipe; } else switch (conf_run.flags.stdio) { - .infer_from_args => if (has_side_effects) .inherit else .ignore, + .infer_from_args => if (maker.protocol_server == null and has_side_effects) .inherit else .ignore, .inherit => .inherit, .check => .ignore, .zig_test => .pipe, }, .stdout = if (conf_run.captured_stdout.value != null) .pipe else switch (conf_run.flags.stdio) { - .infer_from_args => if (has_side_effects) .inherit else .ignore, + .infer_from_args => if (maker.protocol_server == null and has_side_effects) .inherit else .ignore, .inherit => .inherit, .check => if (checksContainStdout(&conf_run)) .pipe else .ignore, .zig_test => .pipe, }, .stderr = if (conf_run.captured_stderr.value != null) .pipe else switch (conf_run.flags.stdio) { - .infer_from_args => if (has_side_effects) .inherit else .pipe, - .inherit => .inherit, + .infer_from_args => if (maker.protocol_server == null and has_side_effects) .inherit else .pipe, + .inherit => if (maker.protocol_server == null) .inherit else .pipe, .check => .pipe, .zig_test => .pipe, }, }; + if (maker.protocol_server != null) { + if (spawn_options.stdin == .inherit) { + return step.fail(maker, "Cannot inherit stdin when running through over the build system protocol", .{}); + } + if (spawn_options.stdout == .inherit) { + return step.fail(maker, "Cannot inherit stdout when running through over the build system protocol", .{}); + } + assert(spawn_options.stderr != .inherit); + } + if (conf_run.flags.stdio == .zig_test) { try setColorEnvironmentVariables(&conf_run, environ_map, graph.stderr_mode.?); const started: Io.Clock.Timestamp = .now(io, .awake); diff --git a/lib/compiler/Maker/Step/TranslateC.zig b/lib/compiler/Maker/Step/TranslateC.zig index 94b90d65dc9a8ec48871d945924cb0e4461e80f4..79b8571ba6bfef3474ac68e2036f9bdbd1c2f5f8 100644 --- a/lib/compiler/Maker/Step/TranslateC.zig +++ b/lib/compiler/Maker/Step/TranslateC.zig @@ -49,9 +49,9 @@ pub fn make( const opt: ?OptimizeMode = switch (conf_tc.flags.optimize) { .debug, .default => null, // Skip since it's the default - .safe => .ReleaseSafe, - .fast => .ReleaseFast, - .small => .ReleaseSmall, + .safe => .safe, + .fast => .fast, + .small => .small, }; if (opt) |o| argv.appendAssumeCapacity(try arena.print("-O{t}", .{o})); diff --git a/lib/compiler/Maker/WebServer.zig b/lib/compiler/Maker/WebServer.zig index e47f18bb5f786aba032d64dc37f806200f15636c..1064519adc547a78c26bafc23351a640367178f5 100644 --- a/lib/compiler/Maker/WebServer.zig +++ b/lib/compiler/Maker/WebServer.zig @@ -501,7 +501,7 @@ fn serveRequest(ws: *WebServer, req: *http.Server.Request) !void { if (mem.eql(u8, target, "/main.js")) return serveLibFile(ws, req, "build-web/main.js", "application/javascript"); if (mem.eql(u8, target, "/style.css")) return serveLibFile(ws, req, "build-web/style.css", "text/css"); if (mem.eql(u8, target, "/time_report.css")) return serveLibFile(ws, req, "build-web/time_report.css", "text/css"); - if (mem.eql(u8, target, "/main.wasm")) return serveClientWasm(ws, req, if (debug) .Debug else .ReleaseFast); + if (mem.eql(u8, target, "/main.wasm")) return serveClientWasm(ws, req, if (debug) .debug else .fast); if (ws.fuzz) |*fuzz| { if (mem.eql(u8, target, "/sources.tar")) return fuzz.serveSourcesTar(req); diff --git a/lib/compiler/aro/aro/Compilation.zig b/lib/compiler/aro/aro/Compilation.zig index d25154248e48cb68a2a07cca639d13942c61ec81..932b09a088a70e91a7838d5e75ad3be0ba174833 100644 --- a/lib/compiler/aro/aro/Compilation.zig +++ b/lib/compiler/aro/aro/Compilation.zig @@ -1601,6 +1601,7 @@ pub fn addSourceFromOwnedBuffer(comp: *Compilation, path: []const u8, buf: []u8, var list: std.ArrayList(u8) = .{ .items = contents[0..i], .capacity = contents.len, + .pointer_stability = .{}, }; contents = try list.toOwnedSlice(comp.gpa); } diff --git a/lib/compiler/aro/aro/Diagnostics.zig b/lib/compiler/aro/aro/Diagnostics.zig index e2cd09c19f952da6c3e9507011443efea189cb5a..7bfa8be6efbdf7cb4af49d683e67bd2ab86fc068 100644 --- a/lib/compiler/aro/aro/Diagnostics.zig +++ b/lib/compiler/aro/aro/Diagnostics.zig @@ -510,7 +510,7 @@ pub fn formatArgs(w: *std.Io.Writer, fmt: []const u8, args: anytype) std.Io.Writ pub fn templateIndex(w: *std.Io.Writer, fmt: []const u8, template: []const u8) std.Io.Writer.Error!usize { const i = std.mem.indexOf(u8, fmt, template) orelse { - if (@import("builtin").mode == .Debug) { + if (@import("builtin").mode == .debug) { std.debug.panic("template `{s}` not found in format string `{s}`", .{ template, fmt }); } try w.print("template `{s}` not found in format string `{s}` (this is a bug in arocc)", .{ template, fmt }); diff --git a/lib/compiler/aro/aro/Target.zig b/lib/compiler/aro/aro/Target.zig index 3a871504700f666b6e74ca464d37c0770568c43d..a0c9f3be3943810313dfcd94b94f6bea0794ff2d 100644 --- a/lib/compiler/aro/aro/Target.zig +++ b/lib/compiler/aro/aro/Target.zig @@ -1559,15 +1559,15 @@ pub fn ptrBitWidth(target: *const Target) u16 { } pub fn cCharSignedness(target: *const Target) std.builtin.Signedness { - return target.toZigTarget().cCharSignedness(); + return target.toZigTarget().cCharSignedness().?; } pub fn cTypeBitSize(target: *const Target, c_type: std.Target.CType) u16 { - return target.toZigTarget().cTypeBitSize(c_type); + return target.toZigTarget().cTypeBitSize(c_type).?; } pub fn cTypeAlignment(target: *const Target, c_type: std.Target.CType) u16 { - return target.toZigTarget().cTypeAlignment(c_type); + return target.toZigTarget().cTypeAlignment(c_type).?; } pub fn standardDynamicLinkerPath(target: *const Target) std.Target.DynamicLinker { diff --git a/lib/compiler/aro/main.zig b/lib/compiler/aro/main.zig index 7d946af0c54790f78c63b8efbe048a3c1f2af372..1bfc84caad7831b6132864158694e51b940080fc 100644 --- a/lib/compiler/aro/main.zig +++ b/lib/compiler/aro/main.zig @@ -40,7 +40,7 @@ pub fn main(init: process.Init.Minimal) u8 { defer threaded.deinit(); const io = threaded.io(); - const fast_exit = @import("builtin").mode != .Debug; + const fast_exit = @import("builtin").mode != .debug; const args = init.args.toSlice(arena) catch { std.debug.print("out of memory\n", .{}); diff --git a/lib/compiler/configurer.zig b/lib/compiler/configurer.zig index b956ee1716db56768de7e872b7d09345881651b3..e55c37dfcc4db03f4f4fadff8a641a6f5d0c6414 100644 --- a/lib/compiler/configurer.zig +++ b/lib/compiler/configurer.zig @@ -83,7 +83,7 @@ pub fn main(init: process.Init.Minimal) !void { if (mem.cutPrefix(u8, arg, "-D")) |option_contents| { if (option_contents.len == 0) fatalWithHint("expected option name after '-D'", .{}); - if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| { + if (mem.findScalar(u8, option_contents, '=')) |name_end| { const option_name = option_contents[0..name_end]; const option_value = option_contents[name_end + 1 ..]; if (try builder.addUserInputOption(option_name, option_value)) diff --git a/lib/compiler/objcopy.zig b/lib/compiler/objcopy.zig index 857299a60e16f410c3eb54ca6be8382c33b99567..fcc55891aa430ee4d53170036a2f8f476b75def3 100644 --- a/lib/compiler/objcopy.zig +++ b/lib/compiler/objcopy.zig @@ -214,11 +214,11 @@ fn cmdObjCopy(arena: Allocator, io: Io, args: []const []const u8) !void { if (listen) { var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer); var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); - var server = try Server.init(.{ + var server: Server = .{ .in = &stdin_reader.interface, .out = &stdout_writer.interface, - .zig_version = builtin.zig_version_string, - }); + }; + try server.serveStringMessage(.zig_version, builtin.zig_version_string); var seen_update = false; while (true) { @@ -435,13 +435,13 @@ const BinaryElfOutput = struct { var program_headers = elf_hdr.iterateProgramHeaders(in); while (try program_headers.next()) |phdr| { - if (phdr.p_type == elf.PT_LOAD) { + if (phdr.type == .LOAD) { const newSegment = try allocator.create(BinaryElfSegment); - newSegment.physicalAddress = phdr.p_paddr; - newSegment.virtualAddress = phdr.p_vaddr; - newSegment.fileSize = @intCast(phdr.p_filesz); - newSegment.elfOffset = phdr.p_offset; + newSegment.physicalAddress = phdr.paddr; + newSegment.virtualAddress = phdr.vaddr; + newSegment.fileSize = @intCast(phdr.filesz); + newSegment.elfOffset = phdr.offset; newSegment.binaryOffset = 0; newSegment.firstSection = null; @@ -495,8 +495,8 @@ const BinaryElfOutput = struct { return self; } - fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool { - return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize); + fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64.Phdr) bool { + return segment.offset <= section.elfOffset and (segment.offset + segment.filesz) >= (section.elfOffset + section.fileSize); } fn sectionValidForOutput(shdr: anytype) bool { diff --git a/lib/compiler/reduce.zig b/lib/compiler/reduce.zig index 04f0c03650031d0083cd84f89fa87bfa7b8aff09..398a44a9b4e1d9ec0670db4cd0d2878c37ff6c83 100644 --- a/lib/compiler/reduce.zig +++ b/lib/compiler/reduce.zig @@ -400,7 +400,7 @@ fn parse(gpa: Allocator, io: Io, file_path: []const u8) !Ast { file_path, gpa, .limited(std.math.maxInt(u32)), - .fromByteUnits(1), + .@"1", 0, ) catch |err| { fatal("unable to open '{s}': {s}", .{ file_path, @errorName(err) }); diff --git a/lib/compiler/resinator/compile.zig b/lib/compiler/resinator/compile.zig index 0ac556120885512572c9dde4a8525373849b8c72..10fc7b261c7925e55dee2211ac67139460847618 100644 --- a/lib/compiler/resinator/compile.zig +++ b/lib/compiler/resinator/compile.zig @@ -540,7 +540,7 @@ pub const Compiler = struct { // This currently only checks for NUL bytes, but it should probably also check for // platform-specific invalid characters like '*', '?', '"', '<', '>', '|' (Windows) // Related: https://github.com/ziglang/zig/pull/14533#issuecomment-1416888193 - if (std.mem.indexOfScalar(u8, filename_utf8, 0) != null) { + if (std.mem.findScalar(u8, filename_utf8, 0) != null) { return self.addErrorDetailsAndFail(.{ .err = .invalid_filename, .token = node.filename.getFirstToken(), @@ -2919,11 +2919,11 @@ fn validateSearchPath(path: []const u8) error{BadPathName}!void { var component_iterator = std.fs.path.componentIterator(path); while (component_iterator.next()) |component| { // https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file - if (std.mem.indexOfAny(u8, component.name, "\x00<>:\"|?*") != null) return error.BadPathName; + if (std.mem.findAny(u8, component.name, "\x00<>:\"|?*") != null) return error.BadPathName; } }, else => { - if (std.mem.indexOfScalar(u8, path, 0) != null) return error.BadPathName; + if (std.mem.findScalar(u8, path, 0) != null) return error.BadPathName; }, } } diff --git a/lib/compiler/resinator/cvtres.zig b/lib/compiler/resinator/cvtres.zig index fb8ce8718907f1b369f4c5126e6d6f3bb554e85a..29d9e14ce8c0cfe4662d6f03cc4c67f8350da173 100644 --- a/lib/compiler/resinator/cvtres.zig +++ b/lib/compiler/resinator/cvtres.zig @@ -1056,7 +1056,7 @@ pub const supported_targets = struct { comptime { const info = @typeInfo(Arch).@"enum"; for (info.field_names, info.field_values) |field_name, field_value| { - _ = std.mem.indexOfScalar(Arch, ordered_for_display, @fromBackingInt(@intCast(field_value))) orelse { + _ = std.mem.findScalar(Arch, ordered_for_display, @fromBackingInt(@intCast(field_value))) orelse { @compileError(std.fmt.comptimePrint("'{s}' missing from ordered_for_display", .{field_name})); }; } diff --git a/lib/compiler/resinator/errors.zig b/lib/compiler/resinator/errors.zig index 3fda3d3c52724679a359e370ab8bee677100a45b..cbd5e5c74e31f33086db4ea446c6223ea5b07141 100644 --- a/lib/compiler/resinator/errors.zig +++ b/lib/compiler/resinator/errors.zig @@ -506,7 +506,7 @@ pub const ErrorDetails = struct { // We know that the token slice is a well-formed #pragma code_page(N), so // we can skip to the first ( and then get the number that follows const token_slice = self.token.slice(source); - var number_start = std.mem.indexOfScalar(u8, token_slice, '(').? + 1; + var number_start = std.mem.findScalar(u8, token_slice, '(').? + 1; while (std.ascii.isWhitespace(token_slice[number_start])) { number_start += 1; } diff --git a/lib/compiler/resinator/parse.zig b/lib/compiler/resinator/parse.zig index 445424429ea2249991661e99840331e2b936bd96..1f3b2f156ae15fb7fb548ffe37bce6f036079e19 100644 --- a/lib/compiler/resinator/parse.zig +++ b/lib/compiler/resinator/parse.zig @@ -1277,7 +1277,7 @@ pub const Parser = struct { }, else => unreachable, } - @compileError("unreachable"); + comptime unreachable; } pub const OptionalParamParser = struct { diff --git a/lib/compiler/resinator/source_mapping.zig b/lib/compiler/resinator/source_mapping.zig index 8ae4a70dd0a4afef5c7f346a864693a9dfc799c5..d2f72821c2076d1794e734f741bc25b274595310 100644 --- a/lib/compiler/resinator/source_mapping.zig +++ b/lib/compiler/resinator/source_mapping.zig @@ -538,7 +538,7 @@ pub fn handleLineCommand(allocator: Allocator, line_command: []const u8, current defer allocator.free(filename); // \x00 bytes in the filename is incompatible with how StringTable works - if (std.mem.indexOfScalar(u8, filename, '\x00') != null) return error.InvalidLineCommand; + if (std.mem.findScalar(u8, filename, '\x00') != null) return error.InvalidLineCommand; current_mapping.line_num = linenum; current_mapping.filename.clearRetainingCapacity(); diff --git a/lib/compiler/std-docs.zig b/lib/compiler/std-docs.zig index f41159adea3c864e0c02fe2402bbba70196dd91d..0ed2c5bf186c2c91730b1aa4aa1755babdab0be2 100644 --- a/lib/compiler/std-docs.zig +++ b/lib/compiler/std-docs.zig @@ -142,9 +142,9 @@ fn serveRequest(request: *std.http.Server.Request, context: *Context) !void { { try serveDocsFile(request, context, "docs/main.js", "application/javascript"); } else if (std.mem.eql(u8, request.head.target, "/main.wasm")) { - try serveWasm(request, context, .ReleaseFast); + try serveWasm(request, context, .fast); } else if (std.mem.eql(u8, request.head.target, "/debug/main.wasm")) { - try serveWasm(request, context, .Debug); + try serveWasm(request, context, .debug); } else if (std.mem.eql(u8, request.head.target, "/sources.tar") or std.mem.eql(u8, request.head.target, "/debug/sources.tar")) { @@ -346,29 +346,39 @@ fn buildWasmBinary( multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? }); defer multi_reader.deinit(); - try sendMessage(io, child.stdin.?, .update); - try sendMessage(io, child.stdin.?, .exit); + const stdout = multi_reader.reader(0); + + var stdin_buffer: [256]u8 = undefined; + var stdin_writer = child.stdin.?.writerStreaming(io, &stdin_buffer); + + var client: std.zig.Client = .{ + .in = stdout, + .out = &stdin_writer.interface, + }; + + try client.serveMessageHeader(.{ .tag = .update, .bytes_len = 0 }); + try client.serveMessageHeader(.{ .tag = .exit, .bytes_len = 0 }); + try client.out.flush(); var result: ?Cache.Path = null; var result_error_bundle = std.zig.ErrorBundle.empty; - const stdout = multi_reader.fileReader(0); - const MessageHeader = std.zig.Server.Message.Header; - var eos_err: error{EndOfStream}!void = {}; while (true) { - const header = stdout.interface.takeStruct(MessageHeader, .little) catch |err| switch (err) { - error.EndOfStream => break, - error.ReadFailed => return stdout.err.?, - }; - const body = stdout.interface.take(header.bytes_len) catch |err| switch (err) { + const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { + error.Timeout => unreachable, error.EndOfStream => |e| { + if (client.in.bufferedLen() == 0) break; + // Better to report the crash with stderr below, but we set + // this in case the child exits successfully while violating + // this protocol. eos_err = e; break; }, - error.ReadFailed => return stdout.err.?, + else => |e| return e, }; + const body = client.in.take(header.bytes_len) catch unreachable; switch (header.tag) { .zig_version => { @@ -435,17 +445,6 @@ fn buildWasmBinary( }; } -fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void { - const header: std.zig.Client.Message.Header = .{ - .tag = tag, - .bytes_len = 0, - }; - var w = file.writer(io, &.{}); - w.interface.writeStruct(header, .little) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; -} - fn openBrowserTab(io: Io, url: []const u8) !void { // Until https://github.com/ziglang/zig/issues/19205 is implemented, we // spawn and then leak a concurrent task for this child process. diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index 62c09fe22800abc8aeb462dbd8c8beffe0ef7925..0fd5afad694b6aa417fb7cdfcf7305614574d883 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -78,11 +78,11 @@ fn mainServer(init: std.process.Init.Minimal) !void { @disableInstrumentation(); stdin_reader = .initStreaming(.stdin(), runner_threaded_io, &stdin_buffer); stdout_writer = .initStreaming(.stdout(), runner_threaded_io, &stdout_buffer); - var server = try std.zig.Server.init(.{ + var server: std.zig.Server = .{ .in = &stdin_reader.interface, .out = &stdout_writer.interface, - .zig_version = builtin.zig_version_string, - }); + }; + try server.serveStringMessage(.zig_version, builtin.zig_version_string); while (true) { const hdr = try server.receiveMessage(); @@ -91,24 +91,23 @@ fn mainServer(init: std.process.Init.Minimal) !void { return std.process.exit(0); }, .query_test_metadata => { - testing.allocator_instance = .init(std.heap.page_allocator, .{}); - defer if (testing.allocator_instance.deinit() != 0) { - @panic("internal test runner memory leak"); - }; + var sa: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{}); + defer if (sa.deinit() != 0) @panic("internal test runner memory leak"); + const gpa = sa.allocator(); var string_bytes: std.ArrayList(u8) = .empty; - defer string_bytes.deinit(testing.allocator); - try string_bytes.append(testing.allocator, 0); // Reserve 0 for null. + defer string_bytes.deinit(gpa); + try string_bytes.append(gpa, 0); // Reserve 0 for null. const test_fns = builtin.test_functions; - const names = try testing.allocator.alloc(u32, test_fns.len); - defer testing.allocator.free(names); - const expected_panic_msgs = try testing.allocator.alloc(u32, test_fns.len); - defer testing.allocator.free(expected_panic_msgs); + const names = try gpa.alloc(u32, test_fns.len); + defer gpa.free(names); + const expected_panic_msgs = try gpa.alloc(u32, test_fns.len); + defer gpa.free(expected_panic_msgs); for (test_fns, names, expected_panic_msgs) |test_fn, *name, *expected_panic_msg| { name.* = @intCast(string_bytes.items.len); - try string_bytes.ensureUnusedCapacity(testing.allocator, test_fn.name.len + 1); + try string_bytes.ensureUnusedCapacity(gpa, test_fn.name.len + 1); string_bytes.appendSliceAssumeCapacity(test_fn.name); string_bytes.appendAssumeCapacity(0); expected_panic_msg.* = 0; @@ -377,6 +376,7 @@ pub fn mainSimple() anyerror!void { else => false, }; + testing.allocator_instance = .init(std.heap.page_allocator, .{}); testing.io_instance = .init(testing.allocator, .{}); var passed: u64 = 0; diff --git a/lib/compiler/translate-c/MacroTranslator.zig b/lib/compiler/translate-c/MacroTranslator.zig index ed4cb8a997a0d87b1bc25d63a1a0f86b6501a313..04b0e9cb3d84a0d78566470e94a7f1ca565ec8b5 100644 --- a/lib/compiler/translate-c/MacroTranslator.zig +++ b/lib/compiler/translate-c/MacroTranslator.zig @@ -361,7 +361,7 @@ fn parseCNumLit(mt: *MacroTranslator) ParseError!ZigNode { return error.ParseError; }, }); - if (bytes.getLast().? == '.') { + if (bytes.last().? == '.') { bytes.appendAssumeCapacity('0'); } else if (mem.findAny(u8, bytes.items, ".eEpP") == null) { bytes.appendSliceAssumeCapacity(".0"); diff --git a/lib/compiler/translate-c/main.zig b/lib/compiler/translate-c/main.zig index 95836a94519ecbae20eea20f63b03d161301376c..e5c3961076a2daa2ec4a119c5903f175db96857c 100644 --- a/lib/compiler/translate-c/main.zig +++ b/lib/compiler/translate-c/main.zig @@ -9,7 +9,7 @@ const compiler_util = @import("../util.zig"); const Translator = @import("Translator.zig"); -const fast_exit = @import("builtin").mode != .Debug; +const fast_exit = @import("builtin").mode != .debug; pub fn main(init: process.Init) u8 { const gpa = init.gpa; diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 0a8621ed13e8e6b4422b7b2554bf29955282f91c..5ff6e659d56f0797225b7661aa076cb41f715a42 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -1,4 +1,5 @@ const builtin = @import("builtin"); +const compiler_rt = @This(); const ofmt_c = builtin.object_format == .c; const native_endian = builtin.cpu.arch.endian(); @@ -84,144 +85,17 @@ comptime { // Float routines // conversion _ = @import("compiler_rt/extendf.zig"); - _ = @import("compiler_rt/extendhfsf2.zig"); - _ = @import("compiler_rt/extendhfdf2.zig"); - _ = @import("compiler_rt/extendhftf2.zig"); - _ = @import("compiler_rt/extendhfxf2.zig"); - _ = @import("compiler_rt/extendsfdf2.zig"); - _ = @import("compiler_rt/extendsftf2.zig"); - _ = @import("compiler_rt/extendsfxf2.zig"); - _ = @import("compiler_rt/extenddftf2.zig"); - _ = @import("compiler_rt/extenddfxf2.zig"); - _ = @import("compiler_rt/extendxftf2.zig"); - _ = @import("compiler_rt/truncf.zig"); - _ = @import("compiler_rt/truncsfhf2.zig"); - _ = @import("compiler_rt/truncdfhf2.zig"); - _ = @import("compiler_rt/truncdfsf2.zig"); - _ = @import("compiler_rt/truncxfhf2.zig"); - _ = @import("compiler_rt/truncxfsf2.zig"); - _ = @import("compiler_rt/truncxfdf2.zig"); - _ = @import("compiler_rt/trunctfhf2.zig"); - _ = @import("compiler_rt/trunctfsf2.zig"); - _ = @import("compiler_rt/trunctfdf2.zig"); - _ = @import("compiler_rt/trunctfxf2.zig"); - _ = @import("compiler_rt/int_from_float.zig"); - _ = @import("compiler_rt/fixhfei.zig"); - _ = @import("compiler_rt/fixsfsi.zig"); - _ = @import("compiler_rt/fixsfdi.zig"); - _ = @import("compiler_rt/fixsfti.zig"); - _ = @import("compiler_rt/fixsfei.zig"); - _ = @import("compiler_rt/fixdfsi.zig"); - _ = @import("compiler_rt/fixdfdi.zig"); - _ = @import("compiler_rt/fixdfti.zig"); - _ = @import("compiler_rt/fixdfei.zig"); - _ = @import("compiler_rt/fixtfsi.zig"); - _ = @import("compiler_rt/fixtfdi.zig"); - _ = @import("compiler_rt/fixtfti.zig"); - _ = @import("compiler_rt/fixtfei.zig"); - _ = @import("compiler_rt/fixxfsi.zig"); - _ = @import("compiler_rt/fixxfdi.zig"); - _ = @import("compiler_rt/fixxfei.zig"); - - _ = @import("compiler_rt/fixunshfsi.zig"); - _ = @import("compiler_rt/fixunshfdi.zig"); - _ = @import("compiler_rt/fixunshfti.zig"); - _ = @import("compiler_rt/fixunshfei.zig"); - _ = @import("compiler_rt/fixunssfsi.zig"); - _ = @import("compiler_rt/fixunssfdi.zig"); - _ = @import("compiler_rt/fixunssfti.zig"); - _ = @import("compiler_rt/fixunssfei.zig"); - _ = @import("compiler_rt/fixunsdfsi.zig"); - _ = @import("compiler_rt/fixunsdfdi.zig"); - _ = @import("compiler_rt/fixunsdfti.zig"); - _ = @import("compiler_rt/fixunsdfei.zig"); - _ = @import("compiler_rt/fixunstfsi.zig"); - _ = @import("compiler_rt/fixunstfdi.zig"); - _ = @import("compiler_rt/fixunstfti.zig"); - _ = @import("compiler_rt/fixunstfei.zig"); - _ = @import("compiler_rt/fixunsxfsi.zig"); - _ = @import("compiler_rt/fixunsxfdi.zig"); - _ = @import("compiler_rt/fixunsxfti.zig"); - _ = @import("compiler_rt/fixunsxfei.zig"); - _ = @import("compiler_rt/float_from_int.zig"); - _ = @import("compiler_rt/floatsihf.zig"); - _ = @import("compiler_rt/floatsisf.zig"); - _ = @import("compiler_rt/floatsidf.zig"); - _ = @import("compiler_rt/floatsitf.zig"); - _ = @import("compiler_rt/floatsixf.zig"); - _ = @import("compiler_rt/floatdihf.zig"); - _ = @import("compiler_rt/floatdisf.zig"); - _ = @import("compiler_rt/floatdidf.zig"); - _ = @import("compiler_rt/floatditf.zig"); - _ = @import("compiler_rt/floatdixf.zig"); - _ = @import("compiler_rt/floattihf.zig"); - _ = @import("compiler_rt/floattisf.zig"); - _ = @import("compiler_rt/floattidf.zig"); - _ = @import("compiler_rt/floattitf.zig"); - _ = @import("compiler_rt/floattixf.zig"); - _ = @import("compiler_rt/floateihf.zig"); - _ = @import("compiler_rt/floateisf.zig"); - _ = @import("compiler_rt/floateidf.zig"); - _ = @import("compiler_rt/floateitf.zig"); - _ = @import("compiler_rt/floateixf.zig"); - _ = @import("compiler_rt/floatunsihf.zig"); - _ = @import("compiler_rt/floatunsisf.zig"); - _ = @import("compiler_rt/floatunsidf.zig"); - _ = @import("compiler_rt/floatunsitf.zig"); - _ = @import("compiler_rt/floatunsixf.zig"); - _ = @import("compiler_rt/floatundihf.zig"); - _ = @import("compiler_rt/floatundisf.zig"); - _ = @import("compiler_rt/floatundidf.zig"); - _ = @import("compiler_rt/floatunditf.zig"); - _ = @import("compiler_rt/floatundixf.zig"); - _ = @import("compiler_rt/floatuntihf.zig"); - _ = @import("compiler_rt/floatuntisf.zig"); - _ = @import("compiler_rt/floatuntidf.zig"); - _ = @import("compiler_rt/floatuntitf.zig"); - _ = @import("compiler_rt/floatuntixf.zig"); - _ = @import("compiler_rt/floatuneihf.zig"); - _ = @import("compiler_rt/floatuneisf.zig"); - _ = @import("compiler_rt/floatuneidf.zig"); - _ = @import("compiler_rt/floatuneitf.zig"); - _ = @import("compiler_rt/floatuneixf.zig"); // comparison _ = @import("compiler_rt/comparef.zig"); - _ = @import("compiler_rt/cmpdf2.zig"); - _ = @import("compiler_rt/cmptf2.zig"); - _ = @import("compiler_rt/cmpxf2.zig"); - _ = @import("compiler_rt/unorddf2.zig"); - _ = @import("compiler_rt/gehf2.zig"); - _ = @import("compiler_rt/gesf2.zig"); - _ = @import("compiler_rt/gedf2.zig"); - _ = @import("compiler_rt/gexf2.zig"); - _ = @import("compiler_rt/getf2.zig"); // arithmetic _ = @import("compiler_rt/addf3.zig"); - _ = @import("compiler_rt/addhf3.zig"); - _ = @import("compiler_rt/addsf3.zig"); - _ = @import("compiler_rt/adddf3.zig"); - _ = @import("compiler_rt/addtf3.zig"); - _ = @import("compiler_rt/addxf3.zig"); - - _ = @import("compiler_rt/subhf3.zig"); - _ = @import("compiler_rt/subsf3.zig"); - _ = @import("compiler_rt/subdf3.zig"); - _ = @import("compiler_rt/subtf3.zig"); - _ = @import("compiler_rt/subxf3.zig"); - _ = @import("compiler_rt/mulf3.zig"); - _ = @import("compiler_rt/mulhf3.zig"); - _ = @import("compiler_rt/mulsf3.zig"); - _ = @import("compiler_rt/muldf3.zig"); - _ = @import("compiler_rt/multf3.zig"); - _ = @import("compiler_rt/mulxf3.zig"); - _ = @import("compiler_rt/divhf3.zig"); _ = @import("compiler_rt/divsf3.zig"); _ = @import("compiler_rt/divdf3.zig"); _ = @import("compiler_rt/divxf3.zig"); @@ -235,25 +109,17 @@ comptime { symbol(&__negsf2, "__negsf2"); symbol(&__negdf2, "__negdf2"); } - if (want_ppc_abi) symbol(&__negtf2, "__negkf2"); - symbol(&__negtf2, "__negtf2"); + if (want_ppc_abi) { + symbol(&__negtf2, "__negkf2"); + } else { + symbol(&__negtf2, "__negtf2"); + } symbol(&__negxf2, "__negxf2"); // other _ = @import("compiler_rt/powiXf2.zig"); _ = @import("compiler_rt/mulc3.zig"); - _ = @import("compiler_rt/mulhc3.zig"); - _ = @import("compiler_rt/mulsc3.zig"); - _ = @import("compiler_rt/muldc3.zig"); - _ = @import("compiler_rt/mulxc3.zig"); - _ = @import("compiler_rt/multc3.zig"); - _ = @import("compiler_rt/divc3.zig"); - _ = @import("compiler_rt/divhc3.zig"); - _ = @import("compiler_rt/divsc3.zig"); - _ = @import("compiler_rt/divdc3.zig"); - _ = @import("compiler_rt/divxc3.zig"); - _ = @import("compiler_rt/divtc3.zig"); // Math routines. Alphabetically sorted. _ = @import("compiler_rt/cos.zig"); @@ -279,7 +145,7 @@ comptime { _ = @import("compiler_rt/divmodei4.zig"); _ = @import("compiler_rt/udivmodei4.zig"); - _ = @import("compiler_rt/limb64.zig"); + if (builtin.cpu.arch.isWasm()) _ = @import("compiler_rt/limb64.zig"); // extra _ = @import("compiler_rt/os_version_check.zig"); @@ -290,7 +156,7 @@ comptime { _ = @import("compiler_rt/clear_cache.zig"); _ = @import("compiler_rt/hexagon.zig"); - if (@import("builtin").object_format != .c) { + if (builtin.object_format != .c) { if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/atomics.zig"); _ = @import("compiler_rt/stack_probe.zig"); @@ -302,7 +168,6 @@ comptime { _ = @import("compiler_rt/memcpy.zig"); if (!ofmt_c) { symbol(&memset, "memset"); - symbol(&__memset, "__memset"); } _ = @import("compiler_rt/memmove.zig"); symbol(&memcmp, "memcmp"); @@ -367,10 +232,7 @@ pub const want_aeabi = switch (builtin.abi) { .gnueabihf, .android, .androideabi, - => switch (builtin.cpu.arch) { - .arm, .armeb, .thumb, .thumbeb => true, - else => false, - }, + => builtin.cpu.arch.isArm(), else => false, }; @@ -444,17 +306,106 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) { pub const want_sparc64_abi = builtin.cpu.arch == .sparc64; pub const want_sparc32_abi = builtin.cpu.arch == .sparc; -pub fn F16T(comptime OtherType: type) type { - return switch (builtin.cpu.arch) { - .x86, .x86_64 => if (builtin.target.os.tag.isDarwin()) switch (OtherType) { - // Starting with LLVM 16, Darwin uses different abi for f16 - // depending on the type of the other return/argument..??? - f32, f64 => u16, - f80, f128 => f16, - else => unreachable, - } else f16, - else => f16, +/// For operations converting between `f16` and another floating point type. +pub fn f16Conv(comptime OtherType: type) type { + switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 16)) { + .hard => {}, + .soft => return softFloatAbi(f16), + } + if (builtin.cpu.arch.isX86() and builtin.os.tag.isDarwin()) switch (OtherType) { + else => unreachable, + // Starting with LLVM 16, Darwin uses different abi for f16 + // depending on the type of the other return/argument..??? + f32, f64 => return softFloatAbi(f16), + f80, f128 => {}, }; + return hardFloatAbi(f16); +} +pub const @"f16" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 16)) { + .hard => hardFloatAbi(f16), + .soft => softFloatAbi(f16), +}; +pub const @"f32" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 32)) { + .hard => hardFloatAbi(f32), + .soft => softFloatAbi(f32), +}; +pub const @"f64" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 64)) { + .hard => hardFloatAbi(f64), + .soft => softFloatAbi(f64), +}; +pub const @"f80" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 80)) { + .hard => hardFloatAbi(f80), + .soft => struct { + pub const Abi = extern struct { mantissa: u64, exponent: u16 }; + const Repr = packed struct { mantissa: u64, exponent: u16 }; + pub inline fn toAbi(raw: f80) Abi { + const repr: Repr = @bitCast(raw); + return .{ .mantissa = repr.mantissa, .exponent = repr.exponent }; + } + pub inline fn fromAbi(abi: Abi) f80 { + const repr: Repr = .{ .mantissa = abi.mantissa, .exponent = abi.exponent }; + return @bitCast(repr); + } + pub const complex = complexAbi(f80, @This()); + }, +}; +pub const @"f128" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 128)) { + .hard => hardFloatAbi(f128), + .soft => struct { + pub const Abi = switch (builtin.cpu.arch.endian()) { + .big => extern struct { hi: u64, lo: u64 }, + .little => extern struct { lo: u64, hi: u64 }, + }; + const Repr = packed struct { lo: u64, hi: u64 }; + pub inline fn toAbi(raw: f128) Abi { + const repr: Repr = @bitCast(raw); + return .{ .lo = repr.lo, .hi = repr.hi }; + } + pub inline fn fromAbi(abi: Abi) f128 { + const repr: Repr = .{ .lo = abi.lo, .hi = abi.hi }; + return @bitCast(repr); + } + pub const complex = complexAbi(f128, @This()); + }, +}; +fn hardFloatAbi(comptime Float: type) type { + return struct { + pub const Abi = Float; + pub inline fn toAbi(raw: Float) Abi { + return raw; + } + pub inline fn fromAbi(abi: Abi) Float { + return abi; + } + pub const complex = complexAbi(Float, @This()); + }; +} +fn softFloatAbi(comptime Float: type) type { + return struct { + pub const Abi = @Int(.unsigned, @bitSizeOf(Float)); + pub inline fn toAbi(raw: Float) Abi { + return @bitCast(raw); + } + pub inline fn fromAbi(abi: Abi) Float { + return @bitCast(abi); + } + pub const complex = complexAbi(Float, @This()); + }; +} +fn complexAbi(comptime Float: type, comptime float: type) type { + return struct { + pub const Abi = extern struct { real: float.Abi, imag: float.Abi }; + pub inline fn toAbi(raw: Complex(Float)) Abi { + return .{ .real = float.toAbi(raw.real), .imag = float.toAbi(raw.imag) }; + } + pub inline fn fromAbi(abi: Abi) Complex(Float) { + return .{ .real = float.fromAbi(abi.real), .imag = float.fromAbi(abi.imag) }; + } + }; +} + +pub fn Complex(comptime Float: type) type { + return struct { real: Float, imag: Float }; } pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { @@ -589,34 +540,34 @@ pub inline fn fneg(a: anytype) @TypeOf(a) { return @bitCast(negated); } -fn __negxf2(a: f80) callconv(.c) f80 { - return fneg(a); +fn __neghf2(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fneg(compiler_rt.f16.fromAbi(a))); } -fn __neghf2(a: f16) callconv(.c) f16 { - return fneg(a); +fn __negsf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fneg(compiler_rt.f32.fromAbi(a))); } -fn __negdf2(a: f64) callconv(.c) f64 { - return fneg(a); +fn __negdf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fneg(compiler_rt.f64.fromAbi(a))); } -fn __aeabi_dneg(a: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return fneg(a); +fn __negxf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fneg(compiler_rt.f80.fromAbi(a))); } -fn __negtf2(a: f128) callconv(.c) f128 { - return fneg(a); -} - -fn __negsf2(a: f32) callconv(.c) f32 { - return fneg(a); +fn __negtf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fneg(compiler_rt.f128.fromAbi(a))); } fn __aeabi_fneg(a: f32) callconv(.{ .arm_aapcs = .{} }) f32 { return fneg(a); } +fn __aeabi_dneg(a: f64) callconv(.{ .arm_aapcs = .{} }) f64 { + return fneg(a); +} + /// Allows to access underlying bits as two equally sized lower and higher /// signed or unsigned integers. pub fn HalveInt(comptime T: type, comptime signed_half: bool) type { @@ -650,14 +601,80 @@ inline fn negXi2(comptime T: type, a: T) T { return -a; } -pub fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.c) ?[*]u8 { - @setRuntimeSafety(false); +fn memsetSmallPowerOf2(d: [*]u8, b: u8, comptime size: usize) void { + if (size > @sizeOf(usize)) { + d[0..size].* = @splat(b); + } else { + const T = @Int(.unsigned, 8 * size); + var splatted: T = 0; // Setting this to undefined causes a memset call and thus infinite recursion in Debug test-compiler-rt. + @as(*[size]u8, @ptrCast(&splatted)).* = @splat(b); + @as(*align(1) T, @ptrCast(d)).* = splatted; + } +} + +fn shortMemset( + log_min: comptime_int, + log_max: comptime_int, + d: [*]u8, + b: u8, + len: usize, +) void { + if (log_min + 1 != log_max) { + const mid = (log_min + log_max) / 2; + if (len > 1 << mid) { + shortMemset(mid, log_max, d, b, len); + } else { + shortMemset(log_min, mid, d, b, len); + } + } else { + const size = 1 << log_min; + + memsetSmallPowerOf2(d, b, size); + memsetSmallPowerOf2(d + len - size, b, size); + } +} + +fn fastMemset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 { + const b: u8 = @truncate(@as(c_uint, @bitCast(c))); + const n = std.simd.suggestVectorLength(u8) orelse @sizeOf(usize); + + const d = dest.?; + + if (len > 2 * n) { + memsetSmallPowerOf2(d, b, n); + + const begin_aligned = std.mem.alignBackward(usize, @intFromPtr(d) + n, n); + const end_aligned = std.mem.alignForward(usize, @intFromPtr(d) + len - n, n); + + const aligned_ptr: [*]align(n) u8 = @ptrFromInt(begin_aligned); + + var i: usize = 0; + while (true) { + memsetSmallPowerOf2(aligned_ptr + n * i, b, n); + + i += 1; + if (i == @divExact(end_aligned - begin_aligned, n)) + break; + } + + memsetSmallPowerOf2(d + len - n, b, n); + } else { + if (len == 0) return dest; + + shortMemset(0, @ctz(@as(usize, 2 * n)), d, b, len); + } + + return dest; +} + +fn smallMemset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 { + const b: u8 = @truncate(@as(c_uint, @bitCast(c))); if (len != 0) { var d = dest.?; var n = len; while (true) { - d[0] = c; + d[0] = b; n -= 1; if (n == 0) break; d += 1; @@ -667,11 +684,10 @@ pub fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.c) ?[*]u8 { return dest; } -pub fn __memset(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.c) ?[*]u8 { - if (dest_n < n) - @panic("buffer overflow"); - return memset(dest, c, n); -} +pub const memset = if (builtin.optimize == .small) + smallMemset +else + fastMemset; pub fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.c) c_int { @setRuntimeSafety(false); diff --git a/lib/compiler_rt/absv.zig b/lib/compiler_rt/absv.zig index 8910a4a6b9417bd099065db02f1535ace9968ee0..4621835dd6f6abd9cdb37a53231e88139556eb9a 100644 --- a/lib/compiler_rt/absv.zig +++ b/lib/compiler_rt/absv.zig @@ -14,8 +14,7 @@ pub inline fn absv(comptime ST: type, a: ST) ST { const sign: ST = a >> N - 1; x +%= sign; x ^= sign; - if (x < 0) - @panic("compiler_rt absv: overflow"); + if (x < 0) @panic("integer overflow"); return x; } diff --git a/lib/compiler_rt/absvdi2.zig b/lib/compiler_rt/absvdi2.zig index 408d70ad167d29c7895e6145e7635da95ec62a82..598629ebfc689258a055110aa976cf0d3b56226a 100644 --- a/lib/compiler_rt/absvdi2.zig +++ b/lib/compiler_rt/absvdi2.zig @@ -1,5 +1,6 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const absv = @import("./absv.zig").absv; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; +const absv = @import("absv.zig").absv; comptime { symbol(&__absvdi2, "__absvdi2"); diff --git a/lib/compiler_rt/absvsi2.zig b/lib/compiler_rt/absvsi2.zig index 538d7f7f0155f98cf997b711514145ae77da5c2a..e01627090082800cd53ee4b614f3a68d9480c214 100644 --- a/lib/compiler_rt/absvsi2.zig +++ b/lib/compiler_rt/absvsi2.zig @@ -1,6 +1,6 @@ const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; -const absv = @import("./absv.zig").absv; +const absv = @import("absv.zig").absv; comptime { symbol(&__absvsi2, "__absvsi2"); diff --git a/lib/compiler_rt/absvti2.zig b/lib/compiler_rt/absvti2.zig index ab367d2b78ae2f0a813d011ec74dc532d103303f..008060504e318f7d9979a43d4d53ac34a8d38c76 100644 --- a/lib/compiler_rt/absvti2.zig +++ b/lib/compiler_rt/absvti2.zig @@ -1,5 +1,6 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const absv = @import("./absv.zig").absv; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; +const absv = @import("absv.zig").absv; comptime { symbol(&__absvti2, "__absvti2"); diff --git a/lib/compiler_rt/adddf3.zig b/lib/compiler_rt/adddf3.zig deleted file mode 100644 index 7b6f252da2c7f697b23b8e9e9fd13d34cc99bc80..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/adddf3.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const addf3 = @import("./addf3.zig").addf3; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dadd, "__aeabi_dadd"); - } else { - symbol(&__adddf3, "__adddf3"); - } -} - -fn __adddf3(a: f64, b: f64) callconv(.c) f64 { - return addf3(f64, a, b); -} - -fn __aeabi_dadd(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return addf3(f64, a, b); -} diff --git a/lib/compiler_rt/addf3.zig b/lib/compiler_rt/addf3.zig index 1e68c82f0fbcf3a4a28d4d9c0d877b997496d7a2..189f7afd6d02c78bdb63de8e38ca7731c96684d4 100644 --- a/lib/compiler_rt/addf3.zig +++ b/lib/compiler_rt/addf3.zig @@ -1,12 +1,143 @@ const std = @import("std"); const math = std.math; const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; const normalize = compiler_rt.normalize; +comptime { + symbol(&__addhf3, "__addhf3"); + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_fadd, "__aeabi_fadd"); + symbol(&__aeabi_dadd, "__aeabi_dadd"); + } else { + symbol(&__addsf3, "__addsf3"); + symbol(&__adddf3, "__adddf3"); + } + symbol(&__addxf3, "__addxf3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__addtf3, "__addkf3"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_add, "_Qp_add"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__addtf3, "_Q_add"); + } else { + symbol(&__addtf3, "__addtf3"); + } +} + +fn __addhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(add_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn add_f16(a: f16, b: f16) f16 { + return addf3(f16, a, b); +} + +fn __addsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(add_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); +} +fn __aeabi_fadd(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { + return add_f32(a, b); +} +pub fn add_f32(a: f32, b: f32) f32 { + return addf3(f32, a, b); +} + +fn __adddf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(add_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +fn __aeabi_dadd(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { + return add_f64(a, b); +} +pub fn add_f64(a: f64, b: f64) f64 { + return addf3(f64, a, b); +} + +fn __addxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(add_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn add_f80(a: f80, b: f80) f80 { + return addf3(f80, a, b); +} + +fn __addtf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(add_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} +fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.c) void { + c.* = add_f128(a.*, b.*); +} +pub fn add_f128(a: f128, b: f128) f128 { + return addf3(f128, a, b); +} + +comptime { + symbol(&__subhf3, "__subhf3"); + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_fsub, "__aeabi_fsub"); + symbol(&__aeabi_dsub, "__aeabi_dsub"); + } else { + symbol(&__subsf3, "__subsf3"); + symbol(&__subdf3, "__subdf3"); + } + symbol(&__subxf3, "__subxf3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__subtf3, "__subkf3"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_sub, "_Qp_sub"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__subtf3, "_Q_sub"); + } else { + symbol(&__subtf3, "__subtf3"); + } +} + +fn __subhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(sub_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn sub_f16(a: f16, b: f16) f16 { + return add_f16(a, compiler_rt.fneg(b)); +} + +fn __subsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(sub_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); +} +fn __aeabi_fsub(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { + return sub_f32(a, b); +} +pub fn sub_f32(a: f32, b: f32) f32 { + return add_f32(a, compiler_rt.fneg(b)); +} + +fn __subdf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(sub_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +fn __aeabi_dsub(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { + return sub_f64(a, b); +} +pub fn sub_f64(a: f64, b: f64) f64 { + return add_f64(a, compiler_rt.fneg(b)); +} + +fn __subxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(sub_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn sub_f80(a: f80, b: f80) f80 { + return add_f80(a, compiler_rt.fneg(b)); +} + +fn __subtf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(sub_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} +fn _Qp_sub(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { + c.* = sub_f128(a.*, b.*); +} +pub fn sub_f128(a: f128, b: f128) f128 { + return add_f128(a, compiler_rt.fneg(b)); +} + /// Ported from: /// /// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc -pub inline fn addf3(comptime T: type, a: T, b: T) T { +inline fn addf3(comptime T: type, a: T, b: T) T { const bits = @typeInfo(T).float.bits; const Z = @Int(.unsigned, bits); diff --git a/lib/compiler_rt/addf3_test.zig b/lib/compiler_rt/addf3_test.zig index 1e9bfa1bbf5403cee4cb6fc839478782714eca5b..ffa3a48086a47e9617145c0d33e049b221303ec5 100644 --- a/lib/compiler_rt/addf3_test.zig +++ b/lib/compiler_rt/addf3_test.zig @@ -8,12 +8,13 @@ const builtin = @import("builtin"); const math = std.math; const qnan128: f128 = @bitCast(@as(u128, 0x7fff800000000000) << 64); -const __addtf3 = @import("addtf3.zig").__addtf3; -const __addxf3 = @import("addxf3.zig").__addxf3; -const __subtf3 = @import("subtf3.zig").__subtf3; +const impl = @import("addf3.zig"); +const add_f128 = impl.add_f128; +const add_f80 = impl.add_f80; +const sub_f128 = impl.sub_f128; fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __addtf3(a, b); + const x = add_f128(a, b); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -52,7 +53,7 @@ test "addtf3" { } fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __subtf3(a, b); + const x = sub_f128(a, b); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -91,7 +92,7 @@ test "subtf3" { const qnan80: f80 = @bitCast(@as(u80, @bitCast(math.nan(f80))) | (1 << (math.floatFractionalBits(f80) - 1))); fn test__addxf3(a: f80, b: f80, expected: u80) !void { - const x = __addxf3(a, b); + const x = add_f80(a, b); const rep: u80 = @bitCast(x); if (rep == expected) diff --git a/lib/compiler_rt/addhf3.zig b/lib/compiler_rt/addhf3.zig deleted file mode 100644 index bd13f48cac5f1ebeda2f019b1252d6a6967aa964..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/addhf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - symbol(&__addhf3, "__addhf3"); -} - -fn __addhf3(a: f16, b: f16) callconv(.c) f16 { - return addf3(f16, a, b); -} diff --git a/lib/compiler_rt/addsf3.zig b/lib/compiler_rt/addsf3.zig deleted file mode 100644 index 4878fb704d1769469fb0a9155c930f0e24e0cabc..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/addsf3.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const addf3 = @import("./addf3.zig").addf3; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fadd, "__aeabi_fadd"); - } else { - symbol(&__addsf3, "__addsf3"); - } -} - -fn __addsf3(a: f32, b: f32) callconv(.c) f32 { - return addf3(f32, a, b); -} - -fn __aeabi_fadd(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { - return addf3(f32, a, b); -} diff --git a/lib/compiler_rt/addtf3.zig b/lib/compiler_rt/addtf3.zig deleted file mode 100644 index 3097027f482ed73deee604acfcd7be877192d1fc..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/addtf3.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__addtf3, "__addkf3"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_add, "_Qp_add"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__addtf3, "_Q_add"); - } - symbol(&__addtf3, "__addtf3"); -} - -pub fn __addtf3(a: f128, b: f128) callconv(.c) f128 { - return addf3(f128, a, b); -} - -fn _Qp_add(c: *f128, a: *f128, b: *f128) callconv(.c) void { - c.* = addf3(f128, a.*, b.*); -} diff --git a/lib/compiler_rt/addvdi3.zig b/lib/compiler_rt/addvdi3.zig index a5cde2494acba14282409395aa47ce9660faa0ff..063c2bcd44f16ea3dcd14fb427b24835830190bd 100644 --- a/lib/compiler_rt/addvdi3.zig +++ b/lib/compiler_rt/addvdi3.zig @@ -1,4 +1,5 @@ -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; const testing = @import("std").testing; comptime { @@ -9,7 +10,7 @@ pub fn __addvdi3(a: i64, b: i64) callconv(.c) i64 { const sum = a +% b; // Overflow occurred iff both operands have the same sign, and the sign of the sum does // not match it. In other words, iff the sum sign is not the sign of either operand. - if (((sum ^ a) & (sum ^ b)) < 0) @panic("compiler-rt: integer overflow"); + if (((sum ^ a) & (sum ^ b)) < 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/addvsi3.zig b/lib/compiler_rt/addvsi3.zig index c35b22e8dfd73703480c89f4a5d305fa5b8ec9fd..f180f680c52e8ddc4a991838714eff4647cb57ba 100644 --- a/lib/compiler_rt/addvsi3.zig +++ b/lib/compiler_rt/addvsi3.zig @@ -10,7 +10,7 @@ pub fn __addvsi3(a: i32, b: i32) callconv(.c) i32 { const sum = a +% b; // Overflow occurred iff both operands have the same sign, and the sign of the sum does // not match it. In other words, iff the sum sign is not the sign of either operand. - if (((sum ^ a) & (sum ^ b)) < 0) @panic("compiler-rt: integer overflow"); + if (((sum ^ a) & (sum ^ b)) < 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/addxf3.zig b/lib/compiler_rt/addxf3.zig deleted file mode 100644 index f57708c98553874b47b62591b339e49b22ecedbd..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/addxf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - symbol(&__addxf3, "__addxf3"); -} - -pub fn __addxf3(a: f80, b: f80) callconv(.c) f80 { - return addf3(f80, a, b); -} diff --git a/lib/compiler_rt/atomics.zig b/lib/compiler_rt/atomics.zig index f2c744c730b8c20501af60bf51fa78d57cb7cbc3..83b978a11ca2fad3dc2e4f8483556751c2f6e3d1 100644 --- a/lib/compiler_rt/atomics.zig +++ b/lib/compiler_rt/atomics.zig @@ -5,7 +5,7 @@ const arch = cpu.arch; const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; // This parameter is true iff the target architecture supports the bare minimum // to implement the atomic load/store intrinsics. diff --git a/lib/compiler_rt/aulldiv.zig b/lib/compiler_rt/aulldiv.zig index 4ed92f39eefde1b941634b5b72eac8d1e41ba0d2..3e002379220fa5e957f2d2a728435a2a11972415 100644 --- a/lib/compiler_rt/aulldiv.zig +++ b/lib/compiler_rt/aulldiv.zig @@ -1,7 +1,7 @@ const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { if (compiler_rt.want_windows_x86_msvc_abi) { diff --git a/lib/compiler_rt/cmpdf2.zig b/lib/compiler_rt/cmpdf2.zig deleted file mode 100644 index e55972efbd00da3c3b215e722ba2277557a37525..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/cmpdf2.zig +++ /dev/null @@ -1,67 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const comparef = @import("./comparef.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dcmpeq, "__aeabi_dcmpeq"); - symbol(&__aeabi_dcmplt, "__aeabi_dcmplt"); - symbol(&__aeabi_dcmple, "__aeabi_dcmple"); - } else { - symbol(&__eqdf2, "__eqdf2"); - symbol(&__nedf2, "__nedf2"); - symbol(&__ledf2, "__ledf2"); - symbol(&__cmpdf2, "__cmpdf2"); - symbol(&__ltdf2, "__ltdf2"); - } -} - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__ledf2`, `__eqdf2`, `__nedf2`, `__cmpdf2`, -/// and `__ltdf2`. -fn __cmpdf2(a: f64, b: f64) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f64, comparef.LE, a, b)); -} - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -pub fn __ledf2(a: f64, b: f64) callconv(.c) i32 { - return __cmpdf2(a, b); -} - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqdf2 and __nedf2 are defined -/// to have the same return value. -pub fn __eqdf2(a: f64, b: f64) callconv(.c) i32 { - return __cmpdf2(a, b); -} - -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqdf2 and __nedf2 are defined -/// to have the same return value. -pub fn __nedf2(a: f64, b: f64) callconv(.c) i32 { - return __cmpdf2(a, b); -} - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -pub fn __ltdf2(a: f64, b: f64) callconv(.c) i32 { - return __cmpdf2(a, b); -} - -fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.LE, a, b) == .Equal); -} - -fn __aeabi_dcmplt(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.LE, a, b) == .Less); -} - -fn __aeabi_dcmple(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.LE, a, b) != .Greater); -} diff --git a/lib/compiler_rt/cmptf2.zig b/lib/compiler_rt/cmptf2.zig deleted file mode 100644 index 89418fb320b5b8ea3d2f972cf05dde162eccc7c0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/cmptf2.zig +++ /dev/null @@ -1,146 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const comparef = @import("./comparef.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__eqtf2, "__eqkf2"); - symbol(&__netf2, "__nekf2"); - symbol(&__lttf2, "__ltkf2"); - symbol(&__letf2, "__lekf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_cmp, "_Qp_cmp"); - symbol(&_Qp_feq, "_Qp_feq"); - symbol(&_Qp_fne, "_Qp_fne"); - symbol(&_Qp_flt, "_Qp_flt"); - symbol(&_Qp_fle, "_Qp_fle"); - symbol(&_Qp_fgt, "_Qp_fgt"); - symbol(&_Qp_fge, "_Qp_fge"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&_Q_cmp, "_Q_cmp"); - symbol(&_Q_feq, "_Q_feq"); - symbol(&_Q_fne, "_Q_fne"); - symbol(&_Q_flt, "_Q_flt"); - symbol(&_Q_fle, "_Q_fle"); - symbol(&_Q_fgt, "_Q_fgt"); - symbol(&_Q_fge, "_Q_fge"); - } - symbol(&__eqtf2, "__eqtf2"); - symbol(&__netf2, "__netf2"); - symbol(&__letf2, "__letf2"); - symbol(&__cmptf2, "__cmptf2"); - symbol(&__lttf2, "__lttf2"); -} - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__letf2`, `__eqtf2`, `__netf2`, `__cmptf2`, -/// and `__lttf2`. -fn __cmptf2(a: f128, b: f128) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f128, comparef.LE, a, b)); -} - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -fn __letf2(a: f128, b: f128) callconv(.c) i32 { - return __cmptf2(a, b); -} - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqtf2 and __netf2 are defined -/// to have the same return value. -fn __eqtf2(a: f128, b: f128) callconv(.c) i32 { - return __cmptf2(a, b); -} - -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqtf2 and __netf2 are defined -/// to have the same return value. -fn __netf2(a: f128, b: f128) callconv(.c) i32 { - return __cmptf2(a, b); -} - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -fn __lttf2(a: f128, b: f128) callconv(.c) i32 { - return __cmptf2(a, b); -} - -const SparcFCMP = enum(i32) { - Equal = 0, - Less = 1, - Greater = 2, - Unordered = 3, -}; - -fn _Qp_cmp(a: *const f128, b: *const f128) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f128, SparcFCMP, a.*, b.*)); -} - -fn _Qp_feq(a: *const f128, b: *const f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b)))) == .Equal; -} - -fn _Qp_fne(a: *const f128, b: *const f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b)))) != .Equal; -} - -fn _Qp_flt(a: *const f128, b: *const f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b)))) == .Less; -} - -fn _Qp_fgt(a: *const f128, b: *const f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b)))) == .Greater; -} - -fn _Qp_fge(a: *const f128, b: *const f128) callconv(.c) bool { - return switch (@as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b))))) { - .Equal, .Greater => true, - .Less, .Unordered => false, - }; -} - -fn _Qp_fle(a: *const f128, b: *const f128) callconv(.c) bool { - return switch (@as(SparcFCMP, @fromBackingInt(@intCast(_Qp_cmp(a, b))))) { - .Equal, .Less => true, - .Greater, .Unordered => false, - }; -} - -fn _Q_cmp(a: f128, b: f128) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f128, SparcFCMP, a, b)); -} - -fn _Q_feq(a: f128, b: f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b)))) == .Equal; -} - -fn _Q_fne(a: f128, b: f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b)))) != .Equal; -} - -fn _Q_flt(a: f128, b: f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b)))) == .Less; -} - -fn _Q_fgt(a: f128, b: f128) callconv(.c) bool { - return @as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b)))) == .Greater; -} - -fn _Q_fge(a: f128, b: f128) callconv(.c) bool { - return switch (@as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b))))) { - .Equal, .Greater => true, - .Less, .Unordered => false, - }; -} - -fn _Q_fle(a: f128, b: f128) callconv(.c) bool { - return switch (@as(SparcFCMP, @fromBackingInt(@intCast(_Q_cmp(a, b))))) { - .Equal, .Less => true, - .Greater, .Unordered => false, - }; -} diff --git a/lib/compiler_rt/cmpxf2.zig b/lib/compiler_rt/cmpxf2.zig deleted file mode 100644 index 8146cd83c2f05bff98a3a122de2431820d897a08..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/cmpxf2.zig +++ /dev/null @@ -1,49 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const comparef = @import("./comparef.zig"); - -comptime { - symbol(&__eqxf2, "__eqxf2"); - symbol(&__nexf2, "__nexf2"); - symbol(&__lexf2, "__lexf2"); - symbol(&__cmpxf2, "__cmpxf2"); - symbol(&__ltxf2, "__ltxf2"); -} - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__lexf2`, `__eqxf2`, `__nexf2`, `__cmpxf2`, -/// and `__ltxf2`. -fn __cmpxf2(a: f80, b: f80) callconv(.c) i32 { - return @backingInt(comparef.cmp_f80(comparef.LE, a, b)); -} - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -fn __lexf2(a: f80, b: f80) callconv(.c) i32 { - return __cmpxf2(a, b); -} - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqxf2 and __nexf2 are defined -/// to have the same return value. -fn __eqxf2(a: f80, b: f80) callconv(.c) i32 { - return __cmpxf2(a, b); -} - -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqxf2 and __nexf2 are defined -/// to have the same return value. -fn __nexf2(a: f80, b: f80) callconv(.c) i32 { - return __cmpxf2(a, b); -} - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -fn __ltxf2(a: f80, b: f80) callconv(.c) i32 { - return __cmpxf2(a, b); -} diff --git a/lib/compiler_rt/comparedf2_test.zig b/lib/compiler_rt/comparedf2_test.zig index dbae6bbeeca09ef401a17334d57f3f3be824c781..cb8a7b727f993f5b57d46e55cfffdafa1343cc78 100644 --- a/lib/compiler_rt/comparedf2_test.zig +++ b/lib/compiler_rt/comparedf2_test.zig @@ -5,52 +5,12 @@ const std = @import("std"); const builtin = @import("builtin"); -const __eqdf2 = @import("./cmpdf2.zig").__eqdf2; -const __ledf2 = @import("./cmpdf2.zig").__ledf2; -const __ltdf2 = @import("./cmpdf2.zig").__ltdf2; -const __nedf2 = @import("./cmpdf2.zig").__nedf2; +const compiler_rt = @import("../compiler_rt.zig"); -const __gedf2 = @import("./gedf2.zig").__gedf2; -const __gtdf2 = @import("./gedf2.zig").__gtdf2; - -const __unorddf2 = @import("./unorddf2.zig").__unorddf2; - -const TestVector = struct { - a: f64, - b: f64, - eqReference: c_int, - geReference: c_int, - gtReference: c_int, - leReference: c_int, - ltReference: c_int, - neReference: c_int, - unReference: c_int, -}; - -fn test__cmpdf2(vector: TestVector) bool { - if (__eqdf2(vector.a, vector.b) != vector.eqReference) { - return false; - } - if (__gedf2(vector.a, vector.b) != vector.geReference) { - return false; - } - if (__gtdf2(vector.a, vector.b) != vector.gtReference) { - return false; - } - if (__ledf2(vector.a, vector.b) != vector.leReference) { - return false; - } - if (__ltdf2(vector.a, vector.b) != vector.ltReference) { - return false; - } - if (__nedf2(vector.a, vector.b) != vector.neReference) { - return false; - } - if (__unorddf2(vector.a, vector.b) != vector.unReference) { - return false; - } - return true; -} +const impl = @import("comparef.zig"); +const Order = impl.Order; +const cmp_f64 = impl.cmp_f64; +const unord_f64 = impl.unord_f64; const arguments = [_]f64{ std.math.nan(f64), @@ -73,36 +33,20 @@ const arguments = [_]f64{ std.math.inf(f64), }; -fn generateVector(comptime a: f64, comptime b: f64) TestVector { - const leResult = if (a < b) -1 else if (a == b) 0 else 1; - const geResult = if (a > b) 1 else if (a == b) 0 else -1; - const unResult = if (a != a or b != b) 1 else 0; - return TestVector{ - .a = a, - .b = b, - .eqReference = leResult, - .geReference = geResult, - .gtReference = geResult, - .leReference = leResult, - .ltReference = leResult, - .neReference = leResult, - .unReference = unResult, - }; -} - -const test_vectors = init: { - @setEvalBranchQuota(10000); - var vectors: [arguments.len * arguments.len]TestVector = undefined; +test "compare f64" { for (arguments[0..], 0..) |arg_i, i| { for (arguments[0..], 0..) |arg_j, j| { - vectors[(i * arguments.len) + j] = generateVector(arg_i, arg_j); + const expected_unord = i == 0 or j == 0; + const expected_order: ?Order = if (expected_unord) null else switch (std.math.order( + if (i >= 9) i - 1 else i, + if (j >= 9) j - 1 else j, + )) { + .lt => .lt, + .eq => .eq, + .gt => .gt, + }; + try std.testing.expect(expected_order == cmp_f64(arg_i, arg_j)); + try std.testing.expect(expected_unord == unord_f64(arg_i, arg_j)); } } - break :init vectors; -}; - -test "compare f64" { - for (test_vectors) |vector| { - try std.testing.expect(test__cmpdf2(vector)); - } } diff --git a/lib/compiler_rt/comparef.zig b/lib/compiler_rt/comparef.zig index a0f7551c74c9068909ef9e10c0ea71fa93140eef..d230e9a6b42f8ef88114e4d72b838f3f47c01cec 100644 --- a/lib/compiler_rt/comparef.zig +++ b/lib/compiler_rt/comparef.zig @@ -1,163 +1,309 @@ +const builtin = @import("builtin"); const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; +const Unordered = if (builtin.cpu.arch == .avr) + i8 +else if (builtin.cpu.arch.isAARCH64()) + i32 +else if (builtin.target.cTypeBitSize(.long).? >= builtin.target.ptrBitWidth()) + c_long +else + c_longlong; +pub const Order = enum(Unordered) { lt = -1, eq = 0, gt = 1 }; +const SparcOrder = enum(i32) { eq = 0, lt = 1, gt = 2, un = 3 }; + comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fcmpun, "__aeabi_fcmpun"); - } else { - symbol(&__unordsf2, "__unordsf2"); - } - - symbol(&__unordxf2, "__unordxf2"); - - symbol(&__eqhf2, "__eqhf2"); - symbol(&__nehf2, "__nehf2"); - symbol(&__lehf2, "__lehf2"); symbol(&__cmphf2, "__cmphf2"); - symbol(&__lthf2, "__lthf2"); + symbol(&__cmphf2, "__eqhf2"); + symbol(&__cmphf2, "__nehf2"); + symbol(&__cmphf2, "__lthf2"); + symbol(&__cmphf2, "__lehf2"); + symbol(&__gehf2, "__gthf2"); + symbol(&__gehf2, "__gehf2"); + symbol(&__unordhf2, "__unordhf2"); if (compiler_rt.want_aeabi) { symbol(&__aeabi_fcmpeq, "__aeabi_fcmpeq"); symbol(&__aeabi_fcmplt, "__aeabi_fcmplt"); symbol(&__aeabi_fcmple, "__aeabi_fcmple"); + symbol(&__aeabi_fcmpgt, "__aeabi_fcmpgt"); + symbol(&__aeabi_fcmpge, "__aeabi_fcmpge"); + symbol(&__aeabi_fcmpun, "__aeabi_fcmpun"); + + symbol(&__aeabi_dcmpeq, "__aeabi_dcmpeq"); + symbol(&__aeabi_dcmplt, "__aeabi_dcmplt"); + symbol(&__aeabi_dcmple, "__aeabi_dcmple"); + symbol(&__aeabi_dcmpgt, "__aeabi_dcmpgt"); + symbol(&__aeabi_dcmpge, "__aeabi_dcmpge"); + symbol(&__aeabi_dcmpun, "__aeabi_dcmpun"); } else { - symbol(&__eqsf2, "__eqsf2"); - symbol(&__nesf2, "__nesf2"); - symbol(&__lesf2, "__lesf2"); symbol(&__cmpsf2, "__cmpsf2"); - symbol(&__ltsf2, "__ltsf2"); + symbol(&__cmpsf2, "__eqsf2"); + symbol(&__cmpsf2, "__nesf2"); + symbol(&__cmpsf2, "__ltsf2"); + symbol(&__cmpsf2, "__lesf2"); + symbol(&__gesf2, "__gtsf2"); + symbol(&__gesf2, "__gesf2"); + symbol(&__unordsf2, "__unordsf2"); + + symbol(&__cmpdf2, "__cmpdf2"); + symbol(&__cmpdf2, "__eqdf2"); + symbol(&__cmpdf2, "__nedf2"); + symbol(&__cmpdf2, "__ltdf2"); + symbol(&__cmpdf2, "__ledf2"); + symbol(&__gedf2, "__gtdf2"); + symbol(&__gedf2, "__gedf2"); + symbol(&__unorddf2, "__unorddf2"); } + symbol(&__cmpxf2, "__cmpxf2"); + symbol(&__cmpxf2, "__eqxf2"); + symbol(&__cmpxf2, "__nexf2"); + symbol(&__cmpxf2, "__ltxf2"); + symbol(&__cmpxf2, "__lexf2"); + symbol(&__gexf2, "__gtxf2"); + symbol(&__gexf2, "__gexf2"); + symbol(&__unordxf2, "__unordxf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__cmptf2, "__eqkf2"); + symbol(&__cmptf2, "__nekf2"); + symbol(&__cmptf2, "__ltkf2"); + symbol(&__cmptf2, "__lekf2"); + symbol(&__getf2, "__gtkf2"); + symbol(&__getf2, "__gekf2"); symbol(&__unordtf2, "__unordkf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_cmp, "_Qp_cmp"); + symbol(&_Qp_feq, "_Qp_feq"); + symbol(&_Qp_fne, "_Qp_fne"); + symbol(&_Qp_flt, "_Qp_flt"); + symbol(&_Qp_fle, "_Qp_fle"); + symbol(&_Qp_fgt, "_Qp_fgt"); + symbol(&_Qp_fge, "_Qp_fge"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&_Q_cmp, "_Q_cmp"); + symbol(&_Q_feq, "_Q_feq"); + symbol(&_Q_fne, "_Q_fne"); + symbol(&_Q_flt, "_Q_flt"); + symbol(&_Q_fle, "_Q_fle"); + symbol(&_Q_fgt, "_Q_fgt"); + symbol(&_Q_fge, "_Q_fge"); + } else { + symbol(&__cmptf2, "__cmptf2"); + symbol(&__cmptf2, "__eqtf2"); + symbol(&__cmptf2, "__netf2"); + symbol(&__cmptf2, "__lttf2"); + symbol(&__cmptf2, "__letf2"); + symbol(&__getf2, "__gttf2"); + symbol(&__getf2, "__getf2"); + symbol(&__unordtf2, "__unordtf2"); } - symbol(&__unordtf2, "__unordtf2"); - symbol(&__unordhf2, "__unordhf2"); } -pub fn __unordhf2(a: f16, b: f16) callconv(.c) i32 { - return unordcmp(f16, a, b); +fn __cmphf2(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) Order { + return cmp_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b)) orelse .gt; } - -pub fn __unordtf2(a: f128, b: f128) callconv(.c) i32 { - return unordcmp(f128, a, b); +fn __gehf2(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) Order { + return cmp_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b)) orelse .lt; } - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__lesf2`, `__eqsf2`, `__nesf2`, `__cmpsf2`, -/// and `__ltsf2`. -fn __cmpsf2(a: f32, b: f32) callconv(.c) i32 { - return @backingInt(cmpf2(f32, LE, a, b)); +fn __unordhf2(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); } - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -pub fn __lesf2(a: f32, b: f32) callconv(.c) i32 { - return __cmpsf2(a, b); +pub fn cmp_f16(a: f16, b: f16) ?Order { + return cmpf2(f16, a, b); } - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqsf2 and __nesf2 are defined -/// to have the same return value. -pub fn __eqsf2(a: f32, b: f32) callconv(.c) i32 { - return __cmpsf2(a, b); +pub fn unord_f16(a: f16, b: f16) bool { + return unord(f16, a, b); } -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqsf2 and __nesf2 are defined -/// to have the same return value. -pub fn __nesf2(a: f32, b: f32) callconv(.c) i32 { - return __cmpsf2(a, b); +fn __cmpsf2(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) Order { + return cmp_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b)) orelse .gt; } - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -pub fn __ltsf2(a: f32, b: f32) callconv(.c) i32 { - return __cmpsf2(a, b); -} - fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(cmpf2(f32, LE, a, b) == .Equal); + return @intFromBool(cmp_f32(a, b) == .eq); } - fn __aeabi_fcmplt(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(cmpf2(f32, LE, a, b) == .Less); + return @intFromBool(cmp_f32(a, b) == .lt); } - fn __aeabi_fcmple(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(cmpf2(f32, LE, a, b) != .Greater); + return @intFromBool(cmp_f32(a, b) orelse .gt != .gt); } - -/// "These functions calculate a <=> b. That is, if a is less than b, they return -1; -/// if a is greater than b, they return 1; and if a and b are equal they return 0. -/// If either argument is NaN they return 1..." -/// -/// Note that this matches the definition of `__lehf2`, `__eqhf2`, `__nehf2`, `__cmphf2`, -/// and `__lthf2`. -fn __cmphf2(a: f16, b: f16) callconv(.c) i32 { - return @backingInt(cmpf2(f16, LE, a, b)); +fn __gesf2(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) Order { + return cmp_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b)) orelse .lt; } - -/// "These functions return a value less than or equal to zero if neither argument is NaN, -/// and a is less than or equal to b." -fn __lehf2(a: f16, b: f16) callconv(.c) i32 { - return __cmphf2(a, b); +fn __aeabi_fcmpge(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f32(a, b) orelse .lt != .lt); } - -/// "These functions return zero if neither argument is NaN, and a and b are equal." -/// Note that due to some kind of historical accident, __eqhf2 and __nehf2 are defined -/// to have the same return value. -fn __eqhf2(a: f16, b: f16) callconv(.c) i32 { - return __cmphf2(a, b); +fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f32(a, b) == .gt); } - -/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal." -/// Note that due to some kind of historical accident, __eqhf2 and __nehf2 are defined -/// to have the same return value. -fn __nehf2(a: f16, b: f16) callconv(.c) i32 { - return __cmphf2(a, b); +fn __unordsf2(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); } - -/// "These functions return a value less than zero if neither argument is NaN, and a -/// is strictly less than b." -fn __lthf2(a: f16, b: f16) callconv(.c) i32 { - return __cmphf2(a, b); -} - -fn __unordxf2(a: f80, b: f80) callconv(.c) i32 { - return unordcmp(f80, a, b); -} - -pub fn __unordsf2(a: f32, b: f32) callconv(.c) i32 { - return unordcmp(f32, a, b); -} - fn __aeabi_fcmpun(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return unordcmp(f32, a, b); + return @intFromBool(unord_f32(a, b)); } +pub fn cmp_f32(a: f32, b: f32) ?Order { + return cmpf2(f32, a, b); +} +pub fn unord_f32(a: f32, b: f32) bool { + return unord(f32, a, b); +} + +fn __cmpdf2(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) Order { + return cmp_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b)) orelse .gt; +} +fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) == .eq); +} +fn __aeabi_dcmplt(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) == .lt); +} +fn __aeabi_dcmple(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) orelse .gt != .gt); +} +fn __gedf2(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) Order { + return cmp_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b)) orelse .lt; +} +fn __aeabi_dcmpge(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) orelse .lt != .lt); +} +fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(cmp_f64(a, b) == .gt); +} +fn __unorddf2(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +fn __aeabi_dcmpun(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return @intFromBool(unord_f64(a, b)); +} +pub fn cmp_f64(a: f64, b: f64) ?Order { + return cmpf2(f64, a, b); +} +pub fn unord_f64(a: f64, b: f64) bool { + return unord(f64, a, b); +} + +fn __cmpxf2(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) Order { + return cmp_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b)) orelse .gt; +} +fn __gexf2(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) Order { + return cmp_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b)) orelse .lt; +} +fn __unordxf2(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn cmp_f80(a: f80, b: f80) ?Order { + const a_rep = std.math.F80.fromFloat(a); + const b_rep = std.math.F80.fromFloat(b); + const sig_bits = std.math.floatMantissaBits(f80); + const int_bit = 0x8000000000000000; + const sign_bit = 0x8000; + const special_exp = 0x7FFF; -pub const LE = enum(i32) { - Less = -1, - Equal = 0, - Greater = 1, + // If either a or b is NaN, they are unordered. + if ((a_rep.exp & special_exp == special_exp and a_rep.fraction ^ int_bit != 0) or + (b_rep.exp & special_exp == special_exp and b_rep.fraction ^ int_bit != 0)) + return null; - const Unordered: LE = .Greater; -}; + // If a and b are both zeros, they are equal. + if ((a_rep.fraction | b_rep.fraction) | ((a_rep.exp | b_rep.exp) & special_exp) == 0) + return .eq; -pub const GE = enum(i32) { - Less = -1, - Equal = 0, - Greater = 1, + if (@intFromBool(a_rep.exp == b_rep.exp) & @intFromBool(a_rep.fraction == b_rep.fraction) != 0) { + return .eq; + } else if (a_rep.exp & sign_bit != b_rep.exp & sign_bit) { + // signs are different + if (@as(i16, @bitCast(a_rep.exp)) < @as(i16, @bitCast(b_rep.exp))) { + return .lt; + } else { + return .gt; + } + } else { + const a_fraction = a_rep.fraction | (@as(u80, a_rep.exp) << sig_bits); + const b_fraction = b_rep.fraction | (@as(u80, b_rep.exp) << sig_bits); + if ((a_fraction < b_fraction) == (a_rep.exp & sign_bit == 0)) { + return .lt; + } else { + return .gt; + } + } +} +pub fn unord_f80(a: f80, b: f80) bool { + return unord(f80, a, b); +} - const Unordered: GE = .Less; -}; +fn __cmptf2(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) Order { + return cmp_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b)) orelse .gt; +} +fn __getf2(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) Order { + return cmp_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b)) orelse .lt; +} +fn __unordtf2(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) Unordered { + return @intFromBool(unord_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} +fn _Qp_cmp(a: *const f128, b: *const f128) callconv(.c) SparcOrder { + return switch (cmp_f128(a.*, b.*) orelse return .un) { + .lt => .lt, + .eq => .eq, + .gt => .gt, + }; +} +fn _Qp_feq(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a.*, b.*) == .eq); +} +fn _Qp_fne(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a.*, b.*) != .eq); +} +fn _Qp_flt(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a.*, b.*) == .lt); +} +fn _Qp_fle(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool((cmp_f128(a.*, b.*) orelse .gt) != .gt); +} +fn _Qp_fgt(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a.*, b.*) == .gt); +} +fn _Qp_fge(a: *const f128, b: *const f128) callconv(.c) i32 { + return @intFromBool((cmp_f128(a.*, b.*) orelse .lt) != .lt); +} +fn _Q_cmp(a: f128, b: f128) callconv(.c) SparcOrder { + return switch (cmp_f128(a, b) orelse return .un) { + .lt => .lt, + .eq => .eq, + .gt => .gt, + }; +} +fn _Q_feq(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a, b) == .eq); +} +fn _Q_fne(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a, b) != .eq); +} +fn _Q_flt(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a, b) == .lt); +} +fn _Q_fle(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool((cmp_f128(a, b) orelse .gt) != .gt); +} +fn _Q_fgt(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool(cmp_f128(a, b) == .gt); +} +fn _Q_fge(a: f128, b: f128) callconv(.c) i32 { + return @intFromBool((cmp_f128(a, b) orelse .lt) != .lt); +} +pub fn cmp_f128(a: f128, b: f128) ?Order { + return cmpf2(f128, a, b); +} +pub fn unord_f128(a: f128, b: f128) bool { + return unord(f128, a, b); +} -pub inline fn cmpf2(comptime T: type, comptime RT: type, a: T, b: T) RT { +inline fn cmpf2(comptime T: type, a: T, b: T) ?Order { const bits = @typeInfo(T).float.bits; const srep_t = @Int(.signed, bits); const rep_t = @Int(.unsigned, bits); @@ -175,81 +321,42 @@ pub inline fn cmpf2(comptime T: type, comptime RT: type, a: T, b: T) RT { const bAbs = @as(rep_t, @bitCast(bInt)) & absMask; // If either a or b is NaN, they are unordered. - if (aAbs > infRep or bAbs > infRep) return RT.Unordered; + if (aAbs > infRep or bAbs > infRep) return null; // If a and b are both zeros, they are equal. - if ((aAbs | bAbs) == 0) return .Equal; + if ((aAbs | bAbs) == 0) return .eq; // If at least one of a and b is positive, we get the same result comparing // a and b as signed integers as we would with a floating-point compare. if ((aInt & bInt) >= 0) { if (aInt < bInt) { - return .Less; + return .lt; } else if (aInt == bInt) { - return .Equal; - } else return .Greater; + return .eq; + } else return .gt; } else { // Otherwise, both are negative, so we need to flip the sense of the // comparison to get the correct result. (This assumes a twos- or ones- // complement integer representation; if integers are represented in a // sign-magnitude representation, then this flip is incorrect). if (aInt > bInt) { - return .Less; + return .lt; } else if (aInt == bInt) { - return .Equal; - } else return .Greater; + return .eq; + } else return .gt; } } -pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT { - const a_rep = std.math.F80.fromFloat(a); - const b_rep = std.math.F80.fromFloat(b); - const sig_bits = std.math.floatMantissaBits(f80); - const int_bit = 0x8000000000000000; - const sign_bit = 0x8000; - const special_exp = 0x7FFF; - - // If either a or b is NaN, they are unordered. - if ((a_rep.exp & special_exp == special_exp and a_rep.fraction ^ int_bit != 0) or - (b_rep.exp & special_exp == special_exp and b_rep.fraction ^ int_bit != 0)) - return RT.Unordered; - - // If a and b are both zeros, they are equal. - if ((a_rep.fraction | b_rep.fraction) | ((a_rep.exp | b_rep.exp) & special_exp) == 0) - return .Equal; - - if (@intFromBool(a_rep.exp == b_rep.exp) & @intFromBool(a_rep.fraction == b_rep.fraction) != 0) { - return .Equal; - } else if (a_rep.exp & sign_bit != b_rep.exp & sign_bit) { - // signs are different - if (@as(i16, @bitCast(a_rep.exp)) < @as(i16, @bitCast(b_rep.exp))) { - return .Less; - } else { - return .Greater; - } - } else { - const a_fraction = a_rep.fraction | (@as(u80, a_rep.exp) << sig_bits); - const b_fraction = b_rep.fraction | (@as(u80, b_rep.exp) << sig_bits); - if ((a_fraction < b_fraction) == (a_rep.exp & sign_bit == 0)) { - return .Less; - } else { - return .Greater; - } - } -} - -test "cmp_f80" { - inline for (.{ LE, GE }) |RT| { - try std.testing.expect(cmp_f80(RT, 1.0, 1.0) == RT.Equal); - try std.testing.expect(cmp_f80(RT, 0.0, -0.0) == RT.Equal); - try std.testing.expect(cmp_f80(RT, 2.0, 4.0) == RT.Less); - try std.testing.expect(cmp_f80(RT, 2.0, -4.0) == RT.Greater); - try std.testing.expect(cmp_f80(RT, -2.0, -4.0) == RT.Greater); - try std.testing.expect(cmp_f80(RT, -2.0, 4.0) == RT.Less); - } +test cmp_f80 { + try std.testing.expect(cmp_f80(1.0, 1.0) == .eq); + try std.testing.expect(cmp_f80(0.0, -0.0) == .eq); + try std.testing.expect(cmp_f80(2.0, 4.0) == .lt); + try std.testing.expect(cmp_f80(2.0, -4.0) == .gt); + try std.testing.expect(cmp_f80(-2.0, -4.0) == .gt); + try std.testing.expect(cmp_f80(-2.0, 4.0) == .lt); } -pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { +inline fn unord(comptime T: type, a: T, b: T) bool { const rep_t = @Int(.unsigned, @typeInfo(T).float.bits); const significandBits = std.math.floatMantissaBits(T); @@ -261,7 +368,7 @@ pub inline fn unordcmp(comptime T: type, a: T, b: T) i32 { const aAbs: rep_t = @as(rep_t, @bitCast(a)) & absMask; const bAbs: rep_t = @as(rep_t, @bitCast(b)) & absMask; - return @intFromBool(aAbs > infRep or bAbs > infRep); + return aAbs > infRep or bAbs > infRep; } test { diff --git a/lib/compiler_rt/comparesf2_test.zig b/lib/compiler_rt/comparesf2_test.zig index d42e1ca6db124de615f2eb3a74eadfeb119992eb..5e34b00604b8f7d608cb6d21e51d8118d26d013b 100644 --- a/lib/compiler_rt/comparesf2_test.zig +++ b/lib/compiler_rt/comparesf2_test.zig @@ -5,52 +5,12 @@ const std = @import("std"); const builtin = @import("builtin"); -const __eqsf2 = @import("./comparef.zig").__eqsf2; -const __lesf2 = @import("./comparef.zig").__lesf2; -const __ltsf2 = @import("./comparef.zig").__ltsf2; -const __nesf2 = @import("./comparef.zig").__nesf2; +const compiler_rt = @import("../compiler_rt.zig"); -const __gesf2 = @import("./gesf2.zig").__gesf2; -const __gtsf2 = @import("./gesf2.zig").__gtsf2; - -const __unordsf2 = @import("./comparef.zig").__unordsf2; - -const TestVector = struct { - a: f32, - b: f32, - eqReference: c_int, - geReference: c_int, - gtReference: c_int, - leReference: c_int, - ltReference: c_int, - neReference: c_int, - unReference: c_int, -}; - -fn test__cmpsf2(vector: TestVector) bool { - if (__eqsf2(vector.a, vector.b) != vector.eqReference) { - return false; - } - if (__gesf2(vector.a, vector.b) != vector.geReference) { - return false; - } - if (__gtsf2(vector.a, vector.b) != vector.gtReference) { - return false; - } - if (__lesf2(vector.a, vector.b) != vector.leReference) { - return false; - } - if (__ltsf2(vector.a, vector.b) != vector.ltReference) { - return false; - } - if (__nesf2(vector.a, vector.b) != vector.neReference) { - return false; - } - if (__unordsf2(vector.a, vector.b) != vector.unReference) { - return false; - } - return true; -} +const impl = @import("comparef.zig"); +const Order = impl.Order; +const cmp_f32 = impl.cmp_f32; +const unord_f32 = impl.unord_f32; const arguments = [_]f32{ std.math.nan(f32), @@ -73,36 +33,20 @@ const arguments = [_]f32{ std.math.inf(f32), }; -fn generateVector(comptime a: f32, comptime b: f32) TestVector { - const leResult = if (a < b) -1 else if (a == b) 0 else 1; - const geResult = if (a > b) 1 else if (a == b) 0 else -1; - const unResult = if (a != a or b != b) 1 else 0; - return TestVector{ - .a = a, - .b = b, - .eqReference = leResult, - .geReference = geResult, - .gtReference = geResult, - .leReference = leResult, - .ltReference = leResult, - .neReference = leResult, - .unReference = unResult, - }; -} - -const test_vectors = init: { - @setEvalBranchQuota(10000); - var vectors: [arguments.len * arguments.len]TestVector = undefined; +test "compare f32" { for (arguments[0..], 0..) |arg_i, i| { for (arguments[0..], 0..) |arg_j, j| { - vectors[(i * arguments.len) + j] = generateVector(arg_i, arg_j); + const expected_unord = i == 0 or j == 0; + const expected_order: ?Order = if (expected_unord) null else switch (std.math.order( + i - @intFromBool(i >= 9), + j - @intFromBool(j >= 9), + )) { + .lt => .lt, + .eq => .eq, + .gt => .gt, + }; + try std.testing.expect(expected_order == cmp_f32(arg_i, arg_j)); + try std.testing.expect(expected_unord == unord_f32(arg_i, arg_j)); } } - break :init vectors; -}; - -test "compare f32" { - for (test_vectors) |vector| { - try std.testing.expect(test__cmpsf2(vector)); - } } diff --git a/lib/compiler_rt/cos.zig b/lib/compiler_rt/cos.zig index a207f0244f941c3e6730f9e6f5891201840120cc..72ea9026472a1f8e31bca5cddc9e106cfd66155b 100644 --- a/lib/compiler_rt/cos.zig +++ b/lib/compiler_rt/cos.zig @@ -13,31 +13,34 @@ const expect = std.testing.expect; const expectApproxEqAbs = std.testing.expectApproxEqAbs; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const trig = @import("trig.zig"); const rem_pio2 = @import("rem_pio2.zig").rem_pio2; const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l; comptime { - symbol(&cosh, "__cosh"); - symbol(&cosl, "__cosl"); + symbol(&__cosh, "__cosh"); symbol(&cosf, "cosf"); symbol(&cos, "cos"); - symbol(&cosx, "__cosx"); - if (compiler_rt.want_ppc_abi) { - symbol(&cosq, "cosf128"); - } - symbol(&cosq, "cosq"); + symbol(&__cosx, "__cosx"); + symbol(&cosq, "cosf128"); symbol(&cosl, "cosl"); + symbol(&cosl, "__cosl"); // required by musl } -pub fn cosh(a: f16) callconv(.c) f16 { +fn __cosh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(cos_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn cos_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(cosf(a)); + return @floatCast(cos_f32(x)); } -pub fn cosf(x: f32) callconv(.c) f32 { +fn cosf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(cos_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn cos_f32(x: f32) f32 { // Small multiples of pi/2 rounded to double precision. const c1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 const c2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 @@ -94,7 +97,10 @@ pub fn cosf(x: f32) callconv(.c) f32 { }; } -pub fn cos(x: f64) callconv(.c) f64 { +fn cos(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(cos_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn cos_f64(x: f64) f64 { var ix = @as(u64, @bitCast(x)) >> 32; ix &= 0x7fffffff; @@ -123,7 +129,10 @@ pub fn cos(x: f64) callconv(.c) f64 { }; } -pub fn cosx(x: f80) callconv(.c) f80 { +fn __cosx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(cos_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn cos_f80(x: f80) f80 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -147,7 +156,10 @@ pub fn cosx(x: f80) callconv(.c) f80 { }; } -pub fn cosq(x: f128) callconv(.c) f128 { +fn cosq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(cos_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn cos_f128(x: f128) f128 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -173,20 +185,21 @@ pub fn cosq(x: f128) callconv(.c) f128 { pub fn cosl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return cos(x), - 80 => return cosx(x), - 128 => return cosq(x), - else => @compileError("unreachable"), + 64 => return cos_f64(x), + 80 => return cos_f80(x), + 128 => return cos_f128(x), + else => comptime unreachable, } } fn testCosSpecial(comptime T: type) !void { const f = switch (T) { - f32 => cosf, - f64 => cos, - f80 => cosx, - f128 => cosq, - else => @compileError("unimplemented"), + f16 => cos_f16, + f32 => cos_f32, + f64 => cos_f64, + f80 => cos_f80, + f128 => cos_f128, + else => comptime unreachable, }; try expect(f(0.0) == 1.0); @@ -198,13 +211,13 @@ fn testCosSpecial(comptime T: type) !void { test "cos32.normal" { const epsilon = math.floatEps(f32); - try expectApproxEqAbs(@as(f32, 1.0), cosf(0.0), epsilon); - try expectApproxEqAbs(@as(f32, 0.9800666), cosf(0.2), epsilon); - try expectApproxEqAbs(@as(f32, 0.6276231), cosf(0.8923), epsilon); - try expectApproxEqAbs(@as(f32, 0.0707372), cosf(1.5), epsilon); - try expectApproxEqAbs(@as(f32, 0.0707372), cosf(-1.5), epsilon); - try expectApproxEqAbs(@as(f32, 0.96913195), cosf(37.45), epsilon); - try expectApproxEqAbs(@as(f32, 0.40079966), cosf(89.123), epsilon); + try expectApproxEqAbs(@as(f32, 1.0), cos_f32(0.0), epsilon); + try expectApproxEqAbs(@as(f32, 0.9800666), cos_f32(0.2), epsilon); + try expectApproxEqAbs(@as(f32, 0.6276231), cos_f32(0.8923), epsilon); + try expectApproxEqAbs(@as(f32, 0.0707372), cos_f32(1.5), epsilon); + try expectApproxEqAbs(@as(f32, 0.0707372), cos_f32(-1.5), epsilon); + try expectApproxEqAbs(@as(f32, 0.96913195), cos_f32(37.45), epsilon); + try expectApproxEqAbs(@as(f32, 0.40079966), cos_f32(89.123), epsilon); } test "cos32.special" { @@ -213,13 +226,13 @@ test "cos32.special" { test "cos64.normal" { const epsilon = math.floatEps(f64); - try expectApproxEqAbs(@as(f64, 1.0), cos(0.0), epsilon); - try expectApproxEqAbs(@as(f64, 0.9800665778412416), cos(0.2), epsilon); - try expectApproxEqAbs(@as(f64, 0.6276230983360804), cos(0.8923), epsilon); - try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos(1.5), epsilon); - try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos(-1.5), epsilon); - try expectApproxEqAbs(@as(f64, 0.9691317730707778), cos(37.45), epsilon); - try expectApproxEqAbs(@as(f64, 0.4008006809354791), cos(89.123), epsilon); + try expectApproxEqAbs(@as(f64, 1.0), cos_f64(0.0), epsilon); + try expectApproxEqAbs(@as(f64, 0.9800665778412416), cos_f64(0.2), epsilon); + try expectApproxEqAbs(@as(f64, 0.6276230983360804), cos_f64(0.8923), epsilon); + try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos_f64(1.5), epsilon); + try expectApproxEqAbs(@as(f64, 0.0707372016677029), cos_f64(-1.5), epsilon); + try expectApproxEqAbs(@as(f64, 0.9691317730707778), cos_f64(37.45), epsilon); + try expectApproxEqAbs(@as(f64, 0.4008006809354791), cos_f64(89.123), epsilon); } test "cos64.special" { @@ -228,13 +241,13 @@ test "cos64.special" { test "cos80.normal" { const epsilon = math.floatEps(f80); - try expectApproxEqAbs(@as(f80, 1.0), cosx(0.0), epsilon); - try expectApproxEqAbs(@as(f80, 0.98006657784124163112419651674816888), cosx(0.2), epsilon); - try expectApproxEqAbs(@as(f80, 0.62762309833608037003563995939286067), cosx(0.8923), epsilon); - try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cosx(1.5), epsilon); - try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cosx(-1.5), epsilon); - try expectApproxEqAbs(@as(f80, 0.9691317730707771246), cosx(37.45), epsilon); - try expectApproxEqAbs(@as(f80, 0.4008006809354834001), cosx(89.123), epsilon); + try expectApproxEqAbs(@as(f80, 1.0), cos_f80(0.0), epsilon); + try expectApproxEqAbs(@as(f80, 0.98006657784124163112419651674816888), cos_f80(0.2), epsilon); + try expectApproxEqAbs(@as(f80, 0.62762309833608037003563995939286067), cos_f80(0.8923), epsilon); + try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cos_f80(1.5), epsilon); + try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), cos_f80(-1.5), epsilon); + try expectApproxEqAbs(@as(f80, 0.9691317730707771246), cos_f80(37.45), epsilon); + try expectApproxEqAbs(@as(f80, 0.4008006809354834001), cos_f80(89.123), epsilon); } test "cos80.special" { @@ -243,13 +256,13 @@ test "cos80.special" { test "cos128.normal" { const epsilon = math.floatEps(f128); - try expectApproxEqAbs(@as(f128, 1.0), cosq(0.0), epsilon); - try expectApproxEqAbs(@as(f128, 0.98006657784124163112419651674816888), cosq(0.2), epsilon); - try expectApproxEqAbs(@as(f128, 0.62762309833608037003563995939286067), cosq(0.8923), epsilon); - try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cosq(1.5), epsilon); - try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cosq(-1.5), epsilon); - try expectApproxEqAbs(@as(f128, 0.96913177307077712443149563847233230), cosq(37.45), epsilon); - try expectApproxEqAbs(@as(f128, 0.40080068093548339848199454493704702), cosq(89.123), epsilon); + try expectApproxEqAbs(@as(f128, 1.0), cos_f128(0.0), epsilon); + try expectApproxEqAbs(@as(f128, 0.98006657784124163112419651674816888), cos_f128(0.2), epsilon); + try expectApproxEqAbs(@as(f128, 0.62762309833608037003563995939286067), cos_f128(0.8923), epsilon); + try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cos_f128(1.5), epsilon); + try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), cos_f128(-1.5), epsilon); + try expectApproxEqAbs(@as(f128, 0.96913177307077712443149563847233230), cos_f128(37.45), epsilon); + try expectApproxEqAbs(@as(f128, 0.40080068093548339848199454493704702), cos_f128(89.123), epsilon); } test "cos128.special" { diff --git a/lib/compiler_rt/count0bits.zig b/lib/compiler_rt/count0bits.zig index a8d0445dc69276e4639211818eb42707a8782c6c..fca372b33b98865ec041ee3ca764a5d8207ae330 100644 --- a/lib/compiler_rt/count0bits.zig +++ b/lib/compiler_rt/count0bits.zig @@ -1,6 +1,7 @@ const builtin = @import("builtin"); const std = @import("std"); -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__clzsi2, "__clzsi2"); diff --git a/lib/compiler_rt/divc3.zig b/lib/compiler_rt/divc3.zig index 92d2b39f663d272bdb83042f69abcd6a91c2ba09..a76a63c7e0f9059a112dc5c3b4406349766351f6 100644 --- a/lib/compiler_rt/divc3.zig +++ b/lib/compiler_rt/divc3.zig @@ -7,12 +7,81 @@ const maxInt = std.math.maxInt; const minInt = std.math.minInt; const isFinite = std.math.isFinite; const copysign = std.math.copysign; -const Complex = @import("mulc3.zig").Complex; + +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; +const Complex = compiler_rt.Complex; + +comptime { + if (@import("builtin").zig_backend != .stage2_c) { + symbol(&__divhc3, "__divhc3"); + symbol(&__divsc3, "__divsc3"); + symbol(&__divdc3, "__divdc3"); + symbol(&__divxc3, "__divxc3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__divtc3, "__divkc3"); + } else { + symbol(&__divtc3, "__divtc3"); + } + } +} + +fn __divhc3(lhs_real: compiler_rt.f16.Abi, lhs_imag: compiler_rt.f16.Abi, rhs_real: compiler_rt.f16.Abi, rhs_imag: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.complex.Abi { + return compiler_rt.f16.complex.toAbi(div_cf16( + compiler_rt.f16.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f16.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf16(a: Complex(f16), b: Complex(f16)) Complex(f16) { + return divc3(f16, a, b); +} + +fn __divsc3(lhs_real: compiler_rt.f32.Abi, lhs_imag: compiler_rt.f32.Abi, rhs_real: compiler_rt.f32.Abi, rhs_imag: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.complex.Abi { + return compiler_rt.f32.complex.toAbi(div_cf32( + compiler_rt.f32.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f32.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf32(a: Complex(f32), b: Complex(f32)) Complex(f32) { + return divc3(f32, a, b); +} + +fn __divdc3(lhs_real: compiler_rt.f64.Abi, lhs_imag: compiler_rt.f64.Abi, rhs_real: compiler_rt.f64.Abi, rhs_imag: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.complex.Abi { + return compiler_rt.f64.complex.toAbi(div_cf64( + compiler_rt.f64.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f64.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf64(a: Complex(f64), b: Complex(f64)) Complex(f64) { + return divc3(f64, a, b); +} + +fn __divxc3(lhs_real: compiler_rt.f80.Abi, lhs_imag: compiler_rt.f80.Abi, rhs_real: compiler_rt.f80.Abi, rhs_imag: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.complex.Abi { + return compiler_rt.f80.complex.toAbi(div_cf80( + compiler_rt.f80.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f80.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf80(a: Complex(f80), b: Complex(f80)) Complex(f80) { + return divc3(f80, a, b); +} + +fn __divtc3(lhs_real: compiler_rt.f128.Abi, lhs_imag: compiler_rt.f128.Abi, rhs_real: compiler_rt.f128.Abi, rhs_imag: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.complex.Abi { + return compiler_rt.f128.complex.toAbi(div_cf128( + compiler_rt.f128.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f128.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn div_cf128(a: Complex(f128), b: Complex(f128)) Complex(f128) { + return divc3(f128, a, b); +} /// Implementation based on Annex G of C17 Standard (N2176) -pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) { - var c = c_in; - var d = d_in; +inline fn divc3(comptime T: type, lhs: Complex(T), rhs: Complex(T)) Complex(T) { + const a = lhs.real; + const b = lhs.imag; + var c = rhs.real; + var d = rhs.imag; // logbw used to prevent under/over-flow const logbw = ilogb(@max(@abs(c), @abs(d))); @@ -23,7 +92,7 @@ pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) { break :b logbw; } else 0; const denom = c * c + d * d; - const result = Complex(T){ + const result: Complex(T) = .{ .real = scalbn((a * c + b * d) / denom, -ilogbw), .imag = scalbn((b * c - a * d) / denom, -ilogbw), }; @@ -58,3 +127,7 @@ pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) { return result; } + +test { + _ = @import("divc3_test.zig"); +} diff --git a/lib/compiler_rt/divc3_test.zig b/lib/compiler_rt/divc3_test.zig index d3c400d46cacb1f12ec677d0f5dd0fb661bace4d..277a879253eed991a5e2cfa8453e8d28ab589f21 100644 --- a/lib/compiler_rt/divc3_test.zig +++ b/lib/compiler_rt/divc3_test.zig @@ -2,76 +2,53 @@ const std = @import("std"); const math = std.math; const expect = std.testing.expect; -const Complex = @import("./mulc3.zig").Complex; -const __divhc3 = @import("./divhc3.zig").__divhc3; -const __divsc3 = @import("./divsc3.zig").__divsc3; -const __divdc3 = @import("./divdc3.zig").__divdc3; -const __divxc3 = @import("./divxc3.zig").__divxc3; -const __divtc3 = @import("./divtc3.zig").__divtc3; +const Complex = @import("../compiler_rt.zig").Complex; + +const impl = @import("divc3.zig"); +const div_cf16 = impl.div_cf16; +const div_cf32 = impl.div_cf32; +const div_cf64 = impl.div_cf64; +const div_cf80 = impl.div_cf80; +const div_cf128 = impl.div_cf128; test "divc3" { - try testDiv(f16, __divhc3); - try testDiv(f32, __divsc3); - try testDiv(f64, __divdc3); - try testDiv(f80, __divxc3); - try testDiv(f128, __divtc3); + try testDiv(f16, div_cf16); + try testDiv(f32, div_cf32); + try testDiv(f64, div_cf64); + try testDiv(f80, div_cf80); + try testDiv(f128, div_cf128); } -fn testDiv(comptime T: type, comptime f: fn (T, T, T, T) callconv(.c) Complex(T)) !void { +fn testDiv(comptime T: type, comptime f: fn (Complex(T), Complex(T)) Complex(T)) !void { { - const a: T = 1.0; - const b: T = 0.0; - const c: T = -1.0; - const d: T = 0.0; - - const result = f(a, b, c, d); + const result = f(.{ .real = 1.0, .imag = 0.0 }, .{ .real = -1.0, .imag = 0.0 }); try expect(result.real == -1.0); - try expect(result.imag == 0.0); + try expect(math.isNegativeZero(result.imag)); } { - const a: T = 1.0; - const b: T = 0.0; - const c: T = -4.0; - const d: T = 0.0; - - const result = f(a, b, c, d); + const result = f(.{ .real = 1.0, .imag = 0.0 }, .{ .real = -4.0, .imag = 0.0 }); try expect(result.real == -0.25); - try expect(result.imag == 0.0); + try expect(math.isNegativeZero(result.imag)); } { // if the first operand is an infinity and the second operand is a finite number, then the - // result of the / operator is an infinity; - const a: T = -math.inf(T); - const b: T = 0.0; - const c: T = -4.0; - const d: T = 1.0; - - const result = f(a, b, c, d); - try expect(result.real == math.inf(T)); - try expect(result.imag == math.inf(T)); + // resultult of the / operator is an infinity; + const result = f(.{ .real = -math.inf(T), .imag = 0.0 }, .{ .real = -4.0, .imag = 1.0 }); + try expect(math.isPositiveInf(result.real)); + try expect(math.isPositiveInf(result.imag)); } { // if the first operand is a finite number and the second operand is an infinity, then the // result of the / operator is a zero; - const a: T = 17.2; - const b: T = 0.0; - const c: T = -math.inf(T); - const d: T = 0.0; - - const result = f(a, b, c, d); - try expect(result.real == -0.0); - try expect(result.imag == 0.0); + const result = f(.{ .real = 17.2, .imag = 0.0 }, .{ .real = -math.inf(T), .imag = 0.0 }); + try expect(math.isNegativeZero(result.real)); + try expect(math.isNegativeZero(result.imag)); } { // if the first operand is a nonzero finite number or an infinity and the second operand is // a zero, then the result of the / operator is an infinity - const a: T = 1.1; - const b: T = 0.1; - const c: T = 0.0; - const d: T = 0.0; - - const result = f(a, b, c, d); - try expect(result.real == math.inf(T)); - try expect(result.imag == math.inf(T)); + const result = f(.{ .real = 1.1, .imag = 0.1 }, .{ .real = 0.0, .imag = 0.0 }); + try expect(math.isPositiveInf(result.real)); + try expect(math.isPositiveInf(result.imag)); } } diff --git a/lib/compiler_rt/divdc3.zig b/lib/compiler_rt/divdc3.zig deleted file mode 100644 index e26dd26d61552832bcd1d19c022e8b0455551a40..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divdc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__divdc3, "__divdc3"); - } -} - -pub fn __divdc3(a: f64, b: f64, c: f64, d: f64) callconv(.c) Complex(f64) { - return divc3.divc3(f64, a, b, c, d); -} diff --git a/lib/compiler_rt/divdf3.zig b/lib/compiler_rt/divdf3.zig index 3ad767dbf2292d403aa0e2aafbdaf20f80ff9571..90953e0d0616d6a211872eef0b0c18ba1ff0cdb4 100644 --- a/lib/compiler_rt/divdf3.zig +++ b/lib/compiler_rt/divdf3.zig @@ -17,15 +17,15 @@ comptime { } } -pub fn __divdf3(a: f64, b: f64) callconv(.c) f64 { - return div(a, b); +fn __divdf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(div_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); } fn __aeabi_ddiv(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return div(a, b); + return div_f64(a, b); } -inline fn div(a: f64, b: f64) f64 { +pub fn div_f64(a: f64, b: f64) f64 { const Z = @Int(.unsigned, 64); const SignedZ = @Int(.signed, 64); diff --git a/lib/compiler_rt/divdf3_test.zig b/lib/compiler_rt/divdf3_test.zig index 45de9b27ef794706fc6e0e297f4289be3ae549fc..cd927bafc4d28921e9fb0bf191537b43cb953986 100644 --- a/lib/compiler_rt/divdf3_test.zig +++ b/lib/compiler_rt/divdf3_test.zig @@ -6,7 +6,7 @@ const std = @import("std"); const math = std.math; const testing = std.testing; -const __divdf3 = @import("divdf3.zig").__divdf3; +const div_f64 = @import("divdf3.zig").div_f64; const nanRep: u64 = @as(u64, @bitCast(math.nan(f64))); const infRep: u64 = @as(u64, @bitCast(math.inf(f64))); @@ -30,7 +30,7 @@ fn compareResultD(result: f64, expected: u64) bool { } fn test__divdf3(a: f64, b: f64, expected: u64) !void { - const x = __divdf3(a, b); + const x = div_f64(a, b); const ret = compareResultD(x, expected); try testing.expect(ret == true); } diff --git a/lib/compiler_rt/divhc3.zig b/lib/compiler_rt/divhc3.zig deleted file mode 100644 index c9668f4ca8ae84840ab3ee65446b682b6223832b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divhc3.zig +++ /dev/null @@ -1,14 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__divhc3, "__divhc3"); - } -} - -pub fn __divhc3(a: f16, b: f16, c: f16, d: f16) callconv(.c) Complex(f16) { - return divc3.divc3(f16, a, b, c, d); -} diff --git a/lib/compiler_rt/divhf3.zig b/lib/compiler_rt/divhf3.zig deleted file mode 100644 index fc2710ff2761fce7e8822583b86aefc562f98486..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divhf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const divsf3 = @import("./divsf3.zig"); - -comptime { - symbol(&__divhf3, "__divhf3"); -} - -pub fn __divhf3(a: f16, b: f16) callconv(.c) f16 { - // TODO: more efficient implementation - return @floatCast(divsf3.__divsf3(a, b)); -} diff --git a/lib/compiler_rt/divmodei4.zig b/lib/compiler_rt/divmodei4.zig index 55c7ec5792549933d22e8962f58b8cb6e23a5d54..9198951fe554a89cd2f65c69ce3fea087952db0a 100644 --- a/lib/compiler_rt/divmodei4.zig +++ b/lib/compiler_rt/divmodei4.zig @@ -5,7 +5,7 @@ const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); const udivmod = @import("udivmodei4.zig").divmod; -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { symbol(&__divei4, "__divei4"); diff --git a/lib/compiler_rt/divsc3.zig b/lib/compiler_rt/divsc3.zig deleted file mode 100644 index 9378bfab8ce80584b3b5b1b6d1fbd70200ef6648..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divsc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__divsc3, "__divsc3"); - } -} - -pub fn __divsc3(a: f32, b: f32, c: f32, d: f32) callconv(.c) Complex(f32) { - return divc3.divc3(f32, a, b, c, d); -} diff --git a/lib/compiler_rt/divsf3.zig b/lib/compiler_rt/divsf3.zig index c0fbcb92b743fff4e12db533d7694210e7ebb0a2..c86c860948d315b260498c959e4678f5f64b9e94 100644 --- a/lib/compiler_rt/divsf3.zig +++ b/lib/compiler_rt/divsf3.zig @@ -9,6 +9,7 @@ const symbol = compiler_rt.symbol; const normalize = compiler_rt.normalize; comptime { + symbol(&__divhf3, "__divhf3"); if (compiler_rt.want_aeabi) { symbol(&__aeabi_fdiv, "__aeabi_fdiv"); } else { @@ -16,15 +17,23 @@ comptime { } } -pub fn __divsf3(a: f32, b: f32) callconv(.c) f32 { - return div(a, b); +fn __divhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(div_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn div_f16(a: f16, b: f16) f16 { + // TODO: more efficient implementation + return @floatCast(div_f32(a, b)); +} + +fn __divsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(div_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); } fn __aeabi_fdiv(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { - return div(a, b); + return div_f32(a, b); } -inline fn div(a: f32, b: f32) f32 { +pub fn div_f32(a: f32, b: f32) f32 { const Z = @Int(.unsigned, 32); const significandBits = std.math.floatMantissaBits(f32); diff --git a/lib/compiler_rt/divsf3_test.zig b/lib/compiler_rt/divsf3_test.zig index c457915e49cd41986f1470b2f868398cfad855e9..f12e152b31b41b1fd85d1f1493838dd68a43f983 100644 --- a/lib/compiler_rt/divsf3_test.zig +++ b/lib/compiler_rt/divsf3_test.zig @@ -6,7 +6,7 @@ const std = @import("std"); const math = std.math; const testing = std.testing; -const __divsf3 = @import("divsf3.zig").__divsf3; +const div_f32 = @import("divsf3.zig").div_f32; const nanRep: u32 = @as(u32, @bitCast(math.nan(f32))); const infRep: u32 = @as(u32, @bitCast(math.inf(f32))); @@ -30,7 +30,7 @@ fn compareResultF(result: f32, expected: u32) bool { } fn test__divsf3(a: f32, b: f32, expected: u32) !void { - const x = __divsf3(a, b); + const x = div_f32(a, b); const ret = compareResultF(x, expected); try testing.expect(ret == true); } diff --git a/lib/compiler_rt/divtc3.zig b/lib/compiler_rt/divtc3.zig deleted file mode 100644 index b0e0f35f5447488f4d15ba76ede68bab2425f96b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divtc3.zig +++ /dev/null @@ -1,16 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - if (compiler_rt.want_ppc_abi) - symbol(&__divtc3, "__divkc3"); - symbol(&__divtc3, "__divtc3"); - } -} - -pub fn __divtc3(a: f128, b: f128, c: f128, d: f128) callconv(.c) Complex(f128) { - return divc3.divc3(f128, a, b, c, d); -} diff --git a/lib/compiler_rt/divtf3.zig b/lib/compiler_rt/divtf3.zig index 3b6f648e3ac33e2fb3183bdd7fcb892ea239500c..9995a9bfd796070d9573ac050bf233c9646a5d98 100644 --- a/lib/compiler_rt/divtf3.zig +++ b/lib/compiler_rt/divtf3.zig @@ -13,19 +13,20 @@ comptime { symbol(&_Qp_div, "_Qp_div"); } else if (compiler_rt.want_sparc32_abi) { symbol(&__divtf3, "_Q_div"); + } else { + symbol(&__divtf3, "__divtf3"); } - symbol(&__divtf3, "__divtf3"); } -pub fn __divtf3(a: f128, b: f128) callconv(.c) f128 { - return div(a, b); +fn __divtf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(div_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); } fn _Qp_div(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { - c.* = div(a.*, b.*); + c.* = div_f128(a.*, b.*); } -inline fn div(a: f128, b: f128) f128 { +pub fn div_f128(a: f128, b: f128) f128 { const Z = @Int(.unsigned, 128); const significandBits = std.math.floatMantissaBits(f128); diff --git a/lib/compiler_rt/divtf3_test.zig b/lib/compiler_rt/divtf3_test.zig index 4d10e5c39d7dc61b1c317364750757148635543d..dfc7e1e954ea96eb6927f4c56179efc15fe4a2ee 100644 --- a/lib/compiler_rt/divtf3_test.zig +++ b/lib/compiler_rt/divtf3_test.zig @@ -2,7 +2,7 @@ const std = @import("std"); const math = std.math; const testing = std.testing; -const __divtf3 = @import("divtf3.zig").__divtf3; +const div_f128 = @import("divtf3.zig").div_f128; fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { const rep: u128 = @bitCast(result); @@ -24,7 +24,7 @@ fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { } fn test__divtf3(a: f128, b: f128, expectedHi: u64, expectedLo: u64) !void { - const x = __divtf3(a, b); + const x = div_f128(a, b); const ret = compareResultLD(x, expectedHi, expectedLo); try testing.expect(ret == true); } diff --git a/lib/compiler_rt/divxc3.zig b/lib/compiler_rt/divxc3.zig deleted file mode 100644 index 86c737a83931c6c34f73303eeaba00536d8e1bd4..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/divxc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const divc3 = @import("./divc3.zig"); -const Complex = @import("./mulc3.zig").Complex; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__divxc3, "__divxc3"); - } -} - -pub fn __divxc3(a: f80, b: f80, c: f80, d: f80) callconv(.c) Complex(f80) { - return divc3.divc3(f80, a, b, c, d); -} diff --git a/lib/compiler_rt/divxf3.zig b/lib/compiler_rt/divxf3.zig index fdf43dc83bce6adbb53995826c516aecd7310fe2..eb3fde6862ab3937e8828d729287a35ea9d3ead9 100644 --- a/lib/compiler_rt/divxf3.zig +++ b/lib/compiler_rt/divxf3.zig @@ -11,7 +11,10 @@ comptime { symbol(&__divxf3, "__divxf3"); } -pub fn __divxf3(a: f80, b: f80) callconv(.c) f80 { +fn __divxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(div_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn div_f80(a: f80, b: f80) f80 { const T = f80; const Z = @Int(.unsigned, @bitSizeOf(T)); diff --git a/lib/compiler_rt/divxf3_test.zig b/lib/compiler_rt/divxf3_test.zig index cb897a1014022d50e8cb93043749b033b56af55d..88d7cada4606920997b5b0030134aaab476da576 100644 --- a/lib/compiler_rt/divxf3_test.zig +++ b/lib/compiler_rt/divxf3_test.zig @@ -2,7 +2,7 @@ const std = @import("std"); const math = std.math; const testing = std.testing; -const __divxf3 = @import("divxf3.zig").__divxf3; +const div_f80 = @import("divxf3.zig").div_f80; const nanRep: u80 = @as(u80, @bitCast(math.nan(f80))); const infRep: u80 = @as(u80, @bitCast(math.inf(f80))); @@ -19,14 +19,14 @@ fn compareResult(result: f80, expected: u80) bool { } fn expect__divxf3_result(a: f80, b: f80, expected: u80) !void { - const x = __divxf3(a, b); + const x = div_f80(a, b); const ret = compareResult(x, expected); try testing.expect(ret == true); } fn test__divxf3(a: f80, b: f80) !void { const integerBit = 1 << math.floatFractionalBits(f80); - const x = __divxf3(a, b); + const x = div_f80(a, b); // Next float (assuming normal, non-zero result) const x_plus_eps: f80 = @bitCast((@as(u80, @bitCast(x)) + 1) | integerBit); diff --git a/lib/compiler_rt/exp.zig b/lib/compiler_rt/exp.zig index ce2eadb7f1edfe49ca51562a8b3ec4432f2017eb..6f9d19ddb3adbfe743fd278ce9e458ae45341502 100644 --- a/lib/compiler_rt/exp.zig +++ b/lib/compiler_rt/exp.zig @@ -14,26 +14,29 @@ const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { symbol(&__exph, "__exph"); symbol(&expf, "expf"); symbol(&exp, "exp"); symbol(&__expx, "__expx"); - if (compiler_rt.want_ppc_abi) { - symbol(&expq, "expf128"); - } - symbol(&expq, "expq"); + symbol(&expq, "expf128"); symbol(&expl, "expl"); } -pub fn __exph(a: f16) callconv(.c) f16 { +fn __exph(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(exp_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn exp_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(expf(a)); + return @floatCast(exp_f32(x)); } -pub fn expf(x_: f32) callconv(.c) f32 { +fn expf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(exp_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn exp_f32(x_: f32) f32 { const half = [_]f32{ 0.5, -0.5 }; const ln2hi = 6.9314575195e-1; const ln2lo = 1.4286067653e-6; @@ -108,7 +111,10 @@ pub fn expf(x_: f32) callconv(.c) f32 { } } -pub fn exp(x_: f64) callconv(.c) f64 { +fn exp(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(exp_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn exp_f64(x_: f64) f64 { const half = [_]f64{ 0.5, -0.5 }; const ln2hi: f64 = 6.93147180369123816490e-01; const ln2lo: f64 = 1.90821492927058770002e-10; @@ -189,116 +195,121 @@ pub fn exp(x_: f64) callconv(.c) f64 { } } -pub fn __expx(a: f80) callconv(.c) f80 { +fn __expx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(exp_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn exp_f80(x: f80) f80 { // TODO: more efficient implementation - return @floatCast(expq(a)); + return @floatCast(exp_f128(x)); } -const expq = @import("exp_f128.zig").exp; +fn expq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(exp_f128(compiler_rt.f128.fromAbi(x))); +} +pub const exp_f128 = @import("exp_f128.zig").exp; pub fn expl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return exp(x), - 80 => return __expx(x), - 128 => return expq(x), - else => @compileError("unreachable"), + 64 => return exp_f64(x), + 80 => return exp_f80(x), + 128 => return exp_f128(x), + else => comptime unreachable, } } test "expf() special" { - try expectEqual(expf(0.0), 1.0); - try expectEqual(expf(-0.0), 1.0); - try expectEqual(expf(1.0), math.e); - try expectEqual(expf(math.ln2), 2.0); - try expectEqual(expf(math.inf(f32)), math.inf(f32)); - try expect(math.isPositiveZero(expf(-math.inf(f32)))); - try expect(math.isNan(expf(math.nan(f32)))); - try expect(math.isNan(expf(math.snan(f32)))); + try expectEqual(exp_f32(0.0), 1.0); + try expectEqual(exp_f32(-0.0), 1.0); + try expectEqual(exp_f32(1.0), math.e); + try expectEqual(exp_f32(math.ln2), 2.0); + try expectEqual(exp_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isPositiveZero(exp_f32(-math.inf(f32)))); + try expect(math.isNan(exp_f32(math.nan(f32)))); + try expect(math.isNan(exp_f32(math.snan(f32)))); } test "expf() sanity" { - try expectEqual(expf(-0x1.0223a0p+3), 0x1.490320p-12); - try expectEqual(expf(0x1.161868p+2), 0x1.34712ap+6); - try expectEqual(expf(-0x1.0c34b4p+3), 0x1.e06b1ap-13); - try expectEqual(expf(-0x1.a206f0p+2), 0x1.7dd484p-10); - try expectEqual(expf(0x1.288bbcp+3), 0x1.4abc80p+13); - try expectEqual(expf(0x1.52efd0p-1), 0x1.f04a9cp+0); - try expectEqual(expf(-0x1.a05cc8p-2), 0x1.54f1e0p-1); - try expectEqual(expf(0x1.1f9efap-1), 0x1.c0f628p+0); - try expectEqual(expf(0x1.8c5db0p-1), 0x1.1599b2p+1); - try expectEqual(expf(-0x1.5b86eap-1), 0x1.03b572p-1); - try expectEqual(expf(-0x1.57f25cp+2), 0x1.2fbea2p-8); - try expectEqual(expf(0x1.c7d310p+3), 0x1.76eefp+20); - try expectEqual(expf(0x1.19be70p+4), 0x1.52d3dep+25); - try expectEqual(expf(-0x1.ab6d70p+3), 0x1.a88adep-20); - try expectEqual(expf(-0x1.5ac18ep+2), 0x1.22b328p-8); - try expectEqual(expf(-0x1.925982p-1), 0x1.d2acc0p-2); - try expectEqual(expf(0x1.7221cep+3), 0x1.9c2ceap+16); - try expectEqual(expf(0x1.11a0d4p+4), 0x1.980ee6p+24); - try expectEqual(expf(-0x1.ae41a2p+1), 0x1.1c28d0p-5); - try expectEqual(expf(-0x1.329154p+4), 0x1.47ef94p-28); + try expectEqual(exp_f32(-0x1.0223a0p+3), 0x1.490320p-12); + try expectEqual(exp_f32(0x1.161868p+2), 0x1.34712ap+6); + try expectEqual(exp_f32(-0x1.0c34b4p+3), 0x1.e06b1ap-13); + try expectEqual(exp_f32(-0x1.a206f0p+2), 0x1.7dd484p-10); + try expectEqual(exp_f32(0x1.288bbcp+3), 0x1.4abc80p+13); + try expectEqual(exp_f32(0x1.52efd0p-1), 0x1.f04a9cp+0); + try expectEqual(exp_f32(-0x1.a05cc8p-2), 0x1.54f1e0p-1); + try expectEqual(exp_f32(0x1.1f9efap-1), 0x1.c0f628p+0); + try expectEqual(exp_f32(0x1.8c5db0p-1), 0x1.1599b2p+1); + try expectEqual(exp_f32(-0x1.5b86eap-1), 0x1.03b572p-1); + try expectEqual(exp_f32(-0x1.57f25cp+2), 0x1.2fbea2p-8); + try expectEqual(exp_f32(0x1.c7d310p+3), 0x1.76eefp+20); + try expectEqual(exp_f32(0x1.19be70p+4), 0x1.52d3dep+25); + try expectEqual(exp_f32(-0x1.ab6d70p+3), 0x1.a88adep-20); + try expectEqual(exp_f32(-0x1.5ac18ep+2), 0x1.22b328p-8); + try expectEqual(exp_f32(-0x1.925982p-1), 0x1.d2acc0p-2); + try expectEqual(exp_f32(0x1.7221cep+3), 0x1.9c2ceap+16); + try expectEqual(exp_f32(0x1.11a0d4p+4), 0x1.980ee6p+24); + try expectEqual(exp_f32(-0x1.ae41a2p+1), 0x1.1c28d0p-5); + try expectEqual(exp_f32(-0x1.329154p+4), 0x1.47ef94p-28); } test "expf() boundary" { - try expectEqual(expf(0x1.62e42ep+6), 0x1.ffff08p+127); // The last value before the result gets infinite - try expectEqual(expf(0x1.62e430p+6), math.inf(f32)); // The first value that gives inf - try expectEqual(expf(0x1.fffffep+127), math.inf(f32)); // Max input value - try expectEqual(expf(0x1p-149), 1.0); // Min positive input value - try expectEqual(expf(-0x1p-149), 1.0); // Min negative input value - try expectEqual(expf(0x1p-126), 1.0); // First positive subnormal input - try expectEqual(expf(-0x1p-126), 1.0); // First negative subnormal input - try expectEqual(expf(-0x1.9fe368p+6), 0x1p-149); // The last value before the result flushes to zero - try expectEqual(expf(-0x1.9fe36ap+6), 0.0); // The first value at which the result flushes to zero - try expectEqual(expf(-0x1.5d589ep+6), 0x1.00004cp-126); // The last value before the result flushes to subnormal - try expectEqual(expf(-0x1.5d58a0p+6), 0x1.ffff98p-127); // The first value for which the result flushes to subnormal - + try expectEqual(exp_f32(0x1.62e42ep+6), 0x1.ffff08p+127); // The last value before the result gets infinite + try expectEqual(exp_f32(0x1.62e430p+6), math.inf(f32)); // The first value that gives inf + try expectEqual(exp_f32(0x1.fffffep+127), math.inf(f32)); // Max input value + try expectEqual(exp_f32(0x1p-149), 1.0); // Min positive input value + try expectEqual(exp_f32(-0x1p-149), 1.0); // Min negative input value + try expectEqual(exp_f32(0x1p-126), 1.0); // First positive subnormal input + try expectEqual(exp_f32(-0x1p-126), 1.0); // First negative subnormal input + try expectEqual(exp_f32(-0x1.9fe368p+6), 0x1p-149); // The last value before the result flushes to zero + try expectEqual(exp_f32(-0x1.9fe36ap+6), 0.0); // The first value at which the result flushes to zero + try expectEqual(exp_f32(-0x1.5d589ep+6), 0x1.00004cp-126); // The last value before the result flushes to subnormal + try expectEqual(exp_f32(-0x1.5d58a0p+6), 0x1.ffff98p-127); // The first value for which the result flushes to subnormal } test "exp() special" { - try expectEqual(exp(0.0), 1.0); - try expectEqual(exp(-0.0), 1.0); + try expectEqual(exp_f64(0.0), 1.0); + try expectEqual(exp_f64(-0.0), 1.0); // TODO: Accuracy error - off in the last bit in 64-bit, disagreeing with GCC // try expectEqual(exp(1.0), math.e); - try expectEqual(exp(math.ln2), 2.0); - try expectEqual(exp(math.inf(f64)), math.inf(f64)); - try expect(math.isPositiveZero(exp(-math.inf(f64)))); - try expect(math.isNan(exp(math.nan(f64)))); - try expect(math.isNan(exp(math.snan(f64)))); + try expectEqual(exp_f64(math.ln2), 2.0); + try expectEqual(exp_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isPositiveZero(exp_f64(-math.inf(f64)))); + try expect(math.isNan(exp_f64(math.nan(f64)))); + try expect(math.isNan(exp_f64(math.snan(f64)))); } test "exp() sanity" { - try expectEqual(exp(-0x1.02239f3c6a8f1p+3), 0x1.490327ea61235p-12); - try expectEqual(exp(0x1.161868e18bc67p+2), 0x1.34712ed238c04p+6); - try expectEqual(exp(-0x1.0c34b3e01e6e7p+3), 0x1.e06b1b6c18e64p-13); - try expectEqual(exp(-0x1.a206f0a19dcc4p+2), 0x1.7dd47f810e68cp-10); - try expectEqual(exp(0x1.288bbb0d6a1e6p+3), 0x1.4abc77496e07ep+13); - try expectEqual(exp(0x1.52efd0cd80497p-1), 0x1.f04a9c1080500p+0); - try expectEqual(exp(-0x1.a05cc754481d1p-2), 0x1.54f1e0fd3ea0dp-1); - try expectEqual(exp(0x1.1f9ef934745cbp-1), 0x1.c0f6266a6a547p+0); - try expectEqual(exp(0x1.8c5db097f7442p-1), 0x1.1599b1d4a25fbp+1); - try expectEqual(exp(-0x1.5b86ea8118a0ep-1), 0x1.03b5728a00229p-1); - try expectEqual(exp(-0x1.57f25b2b5006dp+2), 0x1.2fbea6a01cab9p-8); - try expectEqual(exp(0x1.c7d30fb825911p+3), 0x1.76eeed45a0634p+20); - try expectEqual(exp(0x1.19be709de7505p+4), 0x1.52d3eb7be6844p+25); - try expectEqual(exp(-0x1.ab6d6fba96889p+3), 0x1.a88ae12f985d6p-20); - try expectEqual(exp(-0x1.5ac18e27084ddp+2), 0x1.22b327da9cca6p-8); - try expectEqual(exp(-0x1.925981b093c41p-1), 0x1.d2acc046b55f7p-2); - try expectEqual(exp(0x1.7221cd18455f5p+3), 0x1.9c2cde8699cfbp+16); - try expectEqual(exp(0x1.11a0d4a51b239p+4), 0x1.980ef612ff182p+24); - try expectEqual(exp(-0x1.ae41a1079de4dp+1), 0x1.1c28d16bb3222p-5); - try expectEqual(exp(-0x1.329153103b871p+4), 0x1.47efa6ddd0d22p-28); + try expectEqual(exp_f64(-0x1.02239f3c6a8f1p+3), 0x1.490327ea61235p-12); + try expectEqual(exp_f64(0x1.161868e18bc67p+2), 0x1.34712ed238c04p+6); + try expectEqual(exp_f64(-0x1.0c34b3e01e6e7p+3), 0x1.e06b1b6c18e64p-13); + try expectEqual(exp_f64(-0x1.a206f0a19dcc4p+2), 0x1.7dd47f810e68cp-10); + try expectEqual(exp_f64(0x1.288bbb0d6a1e6p+3), 0x1.4abc77496e07ep+13); + try expectEqual(exp_f64(0x1.52efd0cd80497p-1), 0x1.f04a9c1080500p+0); + try expectEqual(exp_f64(-0x1.a05cc754481d1p-2), 0x1.54f1e0fd3ea0dp-1); + try expectEqual(exp_f64(0x1.1f9ef934745cbp-1), 0x1.c0f6266a6a547p+0); + try expectEqual(exp_f64(0x1.8c5db097f7442p-1), 0x1.1599b1d4a25fbp+1); + try expectEqual(exp_f64(-0x1.5b86ea8118a0ep-1), 0x1.03b5728a00229p-1); + try expectEqual(exp_f64(-0x1.57f25b2b5006dp+2), 0x1.2fbea6a01cab9p-8); + try expectEqual(exp_f64(0x1.c7d30fb825911p+3), 0x1.76eeed45a0634p+20); + try expectEqual(exp_f64(0x1.19be709de7505p+4), 0x1.52d3eb7be6844p+25); + try expectEqual(exp_f64(-0x1.ab6d6fba96889p+3), 0x1.a88ae12f985d6p-20); + try expectEqual(exp_f64(-0x1.5ac18e27084ddp+2), 0x1.22b327da9cca6p-8); + try expectEqual(exp_f64(-0x1.925981b093c41p-1), 0x1.d2acc046b55f7p-2); + try expectEqual(exp_f64(0x1.7221cd18455f5p+3), 0x1.9c2cde8699cfbp+16); + try expectEqual(exp_f64(0x1.11a0d4a51b239p+4), 0x1.980ef612ff182p+24); + try expectEqual(exp_f64(-0x1.ae41a1079de4dp+1), 0x1.1c28d16bb3222p-5); + try expectEqual(exp_f64(-0x1.329153103b871p+4), 0x1.47efa6ddd0d22p-28); } test "exp() boundary" { - try expectEqual(exp(0x1.62e42fefa39efp+9), 0x1.fffffffffff2ap+1023); // The last value before the result gets infinite - try expectEqual(exp(0x1.62e42fefa39f0p+9), math.inf(f64)); // The first value that gives inf - try expectEqual(exp(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value - try expectEqual(exp(0x1p-1074), 1.0); // Min positive input value - try expectEqual(exp(-0x1p-1074), 1.0); // Min negative input value - try expectEqual(exp(0x1p-1022), 1.0); // First positive subnormal input - try expectEqual(exp(-0x1p-1022), 1.0); // First negative subnormal input - try expectEqual(exp(-0x1.74910d52d3051p+9), 0x1p-1074); // The last value before the result flushes to zero - try expectEqual(exp(-0x1.74910d52d3052p+9), 0.0); // The first value at which the result flushes to zero - try expectEqual(exp(-0x1.6232bdd7abcd2p+9), 0x1.000000000007cp-1022); // The last value before the result flushes to subnormal - try expectEqual(exp(-0x1.6232bdd7abcd3p+9), 0x1.ffffffffffcf8p-1023); // The first value for which the result flushes to subnormal + try expectEqual(exp_f64(0x1.62e42fefa39efp+9), 0x1.fffffffffff2ap+1023); // The last value before the result gets infinite + try expectEqual(exp_f64(0x1.62e42fefa39f0p+9), math.inf(f64)); // The first value that gives inf + try expectEqual(exp_f64(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value + try expectEqual(exp_f64(0x1p-1074), 1.0); // Min positive input value + try expectEqual(exp_f64(-0x1p-1074), 1.0); // Min negative input value + try expectEqual(exp_f64(0x1p-1022), 1.0); // First positive subnormal input + try expectEqual(exp_f64(-0x1p-1022), 1.0); // First negative subnormal input + try expectEqual(exp_f64(-0x1.74910d52d3051p+9), 0x1p-1074); // The last value before the result flushes to zero + try expectEqual(exp_f64(-0x1.74910d52d3052p+9), 0.0); // The first value at which the result flushes to zero + try expectEqual(exp_f64(-0x1.6232bdd7abcd2p+9), 0x1.000000000007cp-1022); // The last value before the result flushes to subnormal + try expectEqual(exp_f64(-0x1.6232bdd7abcd3p+9), 0x1.ffffffffffcf8p-1023); // The first value for which the result flushes to subnormal } diff --git a/lib/compiler_rt/exp2.zig b/lib/compiler_rt/exp2.zig index abcef881073619a860997766283c950cc702a3e6..4f25cdec63332788d1bdda417503901b02ce6154 100644 --- a/lib/compiler_rt/exp2.zig +++ b/lib/compiler_rt/exp2.zig @@ -19,19 +19,22 @@ comptime { symbol(&exp2f, "exp2f"); symbol(&exp2, "exp2"); symbol(&__exp2x, "__exp2x"); - if (compiler_rt.want_ppc_abi) { - symbol(&exp2q, "exp2f128"); - } - symbol(&exp2q, "exp2q"); + symbol(&exp2q, "exp2f128"); symbol(&exp2l, "exp2l"); } -pub fn __exp2h(x: f16) callconv(.c) f16 { +fn __exp2h(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(exp2_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn exp2_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(exp2f(x)); + return @floatCast(exp2_f32(x)); } -pub fn exp2f(x: f32) callconv(.c) f32 { +fn exp2f(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(exp2_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn exp2_f32(x: f32) f32 { const tblsiz: u32 = @intCast(exp2ft.len); const redux: f32 = 0x1.8p23 / @as(f32, @floatFromInt(tblsiz)); const P1: f32 = 0x1.62e430p-1; @@ -88,7 +91,10 @@ pub fn exp2f(x: f32) callconv(.c) f32 { return @floatCast(r * uk); } -pub fn exp2(x: f64) callconv(.c) f64 { +fn exp2(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(exp2_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn exp2_f64(x: f64) f64 { const tblsiz: u32 = @intCast(exp2dt.len / 2); const redux: f64 = 0x1.8p52 / @as(f64, @floatFromInt(tblsiz)); const P1: f64 = 0x1.62e42fefa39efp-1; @@ -156,19 +162,25 @@ pub fn exp2(x: f64) callconv(.c) f64 { return math.scalbn(r, ik); } -pub fn __exp2x(x: f80) callconv(.c) f80 { +fn __exp2x(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(exp2_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn exp2_f80(x: f80) f80 { // TODO: more efficient implementation - return @floatCast(exp2q(x)); + return @floatCast(exp2_f128(x)); } -pub const exp2q = @import("exp_f128.zig").exp2; +fn exp2q(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(exp2_f128(compiler_rt.f128.fromAbi(x))); +} +pub const exp2_f128 = @import("exp_f128.zig").exp2; pub fn exp2l(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return exp2(x), - 80 => return __exp2x(x), - 128 => return exp2q(x), - else => @compileError("unreachable"), + 64 => return exp2_f64(x), + 80 => return exp2_f80(x), + 128 => return exp2_f128(x), + else => comptime unreachable, } } @@ -452,77 +464,77 @@ const exp2dt = [_]f64{ }; test "exp2f() special" { - try expectEqual(exp2f(0.0), 1.0); - try expectEqual(exp2f(-0.0), 1.0); - try expectEqual(exp2f(1.0), 2.0); - try expectEqual(exp2f(-1.0), 0.5); - try expectEqual(exp2f(math.inf(f32)), math.inf(f32)); - try expect(math.isPositiveZero(exp2f(-math.inf(f32)))); - try expect(math.isNan(exp2f(math.nan(f32)))); - try expect(math.isNan(exp2f(math.snan(f32)))); + try expectEqual(exp2_f32(0.0), 1.0); + try expectEqual(exp2_f32(-0.0), 1.0); + try expectEqual(exp2_f32(1.0), 2.0); + try expectEqual(exp2_f32(-1.0), 0.5); + try expectEqual(exp2_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isPositiveZero(exp2_f32(-math.inf(f32)))); + try expect(math.isNan(exp2_f32(math.nan(f32)))); + try expect(math.isNan(exp2_f32(math.snan(f32)))); } test "exp2f() sanity" { - try expectEqual(exp2f(-0x1.0223a0p+3), 0x1.e8d134p-9); - try expectEqual(exp2f(0x1.161868p+2), 0x1.453672p+4); - try expectEqual(exp2f(-0x1.0c34b4p+3), 0x1.890ca0p-9); - try expectEqual(exp2f(-0x1.a206f0p+2), 0x1.622d4ep-7); - try expectEqual(exp2f(0x1.288bbcp+3), 0x1.340ecep+9); - try expectEqual(exp2f(0x1.52efd0p-1), 0x1.950eeep+0); - try expectEqual(exp2f(-0x1.a05cc8p-2), 0x1.824056p-1); - try expectEqual(exp2f(0x1.1f9efap-1), 0x1.79dfa2p+0); - try expectEqual(exp2f(0x1.8c5db0p-1), 0x1.b5ceacp+0); - try expectEqual(exp2f(-0x1.5b86eap-1), 0x1.3fd8bap-1); + try expectEqual(exp2_f32(-0x1.0223a0p+3), 0x1.e8d134p-9); + try expectEqual(exp2_f32(0x1.161868p+2), 0x1.453672p+4); + try expectEqual(exp2_f32(-0x1.0c34b4p+3), 0x1.890ca0p-9); + try expectEqual(exp2_f32(-0x1.a206f0p+2), 0x1.622d4ep-7); + try expectEqual(exp2_f32(0x1.288bbcp+3), 0x1.340ecep+9); + try expectEqual(exp2_f32(0x1.52efd0p-1), 0x1.950eeep+0); + try expectEqual(exp2_f32(-0x1.a05cc8p-2), 0x1.824056p-1); + try expectEqual(exp2_f32(0x1.1f9efap-1), 0x1.79dfa2p+0); + try expectEqual(exp2_f32(0x1.8c5db0p-1), 0x1.b5ceacp+0); + try expectEqual(exp2_f32(-0x1.5b86eap-1), 0x1.3fd8bap-1); } test "exp2f() boundary" { - try expectEqual(exp2f(0x1.fffffep+6), 0x1.ffff4ep+127); // The last value before the result gets infinite - try expectEqual(exp2f(0x1p+7), math.inf(f32)); // The first value that gives infinite result - try expectEqual(exp2f(-0x1.2bccccp+7), 0x1p-149); // The last value before the result flushes to zero - try expectEqual(exp2f(-0x1.2cp+7), 0); // The first value at which the result flushes to zero - try expectEqual(exp2f(-0x1.f8p+6), 0x1p-126); // The last value before the result flushes to subnormal - try expectEqual(exp2f(-0x1.f80002p+6), 0x1.ffff50p-127); // The first value for which the result flushes to subnormal - try expectEqual(exp2f(0x1.fffffep+127), math.inf(f32)); // Max input value - try expectEqual(exp2f(0x1p-149), 1); // Min positive input value - try expectEqual(exp2f(-0x1p-149), 1); // Min negative input value - try expectEqual(exp2f(0x1p-126), 1); // First positive subnormal input - try expectEqual(exp2f(-0x1p-126), 1); // First negative subnormal input + try expectEqual(exp2_f32(0x1.fffffep+6), 0x1.ffff4ep+127); // The last value before the result gets infinite + try expectEqual(exp2_f32(0x1p+7), math.inf(f32)); // The first value that gives infinite result + try expectEqual(exp2_f32(-0x1.2bccccp+7), 0x1p-149); // The last value before the result flushes to zero + try expectEqual(exp2_f32(-0x1.2cp+7), 0); // The first value at which the result flushes to zero + try expectEqual(exp2_f32(-0x1.f8p+6), 0x1p-126); // The last value before the result flushes to subnormal + try expectEqual(exp2_f32(-0x1.f80002p+6), 0x1.ffff50p-127); // The first value for which the result flushes to subnormal + try expectEqual(exp2_f32(0x1.fffffep+127), math.inf(f32)); // Max input value + try expectEqual(exp2_f32(0x1p-149), 1); // Min positive input value + try expectEqual(exp2_f32(-0x1p-149), 1); // Min negative input value + try expectEqual(exp2_f32(0x1p-126), 1); // First positive subnormal input + try expectEqual(exp2_f32(-0x1p-126), 1); // First negative subnormal input } test "exp2() special" { - try expectEqual(exp2(0.0), 1.0); - try expectEqual(exp2(-0.0), 1.0); - try expectEqual(exp2(1.0), 2.0); - try expectEqual(exp2(-1.0), 0.5); - try expectEqual(exp2(math.inf(f64)), math.inf(f64)); - try expect(math.isPositiveZero(exp2(-math.inf(f64)))); - try expect(math.isNan(exp2(math.nan(f64)))); - try expect(math.isNan(exp2(math.snan(f64)))); + try expectEqual(exp2_f64(0.0), 1.0); + try expectEqual(exp2_f64(-0.0), 1.0); + try expectEqual(exp2_f64(1.0), 2.0); + try expectEqual(exp2_f64(-1.0), 0.5); + try expectEqual(exp2_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isPositiveZero(exp2_f64(-math.inf(f64)))); + try expect(math.isNan(exp2_f64(math.nan(f64)))); + try expect(math.isNan(exp2_f64(math.snan(f64)))); } test "exp2() sanity" { - try expectEqual(exp2(-0x1.02239f3c6a8f1p+3), 0x1.e8d13c396f452p-9); - try expectEqual(exp2(0x1.161868e18bc67p+2), 0x1.4536746bb6f12p+4); - try expectEqual(exp2(-0x1.0c34b3e01e6e7p+3), 0x1.890ca0c00b9a2p-9); - try expectEqual(exp2(-0x1.a206f0a19dcc4p+2), 0x1.622d4b0ebc6c1p-7); - try expectEqual(exp2(0x1.288bbb0d6a1e6p+3), 0x1.340ec7f3e607ep+9); - try expectEqual(exp2(0x1.52efd0cd80497p-1), 0x1.950eef4bc5451p+0); - try expectEqual(exp2(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1); - try expectEqual(exp2(0x1.1f9ef934745cbp-1), 0x1.79dfa14ab121ep+0); - try expectEqual(exp2(0x1.8c5db097f7442p-1), 0x1.b5cead2247372p+0); - try expectEqual(exp2(-0x1.5b86ea8118a0ep-1), 0x1.3fd8ba33216b9p-1); + try expectEqual(exp2_f64(-0x1.02239f3c6a8f1p+3), 0x1.e8d13c396f452p-9); + try expectEqual(exp2_f64(0x1.161868e18bc67p+2), 0x1.4536746bb6f12p+4); + try expectEqual(exp2_f64(-0x1.0c34b3e01e6e7p+3), 0x1.890ca0c00b9a2p-9); + try expectEqual(exp2_f64(-0x1.a206f0a19dcc4p+2), 0x1.622d4b0ebc6c1p-7); + try expectEqual(exp2_f64(0x1.288bbb0d6a1e6p+3), 0x1.340ec7f3e607ep+9); + try expectEqual(exp2_f64(0x1.52efd0cd80497p-1), 0x1.950eef4bc5451p+0); + try expectEqual(exp2_f64(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1); + try expectEqual(exp2_f64(0x1.1f9ef934745cbp-1), 0x1.79dfa14ab121ep+0); + try expectEqual(exp2_f64(0x1.8c5db097f7442p-1), 0x1.b5cead2247372p+0); + try expectEqual(exp2_f64(-0x1.5b86ea8118a0ep-1), 0x1.3fd8ba33216b9p-1); } test "exp2() boundary" { - try expectEqual(exp2(0x1.fffffffffffffp+9), 0x1.ffffffffffd3ap+1023); // The last value before the result gets infinite - try expectEqual(exp2(0x1p+10), math.inf(f64)); // The first value that gives infinite result - try expectEqual(exp2(-0x1.0cbffffffffffp+10), 0x1p-1074); // The last value before the result flushes to zero - try expectEqual(exp2(-0x1.0ccp+10), 0); // The first value at which the result flushes to zero - try expectEqual(exp2(-0x1.ffp+9), 0x1p-1022); // The last value before the result flushes to subnormal - try expectEqual(exp2(-0x1.ff00000000001p+9), 0x1.ffffffffffd3ap-1023); // The first value for which the result flushes to subnormal - try expectEqual(exp2(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value - try expectEqual(exp2(0x1p-1074), 1); // Min positive input value - try expectEqual(exp2(-0x1p-1074), 1); // Min negative input value - try expectEqual(exp2(0x1p-1022), 1); // First positive subnormal input - try expectEqual(exp2(-0x1p-1022), 1); // First negative subnormal input + try expectEqual(exp2_f64(0x1.fffffffffffffp+9), 0x1.ffffffffffd3ap+1023); // The last value before the result gets infinite + try expectEqual(exp2_f64(0x1p+10), math.inf(f64)); // The first value that gives infinite result + try expectEqual(exp2_f64(-0x1.0cbffffffffffp+10), 0x1p-1074); // The last value before the result flushes to zero + try expectEqual(exp2_f64(-0x1.0ccp+10), 0); // The first value at which the result flushes to zero + try expectEqual(exp2_f64(-0x1.ffp+9), 0x1p-1022); // The last value before the result flushes to subnormal + try expectEqual(exp2_f64(-0x1.ff00000000001p+9), 0x1.ffffffffffd3ap-1023); // The first value for which the result flushes to subnormal + try expectEqual(exp2_f64(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value + try expectEqual(exp2_f64(0x1p-1074), 1); // Min positive input value + try expectEqual(exp2_f64(-0x1p-1074), 1); // Min negative input value + try expectEqual(exp2_f64(0x1p-1022), 1); // First positive subnormal input + try expectEqual(exp2_f64(-0x1p-1022), 1); // First negative subnormal input } diff --git a/lib/compiler_rt/exp_f128.zig b/lib/compiler_rt/exp_f128.zig index ac09308ff30ee94c46403e4e7cd9f6afd0bea60c..c7a042c2b11edb228cd597eebdefcadbd3b689bd 100644 --- a/lib/compiler_rt/exp_f128.zig +++ b/lib/compiler_rt/exp_f128.zig @@ -26,7 +26,7 @@ const exp_f128 = @This(); const std = @import("std"); const math = std.math; -pub fn exp(x: f128) callconv(.c) f128 { +pub fn exp(x: f128) f128 { if (!math.isFinite(x)) { if (math.isNan(x)) { if (math.isSignalNan(x)) math.raiseInvalid(); @@ -91,7 +91,7 @@ fn expPoly(r_hi: f128, r_lo: f128) f128 { } /// Computes 2^x -pub fn exp2(x: f128) callconv(.c) f128 { +pub fn exp2(x: f128) f128 { if (!math.isFinite(x)) { if (math.isNan(x)) { if (math.isSignalNan(x)) math.raiseInvalid(); diff --git a/lib/compiler_rt/extenddftf2.zig b/lib/compiler_rt/extenddftf2.zig deleted file mode 100644 index d6267d7d8a93acd5a56d528d803f789a013dced5..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extenddftf2.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const extendf = @import("./extendf.zig").extendf; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__extenddftf2, "__extenddfkf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_dtoq, "_Qp_dtoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__extenddftf2, "_Q_dtoq"); - } - symbol(&__extenddftf2, "__extenddftf2"); -} - -pub fn __extenddftf2(a: f64) callconv(.c) f128 { - return extendf(f128, f64, @as(u64, @bitCast(a))); -} - -fn _Qp_dtoq(c: *f128, a: f64) callconv(.c) void { - c.* = extendf(f128, f64, @as(u64, @bitCast(a))); -} diff --git a/lib/compiler_rt/extenddfxf2.zig b/lib/compiler_rt/extenddfxf2.zig deleted file mode 100644 index d18195aea357d8fdd8fc26a0d34db798bc06f187..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extenddfxf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extend_f80 = @import("./extendf.zig").extend_f80; - -comptime { - symbol(&__extenddfxf2, "__extenddfxf2"); -} - -pub fn __extenddfxf2(a: f64) callconv(.c) f80 { - return extend_f80(f64, @as(u64, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendf.zig b/lib/compiler_rt/extendf.zig index b923e9d25b7fe41a733b0aeb10db9d51b24176df..a0c637b352680a3b1bf1728c662bce3bdb6db91c 100644 --- a/lib/compiler_rt/extendf.zig +++ b/lib/compiler_rt/extendf.zig @@ -1,10 +1,175 @@ const std = @import("std"); -pub inline fn extendf( - comptime dst_t: type, - comptime src_t: type, - a: @Int(.unsigned, @typeInfo(src_t).float.bits), -) dst_t { +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + if (compiler_rt.want_aeabi) { + if (compiler_rt.gnu_f16_abi) { + symbol(&__aeabi_h2f, "__gnu_h2f_ieee"); + } else { + symbol(&__aeabi_h2f, "__aeabi_h2f"); + } + } else if (compiler_rt.gnu_f16_abi) { + symbol(&__extendhfsf2, "__gnu_h2f_ieee"); + } + symbol(&__extendhfsf2, "__extendhfsf2"); + symbol(&__extendhfdf2, "__extendhfdf2"); + symbol(&__extendhfxf2, "__extendhfxf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__extendhftf2, "__extendhfkf2"); + } else { + symbol(&__extendhftf2, "__extendhftf2"); + } + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_f2d, "__aeabi_f2d"); + } else { + symbol(&__extendsfdf2, "__extendsfdf2"); + } + symbol(&__extendsfxf2, "__extendsfxf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__extendsftf2, "__extendsfkf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_stoq, "_Qp_stoq"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__extendsftf2, "_Q_stoq"); + } else { + symbol(&__extendsftf2, "__extendsftf2"); + } + + symbol(&__extenddfxf2, "__extenddfxf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__extenddftf2, "__extenddfkf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_dtoq, "_Qp_dtoq"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__extenddftf2, "_Q_dtoq"); + } else { + symbol(&__extenddftf2, "__extenddftf2"); + } + + if (compiler_rt.want_ppc_abi) { + symbol(&__extendxftf2, "__extendxfkf2"); + } else { + symbol(&__extendxftf2, "__extendxftf2"); + } +} + +fn __extendhfsf2(a: compiler_rt.f16Conv(f32).Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatCast_f16(compiler_rt.f16Conv(f32).fromAbi(a))); +} +fn __aeabi_h2f(a: u16) callconv(.{ .arm_aapcs = .{} }) u32 { + return @bitCast(f32_floatCast_f16(@bitCast(a))); +} +pub fn f32_floatCast_f16(a: f16) f32 { + return extendf(f32, f16, a); +} + +fn __extendhfdf2(a: compiler_rt.f16Conv(f64).Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatCast_f16(compiler_rt.f16Conv(f64).fromAbi(a))); +} +pub fn f64_floatCast_f16(a: f16) f64 { + return extendf(f64, f16, a); +} + +fn __extendhfxf2(a: compiler_rt.f16Conv(f80).Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatCast_f16(compiler_rt.f16Conv(f80).fromAbi(a))); +} +pub fn f80_floatCast_f16(a: f16) f80 { + return extend_f80(f16, a); +} + +fn __extendhftf2(a: compiler_rt.f16Conv(f128).Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatCast_f16(compiler_rt.f16Conv(f128).fromAbi(a))); +} +pub fn f128_floatCast_f16(a: f16) f128 { + return extendf(f128, f16, a); +} + +fn __extendsfdf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatCast_f32(compiler_rt.f32.fromAbi(a))); +} +fn __aeabi_f2d(a: f32) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatCast_f32(a); +} +pub fn f64_floatCast_f32(a: f32) f64 { + return extendf(f64, f32, a); +} + +fn __extendsfxf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatCast_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn f80_floatCast_f32(a: f32) f80 { + return extend_f80(f32, a); +} + +pub fn __extendsftf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatCast_f32(compiler_rt.f32.fromAbi(a))); +} +fn _Qp_stoq(c: *f128, a: f32) callconv(.c) void { + c.* = f128_floatCast_f32(a); +} +pub fn f128_floatCast_f32(a: f32) f128 { + return extendf(f128, f32, a); +} + +fn __extenddfxf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatCast_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn f80_floatCast_f64(a: f64) f80 { + return extend_f80(f64, a); +} + +fn __extenddftf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatCast_f64(compiler_rt.f64.fromAbi(a))); +} +fn _Qp_dtoq(c: *f128, a: f64) callconv(.c) void { + c.* = f128_floatCast_f64(a); +} +pub fn f128_floatCast_f64(a: f64) f128 { + return extendf(f128, f64, a); +} + +fn __extendxftf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatCast_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn f128_floatCast_f80(a: f80) f128 { + const src_int_bit: u64 = 0x8000000000000000; + const src_sig_mask = ~src_int_bit; + const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit + const dst_sig_bits = std.math.floatMantissaBits(f128); + + const dst_bits = @bitSizeOf(f128); + + // Break a into a sign and representation of the absolute value + var a_rep: std.math.F80 = .fromFloat(a); + const sign = a_rep.exp & 0x8000; + a_rep.exp &= 0x7FFF; + var abs_result: u128 = undefined; + + if (a_rep.exp == 0 and a_rep.fraction == 0) { + // zero + abs_result = 0; + } else if (a_rep.exp == 0x7FFF) { + // a is nan or infinite + abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); + abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; + } else if (a_rep.fraction & src_int_bit != 0) { + // a is a normal value + abs_result = @as(u128, a_rep.fraction & src_sig_mask) << (dst_sig_bits - src_sig_bits); + abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; + } else { + // a is denormal + abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); + } + + // Apply the signbit to (dst_t)abs(a). + const result: u128 = abs_result | @as(u128, sign) << (dst_bits - 16); + return @bitCast(result); +} + +inline fn extendf(comptime dst_t: type, comptime src_t: type, f: src_t) dst_t { const src_rep_t = @Int(.unsigned, @typeInfo(src_t).float.bits); const dst_rep_t = @Int(.unsigned, @typeInfo(dst_t).float.bits); const srcSigBits = std.math.floatMantissaBits(src_t); @@ -31,6 +196,7 @@ pub inline fn extendf( const dstMinNormal: dst_rep_t = @as(dst_rep_t, 1) << dstSigBits; + const a: src_rep_t = @bitCast(f); // Break a into a sign and representation of the absolute value const aRep: src_rep_t = @bitCast(a); const aAbs: src_rep_t = aRep & srcAbsMask; @@ -66,11 +232,11 @@ pub inline fn extendf( } // Apply the signbit to (dst_t)abs(a). - const result: dst_rep_t align(@alignOf(dst_t)) = absResult | @as(dst_rep_t, sign) << (dstBits - srcBits); + const result: dst_rep_t = absResult | @as(dst_rep_t, sign) << (dstBits - srcBits); return @bitCast(result); } -pub inline fn extend_f80(comptime src_t: type, a: @Int(.unsigned, @typeInfo(src_t).float.bits)) f80 { +inline fn extend_f80(comptime src_t: type, f: src_t) f80 { const src_rep_t = @Int(.unsigned, @typeInfo(src_t).float.bits); const src_sig_bits = std.math.floatMantissaBits(src_t); const dst_int_bit = 0x8000000000000000; @@ -92,6 +258,7 @@ pub inline fn extend_f80(comptime src_t: type, a: @Int(.unsigned, @typeInfo(src_ var dst: std.math.F80 = undefined; + const a: src_rep_t = @bitCast(f); // Break a into a sign and representation of the absolute value const a_abs = a & src_abs_mask; const sign: u16 = if (a & src_sign_mask != 0) 0x8000 else 0; diff --git a/lib/compiler_rt/extendf_test.zig b/lib/compiler_rt/extendf_test.zig index f572495b6634f8096fa5dd41dd9d2fd1b362a0a1..4cba105a6dc88b24230e9624d250b05da947edf2 100644 --- a/lib/compiler_rt/extendf_test.zig +++ b/lib/compiler_rt/extendf_test.zig @@ -1,31 +1,37 @@ const builtin = @import("builtin"); - const std = @import("std"); -const math = std.math; +const testing = std.testing; -const __extendhfsf2 = @import("extendhfsf2.zig").__extendhfsf2; -const __extendhftf2 = @import("extendhftf2.zig").__extendhftf2; -const __extendsftf2 = @import("extendsftf2.zig").__extendsftf2; -const __extenddftf2 = @import("extenddftf2.zig").__extenddftf2; -const __extenddfxf2 = @import("extenddfxf2.zig").__extenddfxf2; -const F16T = @import("../compiler_rt.zig").F16T; +const impl = @import("extendf.zig"); -fn test__extenddfxf2(a: f64, expected: u80) !void { - const x = __extenddfxf2(a); +const f32_floatCast_f16 = impl.f32_floatCast_f16; +const f64_floatCast_f16 = impl.f64_floatCast_f16; +const f80_floatCast_f16 = impl.f80_floatCast_f16; +const f128_floatCast_f16 = impl.f128_floatCast_f16; + +const f64_floatCast_f32 = impl.f64_floatCast_f32; +const f80_floatCast_f32 = impl.f80_floatCast_f32; +const f128_floatCast_f32 = impl.f128_floatCast_f32; + +const f80_floatCast_f64 = impl.f80_floatCast_f64; +const f128_floatCast_f64 = impl.f128_floatCast_f64; + +const f128_floatCast_f80 = impl.f128_floatCast_f80; + +fn test_f80_floatCast_f64(a: f64, expected: u80) !void { + const x = f80_floatCast_f64(a); const rep: u80 = @bitCast(x); if (rep == expected) return; - // test other possible NaN representation(signal NaN) - if (math.isNan(@as(f80, @bitCast(expected))) and math.isNan(x)) + if (std.math.isNan(@as(f80, @bitCast(expected))) and std.math.isNan(x)) return; - - @panic("__extenddfxf2 test failure"); + return error.TestFailure; } -fn test__extenddftf2(a: f64, expected_hi: u64, expected_lo: u64) !void { - const x = __extenddftf2(a); +fn test_f128_floatCast_f64(a: f64, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatCast_f64(a); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -33,7 +39,6 @@ fn test__extenddftf2(a: f64, expected_hi: u64, expected_lo: u64) !void { if (hi == expected_hi and lo == expected_lo) return; - // test other possible NaN representation(signal NaN) if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and @@ -42,12 +47,11 @@ fn test__extenddftf2(a: f64, expected_hi: u64, expected_lo: u64) !void { return; } } - - @panic("__extenddftf2 test failure"); + return error.TestFailure; } -fn test__extendhfsf2(a: u16, expected: u32) !void { - const x = __extendhfsf2(@as(F16T(f32), @bitCast(a))); +fn test_f32_floatCast_f16(a: u16, expected: u32) !void { + const x = f32_floatCast_f16(@bitCast(a)); const rep: u32 = @bitCast(x); if (rep == expected) { @@ -58,12 +62,11 @@ fn test__extendhfsf2(a: u16, expected: u32) !void { return; } } - return error.TestFailure; } -fn test__extendsftf2(a: f32, expected_hi: u64, expected_lo: u64) !void { - const x = __extendsftf2(a); +fn test_f128_floatCast_f32(a: f32, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatCast_f32(a); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -71,7 +74,6 @@ fn test__extendsftf2(a: f32, expected_hi: u64, expected_lo: u64) !void { if (hi == expected_hi and lo == expected_lo) return; - // test other possible NaN representation(signal NaN) if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and @@ -80,111 +82,108 @@ fn test__extendsftf2(a: f32, expected_hi: u64, expected_lo: u64) !void { return; } } - return error.TestFailure; } -test "extenddfxf2" { +test f80_floatCast_f64 { // qNaN - try test__extenddfxf2(makeQNaN64(), 0x7fffc000000000000000); + try test_f80_floatCast_f64(makeQNaN64(), 0x7fffc000000000000000); // NaN - try test__extenddfxf2(makeNaN64(0x7100000000000), 0x7fffe080000000000000); + try test_f80_floatCast_f64(makeNaN64(0x7100000000000), 0x7fffe080000000000000); // This is bad? // inf - try test__extenddfxf2(makeInf64(), 0x7fff8000000000000000); + try test_f80_floatCast_f64(makeInf64(), 0x7fff8000000000000000); // zero - try test__extenddfxf2(0.0, 0x0); + try test_f80_floatCast_f64(0.0, 0x0); - try test__extenddfxf2(0x0.a3456789abcdefp+6, 0x4004a3456789abcdf000); + try test_f80_floatCast_f64(0x0.a3456789abcdefp+6, 0x4004a3456789abcdf000); - try test__extenddfxf2(0x0.edcba987654321fp-8, 0x3ff6edcba98765432000); + try test_f80_floatCast_f64(0x0.edcba987654321fp-8, 0x3ff6edcba98765432000); - try test__extenddfxf2(0x0.a3456789abcdefp+46, 0x402ca3456789abcdf000); + try test_f80_floatCast_f64(0x0.a3456789abcdefp+46, 0x402ca3456789abcdf000); - try test__extenddfxf2(0x0.edcba987654321fp-44, 0x3fd2edcba98765432000); + try test_f80_floatCast_f64(0x0.edcba987654321fp-44, 0x3fd2edcba98765432000); // subnormal - try test__extenddfxf2(0x1.8000000000001p-1022, 0x3c01c000000000000800); - try test__extenddfxf2(0x1.8000000000002p-1023, 0x3c00c000000000001000); + try test_f80_floatCast_f64(0x1.8000000000001p-1022, 0x3c01c000000000000800); + try test_f80_floatCast_f64(0x1.8000000000002p-1023, 0x3c00c000000000001000); } -test "extenddftf2" { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - +test f128_floatCast_f64 { // qNaN - try test__extenddftf2(makeQNaN64(), 0x7fff800000000000, 0x0); + try test_f128_floatCast_f64(makeQNaN64(), 0x7fff800000000000, 0x0); // NaN - try test__extenddftf2(makeNaN64(0x7100000000000), 0x7fff710000000000, 0x0); + try test_f128_floatCast_f64(makeNaN64(0x7100000000000), 0x7fff710000000000, 0x0); // inf - try test__extenddftf2(makeInf64(), 0x7fff000000000000, 0x0); + try test_f128_floatCast_f64(makeInf64(), 0x7fff000000000000, 0x0); // zero - try test__extenddftf2(0.0, 0x0, 0x0); + try test_f128_floatCast_f64(0.0, 0x0, 0x0); - try test__extenddftf2(0x1.23456789abcdefp+5, 0x400423456789abcd, 0xf000000000000000); + try test_f128_floatCast_f64(0x1.23456789abcdefp+5, 0x400423456789abcd, 0xf000000000000000); - try test__extenddftf2(0x1.edcba987654321fp-9, 0x3ff6edcba9876543, 0x2000000000000000); + try test_f128_floatCast_f64(0x1.edcba987654321fp-9, 0x3ff6edcba9876543, 0x2000000000000000); - try test__extenddftf2(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000); + try test_f128_floatCast_f64(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000); - try test__extenddftf2(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000); + try test_f128_floatCast_f64(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000); // subnormal - try test__extenddftf2(0x1.8p-1022, 0x3c01800000000000, 0x0); - try test__extenddftf2(0x1.8p-1023, 0x3c00800000000000, 0x0); + try test_f128_floatCast_f64(0x1.8p-1022, 0x3c01800000000000, 0x0); + try test_f128_floatCast_f64(0x1.8p-1023, 0x3c00800000000000, 0x0); } -test "extendhfsf2" { - try test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN - try test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN +test f32_floatCast_f16 { + try test_f32_floatCast_f16(0x7e00, 0x7fc00000); // qNaN + try test_f32_floatCast_f16(0x7f00, 0x7fe00000); // sNaN // On x86 the NaN becomes quiet because the return is pushed on the x87 // stack due to ABI requirements if (builtin.target.cpu.arch != .x86 and builtin.target.os.tag == .windows) - try test__extendhfsf2(0x7c01, 0x7f802000); // sNaN + try test_f32_floatCast_f16(0x7c01, 0x7f802000); // sNaN - try test__extendhfsf2(0, 0); // 0 - try test__extendhfsf2(0x8000, 0x80000000); // -0 + try test_f32_floatCast_f16(0, 0); // 0 + try test_f32_floatCast_f16(0x8000, 0x80000000); // -0 - try test__extendhfsf2(0x7c00, 0x7f800000); // inf - try test__extendhfsf2(0xfc00, 0xff800000); // -inf + try test_f32_floatCast_f16(0x7c00, 0x7f800000); // inf + try test_f32_floatCast_f16(0xfc00, 0xff800000); // -inf - try test__extendhfsf2(0x0001, 0x33800000); // denormal (min), 2**-24 - try test__extendhfsf2(0x8001, 0xb3800000); // denormal (min), -2**-24 + try test_f32_floatCast_f16(0x0001, 0x33800000); // denormal (min), 2**-24 + try test_f32_floatCast_f16(0x8001, 0xb3800000); // denormal (min), -2**-24 - try test__extendhfsf2(0x03ff, 0x387fc000); // denormal (max), 2**-14 - 2**-24 - try test__extendhfsf2(0x83ff, 0xb87fc000); // denormal (max), -2**-14 + 2**-24 + try test_f32_floatCast_f16(0x03ff, 0x387fc000); // denormal (max), 2**-14 - 2**-24 + try test_f32_floatCast_f16(0x83ff, 0xb87fc000); // denormal (max), -2**-14 + 2**-24 - try test__extendhfsf2(0x0400, 0x38800000); // normal (min), 2**-14 - try test__extendhfsf2(0x8400, 0xb8800000); // normal (min), -2**-14 + try test_f32_floatCast_f16(0x0400, 0x38800000); // normal (min), 2**-14 + try test_f32_floatCast_f16(0x8400, 0xb8800000); // normal (min), -2**-14 - try test__extendhfsf2(0x7bff, 0x477fe000); // normal (max), 65504 - try test__extendhfsf2(0xfbff, 0xc77fe000); // normal (max), -65504 + try test_f32_floatCast_f16(0x7bff, 0x477fe000); // normal (max), 65504 + try test_f32_floatCast_f16(0xfbff, 0xc77fe000); // normal (max), -65504 - try test__extendhfsf2(0x3c01, 0x3f802000); // normal, 1 + 2**-10 - try test__extendhfsf2(0xbc01, 0xbf802000); // normal, -1 - 2**-10 + try test_f32_floatCast_f16(0x3c01, 0x3f802000); // normal, 1 + 2**-10 + try test_f32_floatCast_f16(0xbc01, 0xbf802000); // normal, -1 - 2**-10 - try test__extendhfsf2(0x3555, 0x3eaaa000); // normal, approx. 1/3 - try test__extendhfsf2(0xb555, 0xbeaaa000); // normal, approx. -1/3 + try test_f32_floatCast_f16(0x3555, 0x3eaaa000); // normal, approx. 1/3 + try test_f32_floatCast_f16(0xb555, 0xbeaaa000); // normal, approx. -1/3 } -test "extendsftf2" { +test f128_floatCast_f32 { // qNaN - try test__extendsftf2(makeQNaN32(), 0x7fff800000000000, 0x0); + try test_f128_floatCast_f32(makeQNaN32(), 0x7fff800000000000, 0x0); // NaN - try test__extendsftf2(makeNaN32(0x410000), 0x7fff820000000000, 0x0); + try test_f128_floatCast_f32(makeNaN32(0x410000), 0x7fff820000000000, 0x0); // inf - try test__extendsftf2(makeInf32(), 0x7fff000000000000, 0x0); + try test_f128_floatCast_f32(makeInf32(), 0x7fff000000000000, 0x0); // zero - try test__extendsftf2(0.0, 0x0, 0x0); - try test__extendsftf2(0x1.23456p+5, 0x4004234560000000, 0x0); - try test__extendsftf2(0x1.edcbap-9, 0x3ff6edcba0000000, 0x0); - try test__extendsftf2(0x1.23456p+45, 0x402c234560000000, 0x0); - try test__extendsftf2(0x1.edcbap-45, 0x3fd2edcba0000000, 0x0); + try test_f128_floatCast_f32(0.0, 0x0, 0x0); + try test_f128_floatCast_f32(0x1.23456p+5, 0x4004234560000000, 0x0); + try test_f128_floatCast_f32(0x1.edcbap-9, 0x3ff6edcba0000000, 0x0); + try test_f128_floatCast_f32(0x1.23456p+45, 0x402c234560000000, 0x0); + try test_f128_floatCast_f32(0x1.edcbap-45, 0x3fd2edcba0000000, 0x0); } fn makeQNaN64() f64 { @@ -211,8 +210,8 @@ fn makeInf32() f32 { return @bitCast(@as(u32, 0x7f800000)); } -fn test__extendhftf2(a: u16, expected_hi: u64, expected_lo: u64) !void { - const x = __extendhftf2(@as(F16T(f128), @bitCast(a))); +fn test_f128_floatCast_f16(a: u16, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatCast_f16(@bitCast(a)); const rep: u128 = @bitCast(x); const hi: u64 = @intCast(rep >> 64); @@ -233,26 +232,26 @@ fn test__extendhftf2(a: u16, expected_hi: u64, expected_lo: u64) !void { return error.TestFailure; } -test "extendhftf2" { +test f128_floatCast_f16 { // qNaN - try test__extendhftf2(0x7e00, 0x7fff800000000000, 0x0); + try test_f128_floatCast_f16(0x7e00, 0x7fff800000000000, 0x0); // NaN - try test__extendhftf2(0x7d00, 0x7fff400000000000, 0x0); + try test_f128_floatCast_f16(0x7d00, 0x7fff400000000000, 0x0); // inf - try test__extendhftf2(0x7c00, 0x7fff000000000000, 0x0); - try test__extendhftf2(0xfc00, 0xffff000000000000, 0x0); + try test_f128_floatCast_f16(0x7c00, 0x7fff000000000000, 0x0); + try test_f128_floatCast_f16(0xfc00, 0xffff000000000000, 0x0); // zero - try test__extendhftf2(0x0000, 0x0000000000000000, 0x0); - try test__extendhftf2(0x8000, 0x8000000000000000, 0x0); + try test_f128_floatCast_f16(0x0000, 0x0000000000000000, 0x0); + try test_f128_floatCast_f16(0x8000, 0x8000000000000000, 0x0); // denormal - try test__extendhftf2(0x0010, 0x3feb000000000000, 0x0); - try test__extendhftf2(0x0001, 0x3fe7000000000000, 0x0); - try test__extendhftf2(0x8001, 0xbfe7000000000000, 0x0); + try test_f128_floatCast_f16(0x0010, 0x3feb000000000000, 0x0); + try test_f128_floatCast_f16(0x0001, 0x3fe7000000000000, 0x0); + try test_f128_floatCast_f16(0x8001, 0xbfe7000000000000, 0x0); // pi - try test__extendhftf2(0x4248, 0x4000920000000000, 0x0); - try test__extendhftf2(0xc248, 0xc000920000000000, 0x0); + try test_f128_floatCast_f16(0x4248, 0x4000920000000000, 0x0); + try test_f128_floatCast_f16(0xc248, 0xc000920000000000, 0x0); - try test__extendhftf2(0x508c, 0x4004230000000000, 0x0); - try test__extendhftf2(0x1bb7, 0x3ff6edc000000000, 0x0); + try test_f128_floatCast_f16(0x508c, 0x4004230000000000, 0x0); + try test_f128_floatCast_f16(0x1bb7, 0x3ff6edc000000000, 0x0); } diff --git a/lib/compiler_rt/extendhfdf2.zig b/lib/compiler_rt/extendhfdf2.zig deleted file mode 100644 index 8cadc7139eebbad29f39b5245a14971c5c187a0d..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendhfdf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const extendf = @import("./extendf.zig").extendf; - -comptime { - symbol(&__extendhfdf2, "__extendhfdf2"); -} - -pub fn __extendhfdf2(a: compiler_rt.F16T(f64)) callconv(.c) f64 { - return extendf(f64, f16, @as(u16, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendhfsf2.zig b/lib/compiler_rt/extendhfsf2.zig deleted file mode 100644 index b638192c47502e6e698e86fcce8be3fbc0f7d2f9..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendhfsf2.zig +++ /dev/null @@ -1,24 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const extendf = @import("./extendf.zig").extendf; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.gnu_f16_abi) { - symbol(&__gnu_h2f_ieee, "__gnu_h2f_ieee"); - } else if (compiler_rt.want_aeabi) { - symbol(&__aeabi_h2f, "__aeabi_h2f"); - } - symbol(&__extendhfsf2, "__extendhfsf2"); -} - -pub fn __extendhfsf2(a: compiler_rt.F16T(f32)) callconv(.c) f32 { - return extendf(f32, f16, @as(u16, @bitCast(a))); -} - -fn __gnu_h2f_ieee(a: compiler_rt.F16T(f32)) callconv(.c) f32 { - return extendf(f32, f16, @as(u16, @bitCast(a))); -} - -fn __aeabi_h2f(a: u16) callconv(.{ .arm_aapcs = .{} }) f32 { - return extendf(f32, f16, @as(u16, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendhftf2.zig b/lib/compiler_rt/extendhftf2.zig deleted file mode 100644 index 29e7866b663389aae7048a474e585916fec7cac1..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendhftf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extendf = @import("./extendf.zig").extendf; - -comptime { - symbol(&__extendhftf2, "__extendhftf2"); -} - -pub fn __extendhftf2(a: compiler_rt.F16T(f128)) callconv(.c) f128 { - return extendf(f128, f16, @as(u16, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendhfxf2.zig b/lib/compiler_rt/extendhfxf2.zig deleted file mode 100644 index e76daf4f55045262daa10cb4547688ed012a6bc0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendhfxf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extend_f80 = @import("./extendf.zig").extend_f80; - -comptime { - symbol(&__extendhfxf2, "__extendhfxf2"); -} - -fn __extendhfxf2(a: compiler_rt.F16T(f80)) callconv(.c) f80 { - return extend_f80(f16, @as(u16, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendsfdf2.zig b/lib/compiler_rt/extendsfdf2.zig deleted file mode 100644 index 4f34b05242a5f57155c9bb83c3e978c6ec3ace42..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendsfdf2.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extendf = @import("./extendf.zig").extendf; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2d, "__aeabi_f2d"); - } else { - symbol(&__extendsfdf2, "__extendsfdf2"); - } -} - -fn __extendsfdf2(a: f32) callconv(.c) f64 { - return extendf(f64, f32, @as(u32, @bitCast(a))); -} - -fn __aeabi_f2d(a: f32) callconv(.{ .arm_aapcs = .{} }) f64 { - return extendf(f64, f32, @as(u32, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendsftf2.zig b/lib/compiler_rt/extendsftf2.zig deleted file mode 100644 index 6135065b14297e34c04e7cefec5b9387321089a7..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendsftf2.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const extendf = @import("./extendf.zig").extendf; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__extendsftf2, "__extendsfkf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_stoq, "_Qp_stoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__extendsftf2, "_Q_stoq"); - } - symbol(&__extendsftf2, "__extendsftf2"); -} - -pub fn __extendsftf2(a: f32) callconv(.c) f128 { - return extendf(f128, f32, @as(u32, @bitCast(a))); -} - -fn _Qp_stoq(c: *f128, a: f32) callconv(.c) void { - c.* = extendf(f128, f32, @as(u32, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendsfxf2.zig b/lib/compiler_rt/extendsfxf2.zig deleted file mode 100644 index 9a6796bd668602b1d653a6581613fcb69edb7853..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendsfxf2.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const extend_f80 = @import("./extendf.zig").extend_f80; - -comptime { - symbol(&__extendsfxf2, "__extendsfxf2"); -} - -fn __extendsfxf2(a: f32) callconv(.c) f80 { - return extend_f80(f32, @as(u32, @bitCast(a))); -} diff --git a/lib/compiler_rt/extendxftf2.zig b/lib/compiler_rt/extendxftf2.zig deleted file mode 100644 index 1c39e1e84c7a3beb0a9470a123c05dea456eed77..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/extendxftf2.zig +++ /dev/null @@ -1,42 +0,0 @@ -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__extendxftf2, "__extendxftf2"); -} - -fn __extendxftf2(a: f80) callconv(.c) f128 { - const src_int_bit: u64 = 0x8000000000000000; - const src_sig_mask = ~src_int_bit; - const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit - const dst_sig_bits = std.math.floatMantissaBits(f128); - - const dst_bits = @bitSizeOf(f128); - - // Break a into a sign and representation of the absolute value - var a_rep = std.math.F80.fromFloat(a); - const sign = a_rep.exp & 0x8000; - a_rep.exp &= 0x7FFF; - var abs_result: u128 = undefined; - - if (a_rep.exp == 0 and a_rep.fraction == 0) { - // zero - abs_result = 0; - } else if (a_rep.exp == 0x7FFF) { - // a is nan or infinite - abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); - abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; - } else if (a_rep.fraction & src_int_bit != 0) { - // a is a normal value - abs_result = @as(u128, a_rep.fraction & src_sig_mask) << (dst_sig_bits - src_sig_bits); - abs_result |= @as(u128, a_rep.exp) << dst_sig_bits; - } else { - // a is denormal - abs_result = @as(u128, a_rep.fraction) << (dst_sig_bits - src_sig_bits); - } - - // Apply the signbit to (dst_t)abs(a). - const result: u128 align(@alignOf(f128)) = abs_result | @as(u128, sign) << (dst_bits - 16); - return @bitCast(result); -} diff --git a/lib/compiler_rt/fabs.zig b/lib/compiler_rt/fabs.zig index abdf21df8f33de1c080aba1452ae233287283540..2238e65e61292668cb2e7bc2e2be3f090470b2e9 100644 --- a/lib/compiler_rt/fabs.zig +++ b/lib/compiler_rt/fabs.zig @@ -9,39 +9,51 @@ comptime { symbol(&fabsf, "fabsf"); symbol(&fabs, "fabs"); symbol(&__fabsx, "__fabsx"); - if (compiler_rt.want_ppc_abi) { - symbol(&fabsq, "fabsf128"); - } - symbol(&fabsq, "fabsq"); + symbol(&fabsq, "fabsf128"); symbol(&fabsl, "fabsl"); } -pub fn __fabsh(a: f16) callconv(.c) f16 { +fn __fabsh(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fabs_f16(compiler_rt.f16.fromAbi(a))); +} +pub fn fabs_f16(a: f16) f16 { return generic_fabs(a); } -pub fn fabsf(a: f32) callconv(.c) f32 { +fn fabsf(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fabs_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn fabs_f32(a: f32) f32 { return generic_fabs(a); } -pub fn fabs(a: f64) callconv(.c) f64 { +fn fabs(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fabs_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn fabs_f64(a: f64) f64 { return generic_fabs(a); } -pub fn __fabsx(a: f80) callconv(.c) f80 { +fn __fabsx(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fabs_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn fabs_f80(a: f80) f80 { return generic_fabs(a); } -pub fn fabsq(a: f128) callconv(.c) f128 { +fn fabsq(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fabs_f128(compiler_rt.f128.fromAbi(a))); +} +pub fn fabs_f128(a: f128) f128 { return generic_fabs(a); } pub fn fabsl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fabs(x), - 80 => return __fabsx(x), - 128 => return fabsq(x), - else => @compileError("unreachable"), + 64 => return fabs_f64(x), + 80 => return fabs_f80(x), + 128 => return fabs_f128(x), + else => comptime unreachable, } } diff --git a/lib/compiler_rt/fixdfdi.zig b/lib/compiler_rt/fixdfdi.zig deleted file mode 100644 index 5a66cc124f0f4ec092f1c49715ae6c547a396b66..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixdfdi.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2lz, "__aeabi_d2lz"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__fixdfdi, "__dtoi64"); - } - symbol(&__fixdfdi, "__fixdfdi"); - } -} - -pub fn __fixdfdi(a: f64) callconv(.c) i64 { - return intFromFloat(i64, a); -} - -fn __aeabi_d2lz(a: f64) callconv(.{ .arm_aapcs = .{} }) i64 { - return intFromFloat(i64, a); -} diff --git a/lib/compiler_rt/fixdfei.zig b/lib/compiler_rt/fixdfei.zig deleted file mode 100644 index 170b4a160337fe5fc426fe2e715ab46426d76d7e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixdfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixdfei, "__fixdfei"); -} - -pub fn __fixdfei(r: [*]u8, bits: usize, a: f64) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixdfsi.zig b/lib/compiler_rt/fixdfsi.zig deleted file mode 100644 index 1d42337ea54573e4c7423147323046b029f9af52..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixdfsi.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2iz, "__aeabi_d2iz"); - } else { - symbol(&__fixdfsi, "__fixdfsi"); - } -} - -pub fn __fixdfsi(a: f64) callconv(.c) i32 { - return intFromFloat(i32, a); -} - -fn __aeabi_d2iz(a: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return intFromFloat(i32, a); -} diff --git a/lib/compiler_rt/fixdfti.zig b/lib/compiler_rt/fixdfti.zig deleted file mode 100644 index ff7434d63da148afc20b22bbfb54d6c1bdd17822..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixdfti.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__fixdfti, "__fixdfti"); -} - -pub fn __fixdfti(a: f64) callconv(.c) i128 { - return intFromFloat(i128, a); -} diff --git a/lib/compiler_rt/fixhfei.zig b/lib/compiler_rt/fixhfei.zig deleted file mode 100644 index 5b759c3fc683d909ce7808242a59129c310bbb56..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixhfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixhfei, "__fixhfei"); -} - -pub fn __fixhfei(r: [*]u8, bits: usize, a: f16) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixint_test.zig b/lib/compiler_rt/fixint_test.zig deleted file mode 100644 index 198167ab867c22ed6160e83ed90920a6c5e97f28..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixint_test.zig +++ /dev/null @@ -1,149 +0,0 @@ -const std = @import("std"); -const math = std.math; -const testing = std.testing; - -const fixint = @import("fixint.zig").fixint; - -fn test__fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t, expected: fixint_t) !void { - const x = fixint(fp_t, fixint_t, a); - try testing.expect(x == expected); -} - -test "fixint.i1" { - try test__fixint(f32, i1, -math.inf(f32), -1); - try test__fixint(f32, i1, -math.floatMax(f32), -1); - try test__fixint(f32, i1, -2.0, -1); - try test__fixint(f32, i1, -1.1, -1); - try test__fixint(f32, i1, -1.0, -1); - try test__fixint(f32, i1, -0.9, 0); - try test__fixint(f32, i1, -0.1, 0); - try test__fixint(f32, i1, -math.floatMin(f32), 0); - try test__fixint(f32, i1, -0.0, 0); - try test__fixint(f32, i1, 0.0, 0); - try test__fixint(f32, i1, math.floatMin(f32), 0); - try test__fixint(f32, i1, 0.1, 0); - try test__fixint(f32, i1, 0.9, 0); - try test__fixint(f32, i1, 1.0, 0); - try test__fixint(f32, i1, 2.0, 0); - try test__fixint(f32, i1, math.floatMax(f32), 0); - try test__fixint(f32, i1, math.inf(f32), 0); -} - -test "fixint.i2" { - try test__fixint(f32, i2, -math.inf(f32), -2); - try test__fixint(f32, i2, -math.floatMax(f32), -2); - try test__fixint(f32, i2, -2.0, -2); - try test__fixint(f32, i2, -1.9, -1); - try test__fixint(f32, i2, -1.1, -1); - try test__fixint(f32, i2, -1.0, -1); - try test__fixint(f32, i2, -0.9, 0); - try test__fixint(f32, i2, -0.1, 0); - try test__fixint(f32, i2, -math.floatMin(f32), 0); - try test__fixint(f32, i2, -0.0, 0); - try test__fixint(f32, i2, 0.0, 0); - try test__fixint(f32, i2, math.floatMin(f32), 0); - try test__fixint(f32, i2, 0.1, 0); - try test__fixint(f32, i2, 0.9, 0); - try test__fixint(f32, i2, 1.0, 1); - try test__fixint(f32, i2, 2.0, 1); - try test__fixint(f32, i2, math.floatMax(f32), 1); - try test__fixint(f32, i2, math.inf(f32), 1); -} - -test "fixint.i3" { - try test__fixint(f32, i3, -math.inf(f32), -4); - try test__fixint(f32, i3, -math.floatMax(f32), -4); - try test__fixint(f32, i3, -4.0, -4); - try test__fixint(f32, i3, -3.0, -3); - try test__fixint(f32, i3, -2.0, -2); - try test__fixint(f32, i3, -1.9, -1); - try test__fixint(f32, i3, -1.1, -1); - try test__fixint(f32, i3, -1.0, -1); - try test__fixint(f32, i3, -0.9, 0); - try test__fixint(f32, i3, -0.1, 0); - try test__fixint(f32, i3, -math.floatMin(f32), 0); - try test__fixint(f32, i3, -0.0, 0); - try test__fixint(f32, i3, 0.0, 0); - try test__fixint(f32, i3, math.floatMin(f32), 0); - try test__fixint(f32, i3, 0.1, 0); - try test__fixint(f32, i3, 0.9, 0); - try test__fixint(f32, i3, 1.0, 1); - try test__fixint(f32, i3, 2.0, 2); - try test__fixint(f32, i3, 3.0, 3); - try test__fixint(f32, i3, 4.0, 3); - try test__fixint(f32, i3, math.floatMax(f32), 3); - try test__fixint(f32, i3, math.inf(f32), 3); -} - -test "fixint.i32" { - try test__fixint(f64, i32, -math.inf(f64), math.minInt(i32)); - try test__fixint(f64, i32, -math.floatMax(f64), math.minInt(i32)); - try test__fixint(f64, i32, @as(f64, math.minInt(i32)), math.minInt(i32)); - try test__fixint(f64, i32, @as(f64, math.minInt(i32)) + 1, math.minInt(i32) + 1); - try test__fixint(f64, i32, -2.0, -2); - try test__fixint(f64, i32, -1.9, -1); - try test__fixint(f64, i32, -1.1, -1); - try test__fixint(f64, i32, -1.0, -1); - try test__fixint(f64, i32, -0.9, 0); - try test__fixint(f64, i32, -0.1, 0); - try test__fixint(f64, i32, -@as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i32, -0.0, 0); - try test__fixint(f64, i32, 0.0, 0); - try test__fixint(f64, i32, @as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i32, 0.1, 0); - try test__fixint(f64, i32, 0.9, 0); - try test__fixint(f64, i32, 1.0, 1); - try test__fixint(f64, i32, @as(f64, math.maxInt(i32)) - 1, math.maxInt(i32) - 1); - try test__fixint(f64, i32, @as(f64, math.maxInt(i32)), math.maxInt(i32)); - try test__fixint(f64, i32, math.floatMax(f64), math.maxInt(i32)); - try test__fixint(f64, i32, math.inf(f64), math.maxInt(i32)); -} - -test "fixint.i64" { - try test__fixint(f64, i64, -math.inf(f64), math.minInt(i64)); - try test__fixint(f64, i64, -math.floatMax(f64), math.minInt(i64)); - try test__fixint(f64, i64, @as(f64, math.minInt(i64)), math.minInt(i64)); - try test__fixint(f64, i64, @as(f64, math.minInt(i64)) + 1, math.minInt(i64)); - try test__fixint(f64, i64, @as(f64, math.minInt(i64) / 2), math.minInt(i64) / 2); - try test__fixint(f64, i64, -2.0, -2); - try test__fixint(f64, i64, -1.9, -1); - try test__fixint(f64, i64, -1.1, -1); - try test__fixint(f64, i64, -1.0, -1); - try test__fixint(f64, i64, -0.9, 0); - try test__fixint(f64, i64, -0.1, 0); - try test__fixint(f64, i64, -@as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i64, -0.0, 0); - try test__fixint(f64, i64, 0.0, 0); - try test__fixint(f64, i64, @as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i64, 0.1, 0); - try test__fixint(f64, i64, 0.9, 0); - try test__fixint(f64, i64, 1.0, 1); - try test__fixint(f64, i64, @as(f64, math.maxInt(i64)) - 1, math.maxInt(i64)); - try test__fixint(f64, i64, @as(f64, math.maxInt(i64)), math.maxInt(i64)); - try test__fixint(f64, i64, math.floatMax(f64), math.maxInt(i64)); - try test__fixint(f64, i64, math.inf(f64), math.maxInt(i64)); -} - -test "fixint.i128" { - try test__fixint(f64, i128, -math.inf(f64), math.minInt(i128)); - try test__fixint(f64, i128, -math.floatMax(f64), math.minInt(i128)); - try test__fixint(f64, i128, @as(f64, math.minInt(i128)), math.minInt(i128)); - try test__fixint(f64, i128, @as(f64, math.minInt(i128)) + 1, math.minInt(i128)); - try test__fixint(f64, i128, -2.0, -2); - try test__fixint(f64, i128, -1.9, -1); - try test__fixint(f64, i128, -1.1, -1); - try test__fixint(f64, i128, -1.0, -1); - try test__fixint(f64, i128, -0.9, 0); - try test__fixint(f64, i128, -0.1, 0); - try test__fixint(f64, i128, -@as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i128, -0.0, 0); - try test__fixint(f64, i128, 0.0, 0); - try test__fixint(f64, i128, @as(f64, math.floatMin(f32)), 0); - try test__fixint(f64, i128, 0.1, 0); - try test__fixint(f64, i128, 0.9, 0); - try test__fixint(f64, i128, 1.0, 1); - try test__fixint(f64, i128, @as(f64, math.maxInt(i128)) - 1, math.maxInt(i128)); - try test__fixint(f64, i128, @as(f64, math.maxInt(i128)), math.maxInt(i128)); - try test__fixint(f64, i128, math.floatMax(f64), math.maxInt(i128)); - try test__fixint(f64, i128, math.inf(f64), math.maxInt(i128)); -} diff --git a/lib/compiler_rt/fixsfdi.zig b/lib/compiler_rt/fixsfdi.zig deleted file mode 100644 index 0a3731877e8bf7c7591391c8d76a6a5f953e74f1..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixsfdi.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2lz, "__aeabi_f2lz"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__fixsfdi, "__stoi64"); - } - symbol(&__fixsfdi, "__fixsfdi"); - } -} - -pub fn __fixsfdi(a: f32) callconv(.c) i64 { - return intFromFloat(i64, a); -} - -fn __aeabi_f2lz(a: f32) callconv(.{ .arm_aapcs = .{} }) i64 { - return intFromFloat(i64, a); -} diff --git a/lib/compiler_rt/fixsfei.zig b/lib/compiler_rt/fixsfei.zig deleted file mode 100644 index 43243254059d78d0ba678bcf1ae9ab37b50c3f47..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixsfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixsfei, "__fixsfei"); -} - -pub fn __fixsfei(r: [*]u8, bits: usize, a: f32) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixsfsi.zig b/lib/compiler_rt/fixsfsi.zig deleted file mode 100644 index 9c07c5824a25aac5f83ae2e2f58ce4df66f53b38..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixsfsi.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2iz, "__aeabi_f2iz"); - } else { - symbol(&__fixsfsi, "__fixsfsi"); - } -} - -pub fn __fixsfsi(a: f32) callconv(.c) i32 { - return intFromFloat(i32, a); -} - -fn __aeabi_f2iz(a: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return intFromFloat(i32, a); -} diff --git a/lib/compiler_rt/fixsfti.zig b/lib/compiler_rt/fixsfti.zig deleted file mode 100644 index 121eff084d58a00726ed140a0d4f4cacafdce87b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixsfti.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixsfti, "__fixsfti"); -} - -pub fn __fixsfti(a: f32) callconv(.c) i128 { - return intFromFloat(i128, a); -} diff --git a/lib/compiler_rt/fixtfdi.zig b/lib/compiler_rt/fixtfdi.zig deleted file mode 100644 index d64682db1c1153d982acba2636b39f2b17e63753..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixtfdi.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__fixtfdi, "__fixkfdi"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtox, "_Qp_qtox"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__fixtfdi, "_Q_qtoll"); - } - symbol(&__fixtfdi, "__fixtfdi"); -} - -pub fn __fixtfdi(a: f128) callconv(.c) i64 { - return intFromFloat(i64, a); -} - -fn _Qp_qtox(a: *const f128) callconv(.c) i64 { - return intFromFloat(i64, a.*); -} diff --git a/lib/compiler_rt/fixtfei.zig b/lib/compiler_rt/fixtfei.zig deleted file mode 100644 index 6443a0cb3be226c25affb17567fa8c860868aaa1..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixtfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixtfei, "__fixtfei"); -} - -pub fn __fixtfei(r: [*]u8, bits: usize, a: f128) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixtfsi.zig b/lib/compiler_rt/fixtfsi.zig deleted file mode 100644 index 9acc5ec8eac8cb72a826c50d6d034e1ea48ef603..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixtfsi.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__fixtfsi, "__fixkfsi"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtoi, "_Qp_qtoi"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__fixtfsi, "_Q_qtoi"); - } - symbol(&__fixtfsi, "__fixtfsi"); -} - -pub fn __fixtfsi(a: f128) callconv(.c) i32 { - return intFromFloat(i32, a); -} - -fn _Qp_qtoi(a: *const f128) callconv(.c) i32 { - return intFromFloat(i32, a.*); -} diff --git a/lib/compiler_rt/fixtfti.zig b/lib/compiler_rt/fixtfti.zig deleted file mode 100644 index 0aac298ca2c4d0fa3f8d7fd02cf1290f98929c2b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixtfti.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) - symbol(&__fixtfti, "__fixkfti"); - symbol(&__fixtfti, "__fixtfti"); -} - -pub fn __fixtfti(a: f128) callconv(.c) i128 { - return intFromFloat(i128, a); -} diff --git a/lib/compiler_rt/fixunsdfdi.zig b/lib/compiler_rt/fixunsdfdi.zig deleted file mode 100644 index 340bb8f6b11276fd9fff401b7f6a655e63d0a218..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsdfdi.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2ulz, "__aeabi_d2ulz"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__fixunsdfdi, "__dtou64"); - } - symbol(&__fixunsdfdi, "__fixunsdfdi"); - } -} - -pub fn __fixunsdfdi(a: f64) callconv(.c) u64 { - return intFromFloat(u64, a); -} - -fn __aeabi_d2ulz(a: f64) callconv(.{ .arm_aapcs = .{} }) u64 { - return intFromFloat(u64, a); -} diff --git a/lib/compiler_rt/fixunsdfei.zig b/lib/compiler_rt/fixunsdfei.zig deleted file mode 100644 index f564f7f7a32869e7cdad92a2f264941a3eab7511..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsdfei.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunsdfei, "__fixunsdfei"); -} - -pub fn __fixunsdfei(r: [*]u8, bits: usize, a: f64) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunsdfsi.zig b/lib/compiler_rt/fixunsdfsi.zig deleted file mode 100644 index e8b976d03d690d0de88d07e3fe4b97c0490e5901..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsdfsi.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2uiz, "__aeabi_d2uiz"); - } else { - symbol(&__fixunsdfsi, "__fixunsdfsi"); - } -} - -pub fn __fixunsdfsi(a: f64) callconv(.c) u32 { - return intFromFloat(u32, a); -} - -fn __aeabi_d2uiz(a: f64) callconv(.{ .arm_aapcs = .{} }) u32 { - return intFromFloat(u32, a); -} diff --git a/lib/compiler_rt/fixunsdfti.zig b/lib/compiler_rt/fixunsdfti.zig deleted file mode 100644 index 1a634baaf5a6da399abaebb3e236ea5c02005ead..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsdfti.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunsdfti, "__fixunsdfti"); -} - -pub fn __fixunsdfti(a: f64) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixunshfdi.zig b/lib/compiler_rt/fixunshfdi.zig deleted file mode 100644 index 741e482506d2df3ffbb1388a9848f9317f6f1808..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunshfdi.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunshfdi, "__fixunshfdi"); -} - -fn __fixunshfdi(a: f16) callconv(.c) u64 { - return intFromFloat(u64, a); -} diff --git a/lib/compiler_rt/fixunshfei.zig b/lib/compiler_rt/fixunshfei.zig deleted file mode 100644 index a61d94f3958f4cc8f5f01f57f317e5a44f32fc20..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunshfei.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunshfei, "__fixunshfei"); -} - -pub fn __fixunshfei(r: [*]u8, bits: usize, a: f16) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunshfsi.zig b/lib/compiler_rt/fixunshfsi.zig deleted file mode 100644 index 438767c7a89a57c22385a1b666a6f59875d1f7ba..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunshfsi.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunshfsi, "__fixunshfsi"); -} - -fn __fixunshfsi(a: f16) callconv(.c) u32 { - return intFromFloat(u32, a); -} diff --git a/lib/compiler_rt/fixunshfti.zig b/lib/compiler_rt/fixunshfti.zig deleted file mode 100644 index 3dc7a5f99390d05606bb09298651e1d4482e3ab6..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunshfti.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__fixunshfti, "__fixunshfti"); -} - -pub fn __fixunshfti(a: f16) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixunssfdi.zig b/lib/compiler_rt/fixunssfdi.zig deleted file mode 100644 index ffc238a53fb9f12a64446371a3d3191331d6994c..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunssfdi.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2ulz, "__aeabi_f2ulz"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__fixunssfdi, "__stou64"); - } - symbol(&__fixunssfdi, "__fixunssfdi"); - } -} - -pub fn __fixunssfdi(a: f32) callconv(.c) u64 { - return intFromFloat(u64, a); -} - -fn __aeabi_f2ulz(a: f32) callconv(.{ .arm_aapcs = .{} }) u64 { - return intFromFloat(u64, a); -} diff --git a/lib/compiler_rt/fixunssfei.zig b/lib/compiler_rt/fixunssfei.zig deleted file mode 100644 index 2fd123bd1b4693f96b51604a794dc2879660dc87..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunssfei.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunssfei, "__fixunssfei"); -} - -pub fn __fixunssfei(r: [*]u8, bits: usize, a: f32) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunssfsi.zig b/lib/compiler_rt/fixunssfsi.zig deleted file mode 100644 index f9c09b3f3d881774c21117e3c32b3a0b0b0a9f82..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunssfsi.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2uiz, "__aeabi_f2uiz"); - } else { - symbol(&__fixunssfsi, "__fixunssfsi"); - } -} - -pub fn __fixunssfsi(a: f32) callconv(.c) u32 { - return intFromFloat(u32, a); -} - -fn __aeabi_f2uiz(a: f32) callconv(.{ .arm_aapcs = .{} }) u32 { - return intFromFloat(u32, a); -} diff --git a/lib/compiler_rt/fixunssfti.zig b/lib/compiler_rt/fixunssfti.zig deleted file mode 100644 index 6824afcde4b518642189696a47c0983047dd47c3..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunssfti.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__fixunssfti, "__fixunssfti"); -} - -pub fn __fixunssfti(a: f32) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixunstfdi.zig b/lib/compiler_rt/fixunstfdi.zig deleted file mode 100644 index c535bcc3583c93721f4fc07146f66edcc7611b01..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunstfdi.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__fixunstfdi, "__fixunskfdi"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtoux, "_Qp_qtoux"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__fixunstfdi, "_Q_qtoull"); - } - symbol(&__fixunstfdi, "__fixunstfdi"); -} - -pub fn __fixunstfdi(a: f128) callconv(.c) u64 { - return intFromFloat(u64, a); -} - -fn _Qp_qtoux(a: *const f128) callconv(.c) u64 { - return intFromFloat(u64, a.*); -} diff --git a/lib/compiler_rt/fixunstfei.zig b/lib/compiler_rt/fixunstfei.zig deleted file mode 100644 index 3d8986da90790a1a9cbf9a5fa2939e94c8009cc2..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunstfei.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunstfei, "__fixunstfei"); -} - -pub fn __fixunstfei(r: [*]u8, bits: usize, a: f128) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunstfsi.zig b/lib/compiler_rt/fixunstfsi.zig deleted file mode 100644 index d31cd759744d7616b30050335f70c50921a76ca9..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunstfsi.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__fixunstfsi, "__fixunskfsi"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtoui, "_Qp_qtoui"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__fixunstfsi, "_Q_qtou"); - } - symbol(&__fixunstfsi, "__fixunstfsi"); -} - -pub fn __fixunstfsi(a: f128) callconv(.c) u32 { - return intFromFloat(u32, a); -} - -fn _Qp_qtoui(a: *const f128) callconv(.c) u32 { - return intFromFloat(u32, a.*); -} diff --git a/lib/compiler_rt/fixunstfti.zig b/lib/compiler_rt/fixunstfti.zig deleted file mode 100644 index 78c6b1e8f7b90aa5d90a957920e949bb0aa2cbc0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunstfti.zig +++ /dev/null @@ -1,14 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - if (compiler_rt.want_ppc_abi) - symbol(&__fixunstfti, "__fixunskfti"); - symbol(&__fixunstfti, "__fixunstfti"); -} - -pub fn __fixunstfti(a: f128) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixunsxfdi.zig b/lib/compiler_rt/fixunsxfdi.zig deleted file mode 100644 index 8385961b6b2ea2cd7632776ffa46d41e9e6f8bf3..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsxfdi.zig +++ /dev/null @@ -1,10 +0,0 @@ -const intFromFloat = @import("./int_from_float.zig").intFromFloat; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__fixunsxfdi, "__fixunsxfdi"); -} - -fn __fixunsxfdi(a: f80) callconv(.c) u64 { - return intFromFloat(u64, a); -} diff --git a/lib/compiler_rt/fixunsxfei.zig b/lib/compiler_rt/fixunsxfei.zig deleted file mode 100644 index d7902ddff54773d5240a57c8aaf6910ab6f9f02e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsxfei.zig +++ /dev/null @@ -1,13 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const symbol = @import("../compiler_rt.zig").symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixunsxfei, "__fixunsxfei"); -} - -pub fn __fixunsxfei(r: [*]u8, bits: usize, a: f80) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.unsigned, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixunsxfsi.zig b/lib/compiler_rt/fixunsxfsi.zig deleted file mode 100644 index 7309fbf5a6cf72a7eb862773fbb121437243c2ee..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsxfsi.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunsxfsi, "__fixunsxfsi"); -} - -fn __fixunsxfsi(a: f80) callconv(.c) u32 { - return intFromFloat(u32, a); -} diff --git a/lib/compiler_rt/fixunsxfti.zig b/lib/compiler_rt/fixunsxfti.zig deleted file mode 100644 index 064c1352c9045870c1a984850f71c86fcf6e8e61..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixunsxfti.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixunsxfti, "__fixunsxfti"); -} - -pub fn __fixunsxfti(a: f80) callconv(.c) u128 { - return intFromFloat(u128, a); -} diff --git a/lib/compiler_rt/fixxfdi.zig b/lib/compiler_rt/fixxfdi.zig deleted file mode 100644 index e9e4b7528b07168dafdf4791a6cc13d795d5b78a..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixxfdi.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixxfdi, "__fixxfdi"); -} - -fn __fixxfdi(a: f80) callconv(.c) i64 { - return intFromFloat(i64, a); -} diff --git a/lib/compiler_rt/fixxfei.zig b/lib/compiler_rt/fixxfei.zig deleted file mode 100644 index 82cd67648df13ac446de3a74ef796ba55ad45065..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixxfei.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const bigIntFromFloat = @import("int_from_float.zig").bigIntFromFloat; - -comptime { - symbol(&__fixxfei, "__fixxfei"); -} - -pub fn __fixxfei(r: [*]u8, bits: usize, a: f80) callconv(.c) void { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return bigIntFromFloat(.signed, @ptrCast(@alignCast(r[0..byte_size])), a); -} diff --git a/lib/compiler_rt/fixxfsi.zig b/lib/compiler_rt/fixxfsi.zig deleted file mode 100644 index 363492168c760bcd12432e7c757ec4b8f60a2cc1..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/fixxfsi.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const intFromFloat = @import("./int_from_float.zig").intFromFloat; - -comptime { - symbol(&__fixxfsi, "__fixxfsi"); -} - -fn __fixxfsi(a: f80) callconv(.c) i32 { - return intFromFloat(i32, a); -} diff --git a/lib/compiler_rt/float_from_int.zig b/lib/compiler_rt/float_from_int.zig index 548d027accbb674e1ecbaeb77ef01a5491e256bc..898f246579c2902f5267d7e54c87422292931891 100644 --- a/lib/compiler_rt/float_from_int.zig +++ b/lib/compiler_rt/float_from_int.zig @@ -1,7 +1,475 @@ +const builtin = @import("builtin"); const std = @import("std"); const math = std.math; -pub fn floatFromInt(comptime T: type, x: anytype) T { +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + symbol(&__floatsihf, "__floatsihf"); + symbol(&__floatdihf, "__floatdihf"); + symbol(&__floattihf, "__floattihf"); + symbol(&__floateihf, "__floateihf"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_i2f, "__aeabi_i2f"); + symbol(&__aeabi_l2f, "__aeabi_l2f"); + } else { + symbol(&__floatsisf, "__floatsisf"); + symbol(&__floatdisf, "__floatdisf"); + if (compiler_rt.want_windows_arm_abi) symbol(&__floatdisf, "__i64tos"); + } + symbol(&__floattisf, "__floattisf"); + symbol(&__floateisf, "__floateisf"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_i2d, "__aeabi_i2d"); + symbol(&__aeabi_l2d, "__aeabi_l2d"); + } else { + symbol(&__floatsidf, "__floatsidf"); + symbol(&__floatdidf, "__floatdidf"); + if (compiler_rt.want_windows_arm_abi) symbol(&__floatdidf, "__i64tod"); + } + symbol(&__floattidf, "__floattidf"); + symbol(&__floateidf, "__floateidf"); + + symbol(&__floatsixf, "__floatsixf"); + symbol(&__floatdixf, "__floatdixf"); + symbol(&__floattixf, "__floattixf"); + symbol(&__floateixf, "__floateixf"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__floatsitf, "__floatsikf"); + symbol(&__floatditf, "__floatdikf"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_itoq, "_Qp_itoq"); + symbol(&_Qp_xtoq, "_Qp_xtoq"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__floatsitf, "_Q_itoq"); + symbol(&__floatditf, "_Q_lltoq"); + } else { + symbol(&__floatsitf, "__floatsitf"); + symbol(&__floatditf, "__floatditf"); + } + if (compiler_rt.want_ppc_abi) { + symbol(&__floattitf, "__floattikf"); + symbol(&__floateitf, "__floateikf"); + } else { + if (builtin.cpu.arch == .x86) { + symbol(&__floattitf_x86, "__floattitf"); + } else { + symbol(&__floattitf, "__floattitf"); + } + symbol(&__floateitf, "__floateitf"); + } +} + +fn __floatsihf(a: i32) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_i32(a)); +} +pub fn f16_floatFromInt_i32(a: i32) f16 { + return floatFromInt(f16, a); +} + +fn __floatdihf(a: i64) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_i64(a)); +} +pub fn f16_floatFromInt_i64(a: i64) f16 { + return floatFromInt(f16, a); +} + +fn __floattihf(a: i128) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_i128(a)); +} +pub fn f16_floatFromInt_i128(a: i128) f16 { + return floatFromInt(f16, a); +} + +fn __floateihf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f16.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f16.toAbi(f16_floatFromInt_signed(a[0..byte_size])); +} +pub fn f16_floatFromInt_signed(a: []const u8) f16 { + return floatFromBigInt(f16, .signed, @ptrCast(@alignCast(a))); +} + +fn __floatsisf(a: i32) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_i32(a)); +} +fn __aeabi_i2f(a: i32) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatFromInt_i32(a); +} +pub fn f32_floatFromInt_i32(a: i32) f32 { + return floatFromInt(f32, a); +} + +fn __floatdisf(a: i64) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_i64(a)); +} +fn __aeabi_l2f(a: i64) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatFromInt_i64(a); +} +pub fn f32_floatFromInt_i64(a: i64) f32 { + return floatFromInt(f32, a); +} + +fn __floattisf(a: i128) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_i128(a)); +} +pub fn f32_floatFromInt_i128(a: i128) f32 { + return floatFromInt(f32, a); +} + +fn __floateisf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f32.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f32.toAbi(f32_floatFromInt_signed(a[0..byte_size])); +} +pub fn f32_floatFromInt_signed(a: []const u8) f32 { + return floatFromBigInt(f32, .signed, @ptrCast(@alignCast(a))); +} + +fn __floatsidf(a: i32) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_i32(a)); +} +fn __aeabi_i2d(a: i32) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatFromInt_i32(a); +} +pub fn f64_floatFromInt_i32(a: i32) f64 { + return floatFromInt(f64, a); +} + +fn __floatdidf(a: i64) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_i64(a)); +} +fn __aeabi_l2d(a: i64) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatFromInt_i64(a); +} +pub fn f64_floatFromInt_i64(a: i64) f64 { + return floatFromInt(f64, a); +} + +fn __floattidf(a: i128) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_i128(a)); +} +pub fn f64_floatFromInt_i128(a: i128) f64 { + return floatFromInt(f64, a); +} + +fn __floateidf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f64.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f64.toAbi(f64_floatFromInt_signed(a[0..byte_size])); +} +pub fn f64_floatFromInt_signed(a: []const u8) f64 { + return floatFromBigInt(f64, .signed, @ptrCast(@alignCast(a))); +} + +fn __floatsixf(a: i32) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_i32(a)); +} +pub fn f80_floatFromInt_i32(a: i32) f80 { + return floatFromInt(f80, a); +} + +fn __floatdixf(a: i64) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_i64(a)); +} +pub fn f80_floatFromInt_i64(a: i64) f80 { + return floatFromInt(f80, a); +} + +fn __floattixf(a: i128) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_i128(a)); +} +pub fn f80_floatFromInt_i128(a: i128) f80 { + return floatFromInt(f80, a); +} + +fn __floateixf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f80.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f80.toAbi(f80_floatFromInt_signed(a[0..byte_size])); +} +pub fn f80_floatFromInt_signed(a: []const u8) f80 { + return floatFromBigInt(f80, .signed, @ptrCast(@alignCast(a))); +} + +fn __floatsitf(a: i32) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_i32(a)); +} +fn _Qp_itoq(c: *f128, a: i32) callconv(.c) void { + c.* = f128_floatFromInt_i32(a); +} +pub fn f128_floatFromInt_i32(a: i32) f128 { + return floatFromInt(f128, a); +} + +fn __floatditf(a: i64) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_i64(a)); +} +fn _Qp_xtoq(c: *f128, a: i64) callconv(.c) void { + c.* = f128_floatFromInt_i64(a); +} +pub fn f128_floatFromInt_i64(a: i64) f128 { + return floatFromInt(f128, a); +} + +fn __floattitf(a: i128) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_i128(a)); +} +fn __floattitf_x86(a: f128) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_i128(@bitCast(a))); +} +pub fn f128_floatFromInt_i128(a: i128) f128 { + return floatFromInt(f128, a); +} + +fn __floateitf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f128.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f128.toAbi(f128_floatFromInt_signed(a[0..byte_size])); +} +pub fn f128_floatFromInt_signed(a: []const u8) f128 { + return floatFromBigInt(f128, .signed, @ptrCast(@alignCast(a))); +} + +comptime { + symbol(&__floatunsihf, "__floatunsihf"); + symbol(&__floatundihf, "__floatundihf"); + symbol(&__floatuntihf, "__floatuntihf"); + symbol(&__floatuneihf, "__floatuneihf"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_ui2f, "__aeabi_ui2f"); + symbol(&__aeabi_ul2f, "__aeabi_ul2f"); + } else { + symbol(&__floatunsisf, "__floatunsisf"); + symbol(&__floatundisf, "__floatundisf"); + if (compiler_rt.want_windows_arm_abi) symbol(&__floatundisf, "__u64tos"); + } + symbol(&__floatuntisf, "__floatuntisf"); + symbol(&__floatuneisf, "__floatuneisf"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_ui2d, "__aeabi_ui2d"); + } else { + symbol(&__floatunsidf, "__floatunsidf"); + } + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_ul2d, "__aeabi_ul2d"); + } else { + if (compiler_rt.want_windows_arm_abi) { + symbol(&__floatundidf, "__u64tod"); + } + symbol(&__floatundidf, "__floatundidf"); + } + symbol(&__floatuntidf, "__floatuntidf"); + symbol(&__floatuneidf, "__floatuneidf"); + + symbol(&__floatunsixf, "__floatunsixf"); + symbol(&__floatundixf, "__floatundixf"); + symbol(&__floatuntixf, "__floatuntixf"); + symbol(&__floatuneixf, "__floatuneixf"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__floatunsitf, "__floatunsikf"); + symbol(&__floatunditf, "__floatundikf"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_uitoq, "_Qp_uitoq"); + symbol(&_Qp_uxtoq, "_Qp_uxtoq"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__floatunsitf, "_Q_utoq"); + symbol(&__floatunditf, "_Q_ulltoq"); + } else { + symbol(&__floatunsitf, "__floatunsitf"); + symbol(&__floatunditf, "__floatunditf"); + } + if (compiler_rt.want_ppc_abi) { + symbol(&__floatuntitf, "__floatuntikf"); + symbol(&__floatuneitf, "__floatuneikf"); + } else { + if (builtin.cpu.arch == .x86) { + symbol(&__floatuntitf_x86, "__floatuntitf"); + } else if (builtin.cpu.arch == .x86_64 and + (builtin.os.tag == .windows or builtin.os.tag == .uefi)) + { + symbol(&__floatuntitf_x86_64_windows, "__floatuntitf"); + } else { + symbol(&__floatuntitf, "__floatuntitf"); + } + symbol(&__floatuneitf, "__floatuneitf"); + } +} + +fn __floatunsihf(a: u32) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_u32(a)); +} +pub fn f16_floatFromInt_u32(a: u32) f16 { + return floatFromInt(f16, a); +} + +fn __floatundihf(a: u64) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_u64(a)); +} +pub fn f16_floatFromInt_u64(a: u64) f16 { + return floatFromInt(f16, a); +} + +fn __floatuntihf(a: u128) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(f16_floatFromInt_u128(a)); +} +pub fn f16_floatFromInt_u128(a: u128) f16 { + return floatFromInt(f16, a); +} + +fn __floatuneihf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f16.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f16.toAbi(f16_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f16_floatFromInt_unsigned(a: []const u8) f16 { + return floatFromBigInt(f16, .unsigned, @ptrCast(@alignCast(a))); +} + +fn __floatunsisf(a: u32) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_u32(a)); +} +fn __aeabi_ui2f(a: u32) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatFromInt_u32(a); +} +pub fn f32_floatFromInt_u32(a: u32) f32 { + return floatFromInt(f32, a); +} + +fn __floatundisf(a: u64) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_u64(a)); +} +fn __aeabi_ul2f(a: u64) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatFromInt_u64(a); +} +pub fn f32_floatFromInt_u64(a: u64) f32 { + return floatFromInt(f32, a); +} + +fn __floatuntisf(a: u128) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatFromInt_u128(a)); +} +pub fn f32_floatFromInt_u128(a: u128) f32 { + return floatFromInt(f32, a); +} + +fn __floatuneisf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f32.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f32.toAbi(f32_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f32_floatFromInt_unsigned(a: []const u8) f32 { + return floatFromBigInt(f32, .unsigned, @ptrCast(@alignCast(a))); +} + +fn __floatunsidf(a: u32) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_u32(a)); +} +fn __aeabi_ui2d(a: u32) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatFromInt_u32(a); +} +pub fn f64_floatFromInt_u32(a: u32) f64 { + return floatFromInt(f64, a); +} + +fn __floatundidf(a: u64) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_u64(a)); +} +fn __aeabi_ul2d(a: u64) callconv(.{ .arm_aapcs = .{} }) f64 { + return f64_floatFromInt_u64(a); +} +pub fn f64_floatFromInt_u64(a: u64) f64 { + return floatFromInt(f64, a); +} + +fn __floatuntidf(a: u128) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatFromInt_u128(a)); +} +pub fn f64_floatFromInt_u128(a: u128) f64 { + return floatFromInt(f64, a); +} + +fn __floatuneidf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f64.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f64.toAbi(f64_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f64_floatFromInt_unsigned(a: []const u8) f64 { + return floatFromBigInt(f64, .unsigned, @ptrCast(@alignCast(a))); +} + +fn __floatunsixf(a: u32) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_u32(a)); +} +pub fn f80_floatFromInt_u32(a: u32) f80 { + return floatFromInt(f80, a); +} + +fn __floatundixf(a: u64) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_u64(a)); +} +pub fn f80_floatFromInt_u64(a: u64) f80 { + return floatFromInt(f80, a); +} + +fn __floatuntixf(a: u128) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatFromInt_u128(a)); +} +pub fn f80_floatFromInt_u128(a: u128) f80 { + return floatFromInt(f80, a); +} + +fn __floatuneixf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f80.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f80.toAbi(f80_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f80_floatFromInt_unsigned(a: []const u8) f80 { + return floatFromBigInt(f80, .unsigned, @ptrCast(@alignCast(a))); +} + +fn __floatunsitf(a: u32) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u32(a)); +} +fn _Qp_uitoq(c: *f128, a: u32) callconv(.c) void { + c.* = f128_floatFromInt_u32(a); +} +pub fn f128_floatFromInt_u32(a: u32) f128 { + return floatFromInt(f128, a); +} + +fn __floatunditf(a: u64) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u64(a)); +} +fn _Qp_uxtoq(c: *f128, a: u64) callconv(.c) void { + c.* = f128_floatFromInt_u64(a); +} +pub fn f128_floatFromInt_u64(a: u64) f128 { + return floatFromInt(f128, a); +} + +fn __floatuntitf(a: u128) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u128(a)); +} +fn __floatuntitf_x86(a: f128) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u128(@bitCast(a))); +} +fn __floatuntitf_x86_64_windows(a_lo: u64, a_hi: u64) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(f128_floatFromInt_u128(@bitCast( + packed struct { lo: u64, hi: u64 }{ .lo = a_lo, .hi = a_hi }, + ))); +} +pub fn f128_floatFromInt_u128(a: u128) f128 { + return floatFromInt(f128, a); +} + +fn __floatuneitf(a: [*]const u8, bits: usize) callconv(.c) compiler_rt.f128.Abi { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return compiler_rt.f128.toAbi(f128_floatFromInt_unsigned(a[0..byte_size])); +} +pub fn f128_floatFromInt_unsigned(a: []const u8) f128 { + return floatFromBigInt(f128, .unsigned, @ptrCast(@alignCast(a))); +} + +inline fn floatFromInt(comptime T: type, x: anytype) T { if (x == 0) return 0; // Various constants whose values follow from the type parameters. @@ -53,7 +521,7 @@ pub fn floatFromInt(comptime T: type, x: anytype) T { return @bitCast(sign_bit | result); } -const endian = @import("builtin").cpu.arch.endian(); +const endian = builtin.cpu.arch.endian(); inline fn limb(limbs: []const u32, index: usize) u32 { return switch (endian) { .little => limbs[index], @@ -61,11 +529,11 @@ inline fn limb(limbs: []const u32, index: usize) u32 { }; } -pub inline fn floatFromBigInt(comptime T: type, comptime signedness: std.builtin.Signedness, x: []const u32) T { +inline fn floatFromBigInt(comptime T: type, comptime signedness: std.lang.Signedness, x: []const u32) T { switch (x.len) { 0 => return 0, inline 1...4 => |limbs_len| { - const low_to_high: [limbs_len]u32 = switch (@import("builtin").cpu.arch.endian()) { + const low_to_high: [limbs_len]u32 = switch (endian) { .little => x[0..limbs_len].*, .big => switch (limbs_len) { 1 => .{x[0]}, diff --git a/lib/compiler_rt/float_from_int_test.zig b/lib/compiler_rt/float_from_int_test.zig index 8c908f420959b28fe107f290cb0bcb709c9ffd85..4ce3129f890f3f303d835733644afcf2fedbff4c 100644 --- a/lib/compiler_rt/float_from_int_test.zig +++ b/lib/compiler_rt/float_from_int_test.zig @@ -2,571 +2,593 @@ const std = @import("std"); const testing = std.testing; const math = std.math; -const __floatunsihf = @import("floatunsihf.zig").__floatunsihf; - -// Conversion to f32 -const __floatsisf = @import("floatsisf.zig").__floatsisf; -const __floatunsisf = @import("floatunsisf.zig").__floatunsisf; -const __floatdisf = @import("floatdisf.zig").__floatdisf; -const __floatundisf = @import("floatundisf.zig").__floatundisf; -const __floattisf = @import("floattisf.zig").__floattisf; -const __floatuntisf = @import("floatuntisf.zig").__floatuntisf; -const __floateisf = @import("floateisf.zig").__floateisf; -const __floatuneisf = @import("floatuneisf.zig").__floatuneisf; - -// Conversion to f64 -const __floatsidf = @import("floatsidf.zig").__floatsidf; -const __floatunsidf = @import("floatunsidf.zig").__floatunsidf; -const __floatdidf = @import("floatdidf.zig").__floatdidf; -const __floatundidf = @import("floatundidf.zig").__floatundidf; -const __floattidf = @import("floattidf.zig").__floattidf; -const __floatuntidf = @import("floatuntidf.zig").__floatuntidf; - -// Conversion to f128 -const __floatsitf = @import("floatsitf.zig").__floatsitf; -const __floatunsitf = @import("floatunsitf.zig").__floatunsitf; -const __floatditf = @import("floatditf.zig").__floatditf; -const __floatunditf = @import("floatunditf.zig").__floatunditf; -const __floattitf = @import("floattitf.zig").__floattitf; -const __floatuntitf = @import("floatuntitf.zig").__floatuntitf; - -fn test__floatsisf(a: i32, expected: u32) !void { - const r = __floatsisf(a); +const impl = @import("float_from_int.zig"); + +const f16_floatFromInt_i32 = impl.f16_floatFromInt_i32; +const f16_floatFromInt_u32 = impl.f16_floatFromInt_u32; +const f16_floatFromInt_i64 = impl.f16_floatFromInt_i64; +const f16_floatFromInt_u64 = impl.f16_floatFromInt_u64; +const f16_floatFromInt_i128 = impl.f16_floatFromInt_i128; +const f16_floatFromInt_u128 = impl.f16_floatFromInt_u128; +const f16_floatFromInt_signed = impl.f16_floatFromInt_signed; +const f16_floatFromInt_unsigned = impl.f16_floatFromInt_unsigned; + +const f32_floatFromInt_i32 = impl.f32_floatFromInt_i32; +const f32_floatFromInt_u32 = impl.f32_floatFromInt_u32; +const f32_floatFromInt_i64 = impl.f32_floatFromInt_i64; +const f32_floatFromInt_u64 = impl.f32_floatFromInt_u64; +const f32_floatFromInt_i128 = impl.f32_floatFromInt_i128; +const f32_floatFromInt_u128 = impl.f32_floatFromInt_u128; +const f32_floatFromInt_signed = impl.f32_floatFromInt_signed; +const f32_floatFromInt_unsigned = impl.f32_floatFromInt_unsigned; + +const f64_floatFromInt_i32 = impl.f64_floatFromInt_i32; +const f64_floatFromInt_u32 = impl.f64_floatFromInt_u32; +const f64_floatFromInt_i64 = impl.f64_floatFromInt_i64; +const f64_floatFromInt_u64 = impl.f64_floatFromInt_u64; +const f64_floatFromInt_i128 = impl.f64_floatFromInt_i128; +const f64_floatFromInt_u128 = impl.f64_floatFromInt_u128; +const f64_floatFromInt_signed = impl.f64_floatFromInt_signed; +const f64_floatFromInt_unsigned = impl.f64_floatFromInt_unsigned; + +const f80_floatFromInt_i32 = impl.f80_floatFromInt_i32; +const f80_floatFromInt_u32 = impl.f80_floatFromInt_u32; +const f80_floatFromInt_i64 = impl.f80_floatFromInt_i64; +const f80_floatFromInt_u64 = impl.f80_floatFromInt_u64; +const f80_floatFromInt_i128 = impl.f80_floatFromInt_i128; +const f80_floatFromInt_u128 = impl.f80_floatFromInt_u128; +const f80_floatFromInt_signed = impl.f80_floatFromInt_signed; +const f80_floatFromInt_unsigned = impl.f80_floatFromInt_unsigned; + +const f128_floatFromInt_i32 = impl.f128_floatFromInt_i32; +const f128_floatFromInt_u32 = impl.f128_floatFromInt_u32; +const f128_floatFromInt_i64 = impl.f128_floatFromInt_i64; +const f128_floatFromInt_u64 = impl.f128_floatFromInt_u64; +const f128_floatFromInt_i128 = impl.f128_floatFromInt_i128; +const f128_floatFromInt_u128 = impl.f128_floatFromInt_u128; +const f128_floatFromInt_signed = impl.f128_floatFromInt_signed; +const f128_floatFromInt_unsigned = impl.f128_floatFromInt_unsigned; + +fn test_f32_floatFromInt_i32(a: i32, expected: u32) !void { + const r = f32_floatFromInt_i32(a); try std.testing.expect(@as(u32, @bitCast(r)) == expected); } -fn test_one_floatunsisf(a: u32, expected: u32) !void { - const r = __floatunsisf(a); +fn test_f32_floatFromInt_u32(a: u32, expected: u32) !void { + const r = f32_floatFromInt_u32(a); try std.testing.expect(@as(u32, @bitCast(r)) == expected); } -test "floatsisf" { - try test__floatsisf(0, 0x00000000); - try test__floatsisf(1, 0x3f800000); - try test__floatsisf(-1, 0xbf800000); - try test__floatsisf(0x7FFFFFFF, 0x4f000000); - try test__floatsisf(@bitCast(@as(u32, @intCast(0x80000000))), 0xcf000000); +test f32_floatFromInt_i32 { + try test_f32_floatFromInt_i32(0, 0x00000000); + try test_f32_floatFromInt_i32(1, 0x3f800000); + try test_f32_floatFromInt_i32(-1, 0xbf800000); + try test_f32_floatFromInt_i32(0x7FFFFFFF, 0x4f000000); + try test_f32_floatFromInt_i32(@bitCast(@as(u32, @intCast(0x80000000))), 0xcf000000); + + try testing.expect(f32_floatFromInt_i32(math.minInt(i32)) == math.minInt(i32)); } -test "floatunsisf" { +test f32_floatFromInt_u32 { // Test the produced bit pattern - try test_one_floatunsisf(0, 0); - try test_one_floatunsisf(1, 0x3f800000); - try test_one_floatunsisf(0x7FFFFFFF, 0x4f000000); - try test_one_floatunsisf(0x80000000, 0x4f000000); - try test_one_floatunsisf(0xFFFFFFFF, 0x4f800000); + try test_f32_floatFromInt_u32(0, 0); + try test_f32_floatFromInt_u32(1, 0x3f800000); + try test_f32_floatFromInt_u32(0x7FFFFFFF, 0x4f000000); + try test_f32_floatFromInt_u32(0x80000000, 0x4f000000); + try test_f32_floatFromInt_u32(0xFFFFFFFF, 0x4f800000); + + try testing.expect(f32_floatFromInt_u32(0) == 0.0); + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24)) == math.maxInt(u24)); + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 1) == math.maxInt(u24) + 1); // 0x100_0000 - Exact + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 2) == math.maxInt(u24) + 1); // 0x100_0001 - Tie: Rounds down to even + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 3) == math.maxInt(u24) + 3); // 0x100_0002 - Exact + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 4) == math.maxInt(u24) + 5); // 0x100_0003 - Tie: Rounds up to even + try testing.expect(f32_floatFromInt_u32(math.maxInt(u24) + 5) == math.maxInt(u24) + 5); // 0x100_0004 - Exact + try testing.expect(f32_floatFromInt_u32(math.maxInt(u32)) == math.maxInt(u32) + 1); } -fn test__floatdisf(a: i64, expected: f32) !void { - const x = __floatdisf(a); +fn test_f32_floatFromInt_i64(a: i64, expected: f32) !void { + const x = f32_floatFromInt_i64(a); try testing.expect(x == expected); } -fn test__floatundisf(a: u64, expected: f32) !void { - try std.testing.expectEqual(expected, __floatundisf(a)); +fn test_f32_floatFromInt_u64(a: u64, expected: f32) !void { + const x = f32_floatFromInt_u64(a); + try testing.expect(x == expected); } -test "floatdisf" { - try test__floatdisf(0, 0.0); - try test__floatdisf(1, 1.0); - try test__floatdisf(2, 2.0); - try test__floatdisf(-1, -1.0); - try test__floatdisf(-2, -2.0); - try test__floatdisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatdisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatdisf(@bitCast(@as(u64, 0x8000008000000000)), -0x1.FFFFFEp+62); - try test__floatdisf(@bitCast(@as(u64, 0x8000010000000000)), -0x1.FFFFFCp+62); - try test__floatdisf(@bitCast(@as(u64, 0x8000000000000000)), -0x1.000000p+63); - try test__floatdisf(@bitCast(@as(u64, 0x8000000000000001)), -0x1.000000p+63); - try test__floatdisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floatdisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floatdisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); +test f32_floatFromInt_i64 { + try test_f32_floatFromInt_i64(0, 0.0); + try test_f32_floatFromInt_i64(1, 1.0); + try test_f32_floatFromInt_i64(2, 2.0); + try test_f32_floatFromInt_i64(-1, -1.0); + try test_f32_floatFromInt_i64(-2, -2.0); + try test_f32_floatFromInt_i64(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f32_floatFromInt_i64(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f32_floatFromInt_i64(@bitCast(@as(u64, 0x8000008000000000)), -0x1.FFFFFEp+62); + try test_f32_floatFromInt_i64(@bitCast(@as(u64, 0x8000010000000000)), -0x1.FFFFFCp+62); + try test_f32_floatFromInt_i64(@bitCast(@as(u64, 0x8000000000000000)), -0x1.000000p+63); + try test_f32_floatFromInt_i64(@bitCast(@as(u64, 0x8000000000000001)), -0x1.000000p+63); + try test_f32_floatFromInt_i64(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test_f32_floatFromInt_i64(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i64(0x0007FB72E4000000, 0x1.FEDCB8p+50); } -test "floatundisf" { - try test__floatundisf(0, 0.0); - try test__floatundisf(1, 1.0); - try test__floatundisf(2, 2.0); - try test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatundisf(0x8000008000000000, 0x1p+63); - try test__floatundisf(0x8000010000000000, 0x1.000002p+63); - try test__floatundisf(0x8000000000000000, 0x1p+63); - try test__floatundisf(0x8000000000000001, 0x1p+63); - try test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); - try test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); - try test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); +test f32_floatFromInt_u64 { + try test_f32_floatFromInt_u64(0, 0.0); + try test_f32_floatFromInt_u64(1, 1.0); + try test_f32_floatFromInt_u64(2, 2.0); + try test_f32_floatFromInt_u64(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f32_floatFromInt_u64(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f32_floatFromInt_u64(0x8000008000000000, 0x1p+63); + try test_f32_floatFromInt_u64(0x8000010000000000, 0x1.000002p+63); + try test_f32_floatFromInt_u64(0x8000000000000000, 0x1p+63); + try test_f32_floatFromInt_u64(0x8000000000000001, 0x1p+63); + try test_f32_floatFromInt_u64(0xFFFFFFFFFFFFFFFE, 0x1p+64); + try test_f32_floatFromInt_u64(0xFFFFFFFFFFFFFFFF, 0x1p+64); + try test_f32_floatFromInt_u64(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test_f32_floatFromInt_u64(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u64(0x0007FB72E4000000, 0x1.FEDCB8p+50); } -fn test__floattisf(a: i128, expected: f32) !void { - const x = __floattisf(a); +fn test_f32_floatFromInt_i128(a: i128, expected: f32) !void { + const x = f32_floatFromInt_i128(a); try testing.expect(x == expected); } -fn test__floatuntisf(a: u128, expected: f32) !void { - const x = __floatuntisf(a); +fn test_f32_floatFromInt_u128(a: u128, expected: f32) !void { + const x = f32_floatFromInt_u128(a); try testing.expect(x == expected); } -test "floattisf" { - try test__floattisf(0, 0.0); +test f32_floatFromInt_i128 { + try test_f32_floatFromInt_i128(0, 0.0); - try test__floattisf(1, 1.0); - try test__floattisf(2, 2.0); - try test__floattisf(-1, -1.0); - try test__floattisf(-2, -2.0); + try test_f32_floatFromInt_i128(1, 1.0); + try test_f32_floatFromInt_i128(2, 2.0); + try test_f32_floatFromInt_i128(-1, -1.0); + try test_f32_floatFromInt_i128(-2, -2.0); - try test__floattisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floattisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f32_floatFromInt_i128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f32_floatFromInt_i128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62); + try test_f32_floatFromInt_i128(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62); + try test_f32_floatFromInt_i128(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63); - try test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63); + try test_f32_floatFromInt_i128(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63); + try test_f32_floatFromInt_i128(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63); - try test__floattisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floattisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test_f32_floatFromInt_i128(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floattisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); + try test_f32_floatFromInt_i128(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_i128(0x0007FB72E4000000, 0x1.FEDCB8p+50); - try test__floattisf(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114); - try test__floattisf(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114); - try test__floattisf(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114); + try test_f32_floatFromInt_i128(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114); } -test "floatuntisf" { - try test__floatuntisf(0, 0.0); +test f32_floatFromInt_u128 { + try test_f32_floatFromInt_u128(0, 0.0); - try test__floatuntisf(1, 1.0); - try test__floatuntisf(2, 2.0); - try test__floatuntisf(20, 20.0); + try test_f32_floatFromInt_u128(1, 1.0); + try test_f32_floatFromInt_u128(2, 2.0); + try test_f32_floatFromInt_u128(20, 20.0); - try test__floatuntisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatuntisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f32_floatFromInt_u128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f32_floatFromInt_u128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatuntisf(make_uti(0x8000008000000000, 0), 0x1.000001p+127); - try test__floatuntisf(make_uti(0x8000000000000800, 0), 0x1.0p+127); - try test__floatuntisf(make_uti(0x8000010000000000, 0), 0x1.000002p+127); + try test_f32_floatFromInt_u128(make_uti(0x8000008000000000, 0), 0x1.000001p+127); + try test_f32_floatFromInt_u128(make_uti(0x8000000000000800, 0), 0x1.0p+127); + try test_f32_floatFromInt_u128(make_uti(0x8000010000000000, 0), 0x1.000002p+127); - try test__floatuntisf(make_uti(0x8000000000000000, 0), 0x1.000000p+127); + try test_f32_floatFromInt_u128(make_uti(0x8000000000000000, 0), 0x1.000000p+127); - try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f32_floatFromInt_u128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f32_floatFromInt_u128(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f32_floatFromInt_u128(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB9p+50); + try test_f32_floatFromInt_u128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f32_floatFromInt_u128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f32_floatFromInt_u128(0x0007FB72E4000000, 0x1.FEDCB9p+50); - try test__floatuntisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); - try test__floatuntisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); + try test_f32_floatFromInt_u128(0xFFFFFFFFFFFFFFFE, 0x1p+64); + try test_f32_floatFromInt_u128(0xFFFFFFFFFFFFFFFF, 0x1p+64); - try test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); - try test__floatuntisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72EA000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72EB000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72EC000000, 0x1.FEDCBCp+50); + try test_f32_floatFromInt_u128(0x0007FB72E8000001, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); - try test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); + try test_f32_floatFromInt_u128(0x0007FB72E6000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E7000000, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E4000001, 0x1.FEDCBAp+50); + try test_f32_floatFromInt_u128(0x0007FB72E4000000, 0x1.FEDCB8p+50); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76); - try test__floatuntisf(make_uti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76); + try test_f32_floatFromInt_u128(make_uti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76); // Test overflow to infinity - try test__floatuntisf(math.maxInt(u128), @bitCast(math.inf(f32))); + try test_f32_floatFromInt_u128(math.maxInt(u128), @bitCast(math.inf(f32))); } -fn test_floateisf(expected: u32, comptime T: type, a: T) !void { +fn test_f32_floatFromInt(expected: u32, comptime T: type, a: T) !void { const int = @typeInfo(T).int; const r = switch (int.signedness) { - .signed => __floateisf, - .unsigned => __floatuneisf, - }(@ptrCast(&a), int.bits); + .signed => f32_floatFromInt_signed, + .unsigned => f32_floatFromInt_unsigned, + }(@ptrCast(&a)); try testing.expect(expected == @as(u32, @bitCast(r))); } -test "floateisf" { - try test_floateisf(0xFF000000, i256, -1 << 127); - try test_floateisf(0xFF000000, i256, -math.maxInt(u127)); - try test_floateisf(0xDF012347, i256, -0x8123468100000000); - try test_floateisf(0xDF012347, i256, -0x8123468000000001); - try test_floateisf(0xDF012346, i256, -0x8123468000000000); - try test_floateisf(0xDF012346, i256, -0x8123458100000000); - try test_floateisf(0xDF012346, i256, -0x8123458000000001); - try test_floateisf(0xDF012346, i256, -0x8123458000000000); - try test_floateisf(0xDF012345, i256, -0x8123456789ABCDEF); - try test_floateisf(0xBF800000, i256, -1); - try test_floateisf(0x00000000, i256, 0); - try test_floateisf(0x5F012345, i256, 0x8123456789ABCDEF); - try test_floateisf(0x5F012346, i256, 0x8123458000000000); - try test_floateisf(0x5F012346, i256, 0x8123458000000001); - try test_floateisf(0x5F012346, i256, 0x8123458100000000); - try test_floateisf(0x5F012346, i256, 0x8123468000000000); - try test_floateisf(0x5F012347, i256, 0x8123468000000001); - try test_floateisf(0x5F012347, i256, 0x8123468100000000); - try test_floateisf(0x7F000000, i256, math.maxInt(u127)); - try test_floateisf(0x7F000000, i256, 1 << 127); +test f32_floatFromInt_signed { + try test_f32_floatFromInt(0xFF000000, i256, -1 << 127); + try test_f32_floatFromInt(0xFF000000, i256, -math.maxInt(u127)); + try test_f32_floatFromInt(0xDF012347, i256, -0x8123468100000000); + try test_f32_floatFromInt(0xDF012347, i256, -0x8123468000000001); + try test_f32_floatFromInt(0xDF012346, i256, -0x8123468000000000); + try test_f32_floatFromInt(0xDF012346, i256, -0x8123458100000000); + try test_f32_floatFromInt(0xDF012346, i256, -0x8123458000000001); + try test_f32_floatFromInt(0xDF012346, i256, -0x8123458000000000); + try test_f32_floatFromInt(0xDF012345, i256, -0x8123456789ABCDEF); + try test_f32_floatFromInt(0xBF800000, i256, -1); + try test_f32_floatFromInt(0x00000000, i256, 0); + try test_f32_floatFromInt(0x5F012345, i256, 0x8123456789ABCDEF); + try test_f32_floatFromInt(0x5F012346, i256, 0x8123458000000000); + try test_f32_floatFromInt(0x5F012346, i256, 0x8123458000000001); + try test_f32_floatFromInt(0x5F012346, i256, 0x8123458100000000); + try test_f32_floatFromInt(0x5F012346, i256, 0x8123468000000000); + try test_f32_floatFromInt(0x5F012347, i256, 0x8123468000000001); + try test_f32_floatFromInt(0x5F012347, i256, 0x8123468100000000); + try test_f32_floatFromInt(0x7F000000, i256, math.maxInt(u127)); + try test_f32_floatFromInt(0x7F000000, i256, 1 << 127); } -test "floatuneisf" { - try test_floateisf(0x00000000, u256, 0); - try test_floateisf(0x5F012345, u256, 0x8123456789ABCDEF); - try test_floateisf(0x5F012346, u256, 0x8123458000000000); - try test_floateisf(0x5F012346, u256, 0x8123458000000001); - try test_floateisf(0x5F012346, u256, 0x8123458080000000); - try test_floateisf(0x5F012346, u256, 0x8123468000000000); - try test_floateisf(0x5F012347, u256, 0x8123468000000001); - try test_floateisf(0x5F012347, u256, 0x8123468080000000); - try test_floateisf(0x7F000000, u256, math.maxInt(u127)); - try test_floateisf(0x7F000000, u256, 1 << 127); - try test_floateisf(0x7F800000, u256, math.maxInt(u256)); +test f32_floatFromInt_unsigned { + try test_f32_floatFromInt(0x00000000, u256, 0); + try test_f32_floatFromInt(0x5F012345, u256, 0x8123456789ABCDEF); + try test_f32_floatFromInt(0x5F012346, u256, 0x8123458000000000); + try test_f32_floatFromInt(0x5F012346, u256, 0x8123458000000001); + try test_f32_floatFromInt(0x5F012346, u256, 0x8123458080000000); + try test_f32_floatFromInt(0x5F012346, u256, 0x8123468000000000); + try test_f32_floatFromInt(0x5F012347, u256, 0x8123468000000001); + try test_f32_floatFromInt(0x5F012347, u256, 0x8123468080000000); + try test_f32_floatFromInt(0x7F000000, u256, math.maxInt(u127)); + try test_f32_floatFromInt(0x7F000000, u256, 1 << 127); + try test_f32_floatFromInt(0x7F800000, u256, math.maxInt(u256)); } -fn test_one_floatsidf(a: i32, expected: u64) !void { - const r = __floatsidf(a); +fn test_f64_floatFromInt_i32(a: i32, expected: u64) !void { + const r = f64_floatFromInt_i32(a); try std.testing.expect(@as(u64, @bitCast(r)) == expected); } -fn test_one_floatunsidf(a: u32, expected: u64) !void { - const r = __floatunsidf(a); +fn test_f64_floatFromInt_u32(a: u32, expected: u64) !void { + const r = f64_floatFromInt_u32(a); try std.testing.expect(@as(u64, @bitCast(r)) == expected); } -test "floatsidf" { - try test_one_floatsidf(0, 0x0000000000000000); - try test_one_floatsidf(1, 0x3ff0000000000000); - try test_one_floatsidf(-1, 0xbff0000000000000); - try test_one_floatsidf(0x7FFFFFFF, 0x41dfffffffc00000); - try test_one_floatsidf(@bitCast(@as(u32, @intCast(0x80000000))), 0xc1e0000000000000); +test f64_floatFromInt_i32 { + try test_f64_floatFromInt_i32(0, 0x0000000000000000); + try test_f64_floatFromInt_i32(1, 0x3ff0000000000000); + try test_f64_floatFromInt_i32(-1, 0xbff0000000000000); + try test_f64_floatFromInt_i32(0x7FFFFFFF, 0x41dfffffffc00000); + try test_f64_floatFromInt_i32(@bitCast(@as(u32, @intCast(0x80000000))), 0xc1e0000000000000); } -test "floatunsidf" { - try test_one_floatunsidf(0, 0x0000000000000000); - try test_one_floatunsidf(1, 0x3ff0000000000000); - try test_one_floatunsidf(0x7FFFFFFF, 0x41dfffffffc00000); - try test_one_floatunsidf(@intCast(0x80000000), 0x41e0000000000000); - try test_one_floatunsidf(@intCast(0xFFFFFFFF), 0x41efffffffe00000); +test f64_floatFromInt_u32 { + try test_f64_floatFromInt_u32(0, 0x0000000000000000); + try test_f64_floatFromInt_u32(1, 0x3ff0000000000000); + try test_f64_floatFromInt_u32(0x7FFFFFFF, 0x41dfffffffc00000); + try test_f64_floatFromInt_u32(@intCast(0x80000000), 0x41e0000000000000); + try test_f64_floatFromInt_u32(@intCast(0xFFFFFFFF), 0x41efffffffe00000); } -fn test__floatdidf(a: i64, expected: f64) !void { - const r = __floatdidf(a); +fn test_f64_floatFromInt_i64(a: i64, expected: f64) !void { + const r = f64_floatFromInt_i64(a); try testing.expect(r == expected); } -fn test__floatundidf(a: u64, expected: f64) !void { - const r = __floatundidf(a); +fn test_f64_floatFromInt_u64(a: u64, expected: f64) !void { + const r = f64_floatFromInt_u64(a); try testing.expect(r == expected); } -test "floatdidf" { - try test__floatdidf(0, 0.0); - try test__floatdidf(1, 1.0); - try test__floatdidf(2, 2.0); - try test__floatdidf(20, 20.0); - try test__floatdidf(-1, -1.0); - try test__floatdidf(-2, -2.0); - try test__floatdidf(-20, -20.0); - try test__floatdidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatdidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatdidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatdidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000008000000000))), -0x1.FFFFFEp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000000000000800))), -0x1.FFFFFFFFFFFFEp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000010000000000))), -0x1.FFFFFCp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000000000001000))), -0x1.FFFFFFFFFFFFCp+62); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000000000000000))), -0x1.000000p+63); - try test__floatdidf(@bitCast(@as(u64, @intCast(0x8000000000000001))), -0x1.000000p+63); // 0x8000000000000001 - try test__floatdidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatdidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatdidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatdidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatdidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatdidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - try test__floatdidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatdidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatdidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatdidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatdidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - try test__floatdidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floatdidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floatdidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floatdidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floatdidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floatdidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); +test f64_floatFromInt_i64 { + try test_f64_floatFromInt_i64(0, 0.0); + try test_f64_floatFromInt_i64(1, 1.0); + try test_f64_floatFromInt_i64(2, 2.0); + try test_f64_floatFromInt_i64(20, 20.0); + try test_f64_floatFromInt_i64(-1, -1.0); + try test_f64_floatFromInt_i64(-2, -2.0); + try test_f64_floatFromInt_i64(-20, -20.0); + try test_f64_floatFromInt_i64(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f64_floatFromInt_i64(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_i64(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f64_floatFromInt_i64(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000008000000000))), -0x1.FFFFFEp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000000000000800))), -0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000010000000000))), -0x1.FFFFFCp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000000000001000))), -0x1.FFFFFFFFFFFFCp+62); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000000000000000))), -0x1.000000p+63); + try test_f64_floatFromInt_i64(@bitCast(@as(u64, @intCast(0x8000000000000001))), -0x1.000000p+63); // 0x8000000000000001 + try test_f64_floatFromInt_i64(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f64_floatFromInt_i64(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f64_floatFromInt_i64(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f64_floatFromInt_i64(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f64_floatFromInt_i64(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f64_floatFromInt_i64(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + try test_f64_floatFromInt_i64(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f64_floatFromInt_i64(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f64_floatFromInt_i64(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f64_floatFromInt_i64(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f64_floatFromInt_i64(0x0007FB72E4000000, 0x1.FEDCB9p+50); + try test_f64_floatFromInt_i64(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i64(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); } -test "floatundidf" { - try test__floatundidf(0, 0.0); - try test__floatundidf(1, 1.0); - try test__floatundidf(2, 2.0); - try test__floatundidf(20, 20.0); - try test__floatundidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatundidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatundidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatundidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - try test__floatundidf(0x8000008000000000, 0x1.000001p+63); - try test__floatundidf(0x8000000000000800, 0x1.0000000000001p+63); - try test__floatundidf(0x8000010000000000, 0x1.000002p+63); - try test__floatundidf(0x8000000000001000, 0x1.0000000000002p+63); - try test__floatundidf(0x8000000000000000, 0x1p+63); - try test__floatundidf(0x8000000000000001, 0x1p+63); - try test__floatundidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - try test__floatundidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatundidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatundidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatundidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatundidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - try test__floatundidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatundidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatundidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatundidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatundidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - try test__floatundidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floatundidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floatundidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floatundidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floatundidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floatundidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); +test f64_floatFromInt_u64 { + try test_f64_floatFromInt_u64(0, 0.0); + try test_f64_floatFromInt_u64(1, 1.0); + try test_f64_floatFromInt_u64(2, 2.0); + try test_f64_floatFromInt_u64(20, 20.0); + try test_f64_floatFromInt_u64(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f64_floatFromInt_u64(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_u64(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f64_floatFromInt_u64(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + try test_f64_floatFromInt_u64(0x8000008000000000, 0x1.000001p+63); + try test_f64_floatFromInt_u64(0x8000000000000800, 0x1.0000000000001p+63); + try test_f64_floatFromInt_u64(0x8000010000000000, 0x1.000002p+63); + try test_f64_floatFromInt_u64(0x8000000000001000, 0x1.0000000000002p+63); + try test_f64_floatFromInt_u64(0x8000000000000000, 0x1p+63); + try test_f64_floatFromInt_u64(0x8000000000000001, 0x1p+63); + try test_f64_floatFromInt_u64(0x0007FB72E8000000, 0x1.FEDCBAp+50); + try test_f64_floatFromInt_u64(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f64_floatFromInt_u64(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f64_floatFromInt_u64(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f64_floatFromInt_u64(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f64_floatFromInt_u64(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + try test_f64_floatFromInt_u64(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f64_floatFromInt_u64(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f64_floatFromInt_u64(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f64_floatFromInt_u64(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f64_floatFromInt_u64(0x0007FB72E4000000, 0x1.FEDCB9p+50); + try test_f64_floatFromInt_u64(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u64(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); } -fn test__floattidf(a: i128, expected: f64) !void { - const x = __floattidf(a); +fn test_f64_floatFromInt_i128(a: i128, expected: f64) !void { + const x = f64_floatFromInt_i128(a); try testing.expect(x == expected); } -fn test__floatuntidf(a: u128, expected: f64) !void { - const x = __floatuntidf(a); +fn test_f64_floatFromInt_u128(a: u128, expected: f64) !void { + const x = f64_floatFromInt_u128(a); try testing.expect(x == expected); } -test "floattidf" { - try test__floattidf(0, 0.0); - - try test__floattidf(1, 1.0); - try test__floattidf(2, 2.0); - try test__floattidf(20, 20.0); - try test__floattidf(-1, -1.0); - try test__floattidf(-2, -2.0); - try test__floattidf(-20, -20.0); - - try test__floattidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floattidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floattidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floattidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - - try test__floattidf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); - try test__floattidf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); - try test__floattidf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); - try test__floattidf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); - - try test__floattidf(make_ti(0x8000000000000000, 0), -0x1.000000p+127); - try test__floattidf(make_ti(0x8000000000000001, 0), -0x1.000000p+127); - - try test__floattidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floattidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floattidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floattidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floattidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floattidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floattidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floattidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floattidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floattidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floattidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floattidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floattidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floattidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floattidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floattidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floattidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floattidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); - try test__floattidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); - try test__floattidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); - try test__floattidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); - try test__floattidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); - try test__floattidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); +test f64_floatFromInt_i128 { + try test_f64_floatFromInt_i128(0, 0.0); + + try test_f64_floatFromInt_i128(1, 1.0); + try test_f64_floatFromInt_i128(2, 2.0); + try test_f64_floatFromInt_i128(20, 20.0); + try test_f64_floatFromInt_i128(-1, -1.0); + try test_f64_floatFromInt_i128(-2, -2.0); + try test_f64_floatFromInt_i128(-20, -20.0); + + try test_f64_floatFromInt_i128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f64_floatFromInt_i128(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_i128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f64_floatFromInt_i128(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + + try test_f64_floatFromInt_i128(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); + try test_f64_floatFromInt_i128(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); + try test_f64_floatFromInt_i128(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); + try test_f64_floatFromInt_i128(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); + + try test_f64_floatFromInt_i128(make_ti(0x8000000000000000, 0), -0x1.000000p+127); + try test_f64_floatFromInt_i128(make_ti(0x8000000000000001, 0), -0x1.000000p+127); + + try test_f64_floatFromInt_i128(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test_f64_floatFromInt_i128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f64_floatFromInt_i128(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f64_floatFromInt_i128(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f64_floatFromInt_i128(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f64_floatFromInt_i128(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test_f64_floatFromInt_i128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f64_floatFromInt_i128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f64_floatFromInt_i128(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f64_floatFromInt_i128(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f64_floatFromInt_i128(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test_f64_floatFromInt_i128(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_i128(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_i128(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); } -test "floatuntidf" { - try test__floatuntidf(0, 0.0); - - try test__floatuntidf(1, 1.0); - try test__floatuntidf(2, 2.0); - try test__floatuntidf(20, 20.0); - - try test__floatuntidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatuntidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatuntidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatuntidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - - try test__floatuntidf(make_uti(0x8000008000000000, 0), 0x1.000001p+127); - try test__floatuntidf(make_uti(0x8000000000000800, 0), 0x1.0000000000001p+127); - try test__floatuntidf(make_uti(0x8000010000000000, 0), 0x1.000002p+127); - try test__floatuntidf(make_uti(0x8000000000001000, 0), 0x1.0000000000002p+127); - - try test__floatuntidf(make_uti(0x8000000000000000, 0), 0x1.000000p+127); - try test__floatuntidf(make_uti(0x8000000000000001, 0), 0x1.0000000000000002p+127); - - try test__floatuntidf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floatuntidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatuntidf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatuntidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatuntidf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatuntidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floatuntidf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatuntidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatuntidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatuntidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatuntidf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floatuntidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); - try test__floatuntidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); - try test__floatuntidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); - try test__floatuntidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); - try test__floatuntidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); - try test__floatuntidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floatuntidf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); - try test__floatuntidf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); - try test__floatuntidf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); +test f64_floatFromInt_u128 { + try test_f64_floatFromInt_u128(0, 0.0); + + try test_f64_floatFromInt_u128(1, 1.0); + try test_f64_floatFromInt_u128(2, 2.0); + try test_f64_floatFromInt_u128(20, 20.0); + + try test_f64_floatFromInt_u128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f64_floatFromInt_u128(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f64_floatFromInt_u128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f64_floatFromInt_u128(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + + try test_f64_floatFromInt_u128(make_uti(0x8000008000000000, 0), 0x1.000001p+127); + try test_f64_floatFromInt_u128(make_uti(0x8000000000000800, 0), 0x1.0000000000001p+127); + try test_f64_floatFromInt_u128(make_uti(0x8000010000000000, 0), 0x1.000002p+127); + try test_f64_floatFromInt_u128(make_uti(0x8000000000001000, 0), 0x1.0000000000002p+127); + + try test_f64_floatFromInt_u128(make_uti(0x8000000000000000, 0), 0x1.000000p+127); + try test_f64_floatFromInt_u128(make_uti(0x8000000000000001, 0), 0x1.0000000000000002p+127); + + try test_f64_floatFromInt_u128(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test_f64_floatFromInt_u128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f64_floatFromInt_u128(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f64_floatFromInt_u128(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f64_floatFromInt_u128(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f64_floatFromInt_u128(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test_f64_floatFromInt_u128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f64_floatFromInt_u128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f64_floatFromInt_u128(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f64_floatFromInt_u128(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f64_floatFromInt_u128(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test_f64_floatFromInt_u128(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57); + try test_f64_floatFromInt_u128(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121); + try test_f64_floatFromInt_u128(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); } -fn test__floatsitf(a: i32, expected: u128) !void { - const r = __floatsitf(a); +fn test_f128_floatFromInt_i32(a: i32, expected: u128) !void { + const r = f128_floatFromInt_i32(a); try std.testing.expect(@as(u128, @bitCast(r)) == expected); } -test "floatsitf" { - try test__floatsitf(0, 0); - try test__floatsitf(0x7FFFFFFF, 0x401dfffffffc00000000000000000000); - try test__floatsitf(0x12345678, 0x401b2345678000000000000000000000); - try test__floatsitf(-0x12345678, 0xc01b2345678000000000000000000000); - try test__floatsitf(@bitCast(@as(u32, @intCast(0xffffffff))), 0xbfff0000000000000000000000000000); - try test__floatsitf(@bitCast(@as(u32, @intCast(0x80000000))), 0xc01e0000000000000000000000000000); -} - -fn test__floatunsitf(a: u32, expected_hi: u64, expected_lo: u64) !void { - const x = __floatunsitf(a); +fn test_f128_floatFromInt_u32(a: u32, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatFromInt_u32(a); const x_repr: u128 = @bitCast(x); const x_hi: u64 = @intCast(x_repr >> 64); @@ -581,24 +603,32 @@ fn test__floatunsitf(a: u32, expected_hi: u64, expected_lo: u64) !void { return; } } + return error.TestFailure; +} - @panic("__floatunsitf test failure"); +test f128_floatFromInt_i32 { + try test_f128_floatFromInt_i32(0, 0); + try test_f128_floatFromInt_i32(0x7FFFFFFF, 0x401dfffffffc00000000000000000000); + try test_f128_floatFromInt_i32(0x12345678, 0x401b2345678000000000000000000000); + try test_f128_floatFromInt_i32(-0x12345678, 0xc01b2345678000000000000000000000); + try test_f128_floatFromInt_i32(@bitCast(@as(u32, @intCast(0xffffffff))), 0xbfff0000000000000000000000000000); + try test_f128_floatFromInt_i32(@bitCast(@as(u32, @intCast(0x80000000))), 0xc01e0000000000000000000000000000); } -test "floatunsitf" { - try test__floatunsitf(0x7fffffff, 0x401dfffffffc0000, 0x0); - try test__floatunsitf(0, 0x0, 0x0); - try test__floatunsitf(0xffffffff, 0x401efffffffe0000, 0x0); - try test__floatunsitf(0x12345678, 0x401b234567800000, 0x0); +test f128_floatFromInt_u32 { + try test_f128_floatFromInt_u32(0x7fffffff, 0x401dfffffffc0000, 0x0); + try test_f128_floatFromInt_u32(0, 0x0, 0x0); + try test_f128_floatFromInt_u32(0xffffffff, 0x401efffffffe0000, 0x0); + try test_f128_floatFromInt_u32(0x12345678, 0x401b234567800000, 0x0); } -fn test__floatditf(a: i64, expected: f128) !void { - const x = __floatditf(a); +fn test_f128_floatFromInt_i64(a: i64, expected: f128) !void { + const x = f128_floatFromInt_i64(a); try testing.expect(x == expected); } -fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) !void { - const x = __floatunditf(a); +fn test_f128_floatFromInt_u64(a: u64, expected_hi: u64, expected_lo: u64) !void { + const x = f128_floatFromInt_u64(a); const x_repr: u128 = @bitCast(x); const x_hi: u64 = @intCast(x_repr >> 64); @@ -613,208 +643,207 @@ fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) !void { return; } } - - @panic("__floatunditf test failure"); + return error.TestFailure; } -test "floatditf" { - try test__floatditf(0x7fffffffffffffff, make_tf(0x403dffffffffffff, 0xfffc000000000000)); - try test__floatditf(0x123456789abcdef1, make_tf(0x403b23456789abcd, 0xef10000000000000)); - try test__floatditf(0x2, make_tf(0x4000000000000000, 0x0)); - try test__floatditf(0x1, make_tf(0x3fff000000000000, 0x0)); - try test__floatditf(0x0, make_tf(0x0, 0x0)); - try test__floatditf(@bitCast(@as(u64, 0xffffffffffffffff)), make_tf(0xbfff000000000000, 0x0)); - try test__floatditf(@bitCast(@as(u64, 0xfffffffffffffffe)), make_tf(0xc000000000000000, 0x0)); - try test__floatditf(-0x123456789abcdef1, make_tf(0xc03b23456789abcd, 0xef10000000000000)); - try test__floatditf(@bitCast(@as(u64, 0x8000000000000000)), make_tf(0xc03e000000000000, 0x0)); +test f128_floatFromInt_i64 { + try test_f128_floatFromInt_i64(0x7fffffffffffffff, make_tf(0x403dffffffffffff, 0xfffc000000000000)); + try test_f128_floatFromInt_i64(0x123456789abcdef1, make_tf(0x403b23456789abcd, 0xef10000000000000)); + try test_f128_floatFromInt_i64(0x2, make_tf(0x4000000000000000, 0x0)); + try test_f128_floatFromInt_i64(0x1, make_tf(0x3fff000000000000, 0x0)); + try test_f128_floatFromInt_i64(0x0, make_tf(0x0, 0x0)); + try test_f128_floatFromInt_i64(@bitCast(@as(u64, 0xffffffffffffffff)), make_tf(0xbfff000000000000, 0x0)); + try test_f128_floatFromInt_i64(@bitCast(@as(u64, 0xfffffffffffffffe)), make_tf(0xc000000000000000, 0x0)); + try test_f128_floatFromInt_i64(-0x123456789abcdef1, make_tf(0xc03b23456789abcd, 0xef10000000000000)); + try test_f128_floatFromInt_i64(@bitCast(@as(u64, 0x8000000000000000)), make_tf(0xc03e000000000000, 0x0)); } -test "floatunditf" { - try test__floatunditf(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000); - try test__floatunditf(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000); - try test__floatunditf(0x8000000000000000, 0x403e000000000000, 0x0); - try test__floatunditf(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000); - try test__floatunditf(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000); - try test__floatunditf(0x2, 0x4000000000000000, 0x0); - try test__floatunditf(0x1, 0x3fff000000000000, 0x0); - try test__floatunditf(0x0, 0x0, 0x0); +test f128_floatFromInt_u64 { + try test_f128_floatFromInt_u64(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000); + try test_f128_floatFromInt_u64(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000); + try test_f128_floatFromInt_u64(0x8000000000000000, 0x403e000000000000, 0x0); + try test_f128_floatFromInt_u64(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000); + try test_f128_floatFromInt_u64(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000); + try test_f128_floatFromInt_u64(0x2, 0x4000000000000000, 0x0); + try test_f128_floatFromInt_u64(0x1, 0x3fff000000000000, 0x0); + try test_f128_floatFromInt_u64(0x0, 0x0, 0x0); } -fn test__floattitf(a: i128, expected: f128) !void { - const x = __floattitf(a); +fn test_f128_floatFromInt_i128(a: i128, expected: f128) !void { + const x = f128_floatFromInt_i128(a); try testing.expect(x == expected); } -fn test__floatuntitf(a: u128, expected: f128) !void { - const x = __floatuntitf(a); +fn test_f128_floatFromInt_u128(a: u128, expected: f128) !void { + const x = f128_floatFromInt_u128(a); try testing.expect(x == expected); } -test "floattitf" { - try test__floattitf(0, 0.0); - - try test__floattitf(1, 1.0); - try test__floattitf(2, 2.0); - try test__floattitf(20, 20.0); - try test__floattitf(-1, -1.0); - try test__floattitf(-2, -2.0); - try test__floattitf(-20, -20.0); - - try test__floattitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floattitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floattitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floattitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - - try test__floattitf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); - try test__floattitf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); - try test__floattitf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); - try test__floattitf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); - - try test__floattitf(make_ti(0x8000000000000000, 0), -0x1.000000p+127); - try test__floattitf(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126); - - try test__floattitf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floattitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floattitf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floattitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floattitf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floattitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floattitf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floattitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floattitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floattitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floattitf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floattitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floattitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); - try test__floattitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); - try test__floattitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); - try test__floattitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); - try test__floattitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); - try test__floattitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); - try test__floattitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); - try test__floattitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); - try test__floattitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); - try test__floattitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); - try test__floattitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); - try test__floattitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); - try test__floattitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); - try test__floattitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floattitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floattitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); - try test__floattitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); - try test__floattitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); - try test__floattitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); - try test__floattitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); - try test__floattitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); - try test__floattitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); - try test__floattitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); - try test__floattitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); - try test__floattitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); - try test__floattitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); - try test__floattitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); - try test__floattitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); - try test__floattitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); - - try test__floattitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); - - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); - try test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); +test f128_floatFromInt_i128 { + try test_f128_floatFromInt_i128(0, 0.0); + + try test_f128_floatFromInt_i128(1, 1.0); + try test_f128_floatFromInt_i128(2, 2.0); + try test_f128_floatFromInt_i128(20, 20.0); + try test_f128_floatFromInt_i128(-1, -1.0); + try test_f128_floatFromInt_i128(-2, -2.0); + try test_f128_floatFromInt_i128(-20, -20.0); + + try test_f128_floatFromInt_i128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f128_floatFromInt_i128(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f128_floatFromInt_i128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f128_floatFromInt_i128(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + + try test_f128_floatFromInt_i128(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126); + try test_f128_floatFromInt_i128(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126); + try test_f128_floatFromInt_i128(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126); + try test_f128_floatFromInt_i128(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126); + + try test_f128_floatFromInt_i128(make_ti(0x8000000000000000, 0), -0x1.000000p+127); + try test_f128_floatFromInt_i128(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126); + + try test_f128_floatFromInt_i128(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test_f128_floatFromInt_i128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f128_floatFromInt_i128(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f128_floatFromInt_i128(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f128_floatFromInt_i128(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f128_floatFromInt_i128(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test_f128_floatFromInt_i128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f128_floatFromInt_i128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f128_floatFromInt_i128(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f128_floatFromInt_i128(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f128_floatFromInt_i128(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test_f128_floatFromInt_i128(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); + try test_f128_floatFromInt_i128(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); + try test_f128_floatFromInt_i128(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); + + try test_f128_floatFromInt_i128(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); + + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); + try test_f128_floatFromInt_i128(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); } -test "floatuntitf" { - try test__floatuntitf(0, 0.0); - - try test__floatuntitf(1, 1.0); - try test__floatuntitf(2, 2.0); - try test__floatuntitf(20, 20.0); - - try test__floatuntitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); - try test__floatuntitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); - try test__floatuntitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); - try test__floatuntitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); - try test__floatuntitf(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59); - try test__floatuntitf(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60); - try test__floatuntitf(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60); - - try test__floatuntitf(0x8000008000000000, 0x8.000008p+60); - try test__floatuntitf(0x8000000000000800, 0x8.0000000000008p+60); - try test__floatuntitf(0x8000010000000000, 0x8.00001p+60); - try test__floatuntitf(0x8000000000001000, 0x8.000000000001p+60); - - try test__floatuntitf(0x8000000000000000, 0x8p+60); - try test__floatuntitf(0x8000000000000001, 0x8.000000000000001p+60); - - try test__floatuntitf(0x0007FB72E8000000, 0x1.FEDCBAp+50); - - try test__floatuntitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50); - try test__floatuntitf(0x0007FB72EB000000, 0x1.FEDCBACp+50); - try test__floatuntitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); - try test__floatuntitf(0x0007FB72EC000000, 0x1.FEDCBBp+50); - try test__floatuntitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); - - try test__floatuntitf(0x0007FB72E6000000, 0x1.FEDCB98p+50); - try test__floatuntitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); - try test__floatuntitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); - try test__floatuntitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); - try test__floatuntitf(0x0007FB72E4000000, 0x1.FEDCB9p+50); - - try test__floatuntitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); - try test__floatuntitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); - try test__floatuntitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); - try test__floatuntitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); - try test__floatuntitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); - try test__floatuntitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); - try test__floatuntitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); - try test__floatuntitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); - try test__floatuntitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); - try test__floatuntitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); - try test__floatuntitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); - try test__floatuntitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); - try test__floatuntitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); - try test__floatuntitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); - try test__floatuntitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); - - try test__floatuntitf(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); - try test__floatuntitf(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); - try test__floatuntitf(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); - try test__floatuntitf(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); - try test__floatuntitf(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); - try test__floatuntitf(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); - - try test__floatuntitf(make_uti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); - - try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127); - try test__floatuntitf(make_uti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128); - - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); - try test__floatuntitf(make_uti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); +test f128_floatFromInt_u128 { + try test_f128_floatFromInt_u128(0, 0.0); + + try test_f128_floatFromInt_u128(1, 1.0); + try test_f128_floatFromInt_u128(2, 2.0); + try test_f128_floatFromInt_u128(20, 20.0); + + try test_f128_floatFromInt_u128(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + try test_f128_floatFromInt_u128(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62); + try test_f128_floatFromInt_u128(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + try test_f128_floatFromInt_u128(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62); + try test_f128_floatFromInt_u128(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59); + try test_f128_floatFromInt_u128(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60); + try test_f128_floatFromInt_u128(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60); + + try test_f128_floatFromInt_u128(0x8000008000000000, 0x8.000008p+60); + try test_f128_floatFromInt_u128(0x8000000000000800, 0x8.0000000000008p+60); + try test_f128_floatFromInt_u128(0x8000010000000000, 0x8.00001p+60); + try test_f128_floatFromInt_u128(0x8000000000001000, 0x8.000000000001p+60); + + try test_f128_floatFromInt_u128(0x8000000000000000, 0x8p+60); + try test_f128_floatFromInt_u128(0x8000000000000001, 0x8.000000000000001p+60); + + try test_f128_floatFromInt_u128(0x0007FB72E8000000, 0x1.FEDCBAp+50); + + try test_f128_floatFromInt_u128(0x0007FB72EA000000, 0x1.FEDCBA8p+50); + try test_f128_floatFromInt_u128(0x0007FB72EB000000, 0x1.FEDCBACp+50); + try test_f128_floatFromInt_u128(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50); + try test_f128_floatFromInt_u128(0x0007FB72EC000000, 0x1.FEDCBBp+50); + try test_f128_floatFromInt_u128(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50); + + try test_f128_floatFromInt_u128(0x0007FB72E6000000, 0x1.FEDCB98p+50); + try test_f128_floatFromInt_u128(0x0007FB72E7000000, 0x1.FEDCB9Cp+50); + try test_f128_floatFromInt_u128(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50); + try test_f128_floatFromInt_u128(0x0007FB72E4000001, 0x1.FEDCB90000004p+50); + try test_f128_floatFromInt_u128(0x0007FB72E4000000, 0x1.FEDCB9p+50); + + try test_f128_floatFromInt_u128(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57); + try test_f128_floatFromInt_u128(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57); + + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121); + try test_f128_floatFromInt_u128(make_uti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121); + + try test_f128_floatFromInt_u128(make_uti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63); + + try test_f128_floatFromInt_u128(make_uti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127); + try test_f128_floatFromInt_u128(make_uti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128); + + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124); + try test_f128_floatFromInt_u128(make_uti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124); } fn make_ti(high: u64, low: u64) i128 { @@ -838,45 +867,40 @@ fn make_tf(high: u64, low: u64) f128 { return @bitCast(result); } -test "conversion to f16" { - try testing.expect(__floatunsihf(@as(u32, 0)) == 0.0); - try testing.expect(__floatunsihf(@as(u32, 1)) == 1.0); - try testing.expect(__floatunsihf(@as(u32, 65504)) == 65504); - try testing.expect(__floatunsihf(@as(u32, 65504 + (1 << 4))) == math.inf(f16)); +test f16_floatFromInt_u32 { + try testing.expect(f16_floatFromInt_u32(0) == 0.0); + try testing.expect(f16_floatFromInt_u32(1) == 1.0); + try testing.expect(f16_floatFromInt_u32(65504) == 65504); + try testing.expect(f16_floatFromInt_u32(65504 + (1 << 4)) == math.inf(f16)); } -test "conversion to f32" { - try testing.expect(__floatunsisf(@as(u32, 0)) == 0.0); - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u32))) != 1.0); - try testing.expect(__floatsisf(@as(i32, math.minInt(i32))) != 1.0); - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24))) == math.maxInt(u24)); - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 1) == math.maxInt(u24) + 1); // 0x100_0000 - Exact - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 2) == math.maxInt(u24) + 1); // 0x100_0001 - Tie: Rounds down to even - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 3) == math.maxInt(u24) + 3); // 0x100_0002 - Exact - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 4) == math.maxInt(u24) + 5); // 0x100_0003 - Tie: Rounds up to even - try testing.expect(__floatunsisf(@as(u32, math.maxInt(u24)) + 5) == math.maxInt(u24) + 5); // 0x100_0004 - Exact +test f80_floatFromInt_u32 { + try testing.expect(f80_floatFromInt_u32(0) == 0.0); + try testing.expect(f80_floatFromInt_u32(1) == 1.0); + try testing.expect(f80_floatFromInt_u32(math.maxInt(u24) + 0) == math.maxInt(u24)); } -test "conversion to f80" { - const floatFromInt = @import("./float_from_int.zig").floatFromInt; +test f80_floatFromInt_u64 { + try testing.expect(f80_floatFromInt_u64(math.maxInt(u64) + 0) == math.maxInt(u64) + 0); +} + +test f80_floatFromInt_i128 { + try testing.expect(f80_floatFromInt_i128(-12) == -12); +} - try testing.expect(floatFromInt(f80, @as(i80, -12)) == -12); - try testing.expect(@as(u80, @intFromFloat(floatFromInt(f80, @as(u64, math.maxInt(u64)) + 0))) == math.maxInt(u64) + 0); - try testing.expect(@as(u80, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 1))) == math.maxInt(u64) + 1); +test f80_floatFromInt_u128 { + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 1) == math.maxInt(u64) + 1); - try testing.expect(floatFromInt(f80, @as(u32, 0)) == 0.0); - try testing.expect(floatFromInt(f80, @as(u32, 1)) == 1.0); - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u32, math.maxInt(u24)) + 0))) == math.maxInt(u24)); - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 0))) == math.maxInt(u64)); - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 1))) == math.maxInt(u64) + 1); // Exact - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 2))) == math.maxInt(u64) + 1); // Rounds down - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 3))) == math.maxInt(u64) + 3); // Tie - Exact - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u64)) + 4))) == math.maxInt(u64) + 5); // Rounds up + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 0) == math.maxInt(u64)); + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 1) == math.maxInt(u64) + 1); // Exact + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 2) == math.maxInt(u64) + 1); // Rounds down + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 3) == math.maxInt(u64) + 3); // Tie - Exact + try testing.expect(f80_floatFromInt_u128(math.maxInt(u64) + 4) == math.maxInt(u64) + 5); // Rounds up - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 0))) == math.maxInt(u65) + 1); // Rounds up - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 1))) == math.maxInt(u65) + 1); // Exact - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 2))) == math.maxInt(u65) + 1); // Rounds down - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 3))) == math.maxInt(u65) + 1); // Tie - Rounds down - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 4))) == math.maxInt(u65) + 5); // Rounds up - try testing.expect(@as(u128, @intFromFloat(floatFromInt(f80, @as(u80, math.maxInt(u65)) + 5))) == math.maxInt(u65) + 5); // Exact + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 0) == math.maxInt(u65) + 1); // Rounds up + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 1) == math.maxInt(u65) + 1); // Exact + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 2) == math.maxInt(u65) + 1); // Rounds down + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 3) == math.maxInt(u65) + 1); // Tie - Rounds down + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 4) == math.maxInt(u65) + 5); // Rounds up + try testing.expect(f80_floatFromInt_u128(math.maxInt(u65) + 5) == math.maxInt(u65) + 5); // Exact } diff --git a/lib/compiler_rt/floatdidf.zig b/lib/compiler_rt/floatdidf.zig deleted file mode 100644 index f8d5153d5b43896b3dd26a32e84f613151b84653..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatdidf.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_l2d, "__aeabi_l2d"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__floatdidf, "__i64tod"); - } - symbol(&__floatdidf, "__floatdidf"); - } -} - -pub fn __floatdidf(a: i64) callconv(.c) f64 { - return floatFromInt(f64, a); -} - -fn __aeabi_l2d(a: i64) callconv(.{ .arm_aapcs = .{} }) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatdihf.zig b/lib/compiler_rt/floatdihf.zig deleted file mode 100644 index c6865dff6b8025e49b8f1a0ffc36674c230247a4..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatdihf.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatdihf, "__floatdihf"); -} - -fn __floatdihf(a: i64) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatdisf.zig b/lib/compiler_rt/floatdisf.zig deleted file mode 100644 index 3da1faba367a6a17b81f97c93db6ff2041765b84..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatdisf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_l2f, "__aeabi_l2f"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__floatdisf, "__i64tos"); - } - symbol(&__floatdisf, "__floatdisf"); - } -} - -pub fn __floatdisf(a: i64) callconv(.c) f32 { - return floatFromInt(f32, a); -} - -fn __aeabi_l2f(a: i64) callconv(.{ .arm_aapcs = .{} }) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatditf.zig b/lib/compiler_rt/floatditf.zig deleted file mode 100644 index 033c35ffcbdd2137d84890c9176d7c77fe29541e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatditf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__floatditf, "__floatdikf"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_xtoq, "_Qp_xtoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__floatditf, "_Q_lltoq"); - } - symbol(&__floatditf, "__floatditf"); -} - -pub fn __floatditf(a: i64) callconv(.c) f128 { - return floatFromInt(f128, a); -} - -fn _Qp_xtoq(c: *f128, a: i64) callconv(.c) void { - c.* = floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatdixf.zig b/lib/compiler_rt/floatdixf.zig deleted file mode 100644 index 6bd06245d584402e7ed93b0d57d71f471bde05d4..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatdixf.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatdixf, "__floatdixf"); -} - -fn __floatdixf(a: i64) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floateidf.zig b/lib/compiler_rt/floateidf.zig deleted file mode 100644 index ac3972c28778600d342d0412741e9a3e41797546..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateidf.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__floateidf, "__floateidf"); -} - -pub fn __floateidf(a: [*]const u8, bits: usize) callconv(.c) f64 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f64, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floateihf.zig b/lib/compiler_rt/floateihf.zig deleted file mode 100644 index c1ec290fb1084a05b6353ffde4968bce3c3cd3d8..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateihf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floateihf, "__floateihf"); -} - -pub fn __floateihf(a: [*]const u8, bits: usize) callconv(.c) f16 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f16, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floateisf.zig b/lib/compiler_rt/floateisf.zig deleted file mode 100644 index dd5933b7dff321ee90d0b13ee6d9a5e0d85a9f20..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateisf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floateisf, "__floateisf"); -} - -pub fn __floateisf(a: [*]const u8, bits: usize) callconv(.c) f32 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f32, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floateitf.zig b/lib/compiler_rt/floateitf.zig deleted file mode 100644 index 0df893bd18881c9ec382e718a7664bf4d0f7a8e4..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateitf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floateitf, "__floateitf"); -} - -pub fn __floateitf(a: [*]const u8, bits: usize) callconv(.c) f128 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f128, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floateixf.zig b/lib/compiler_rt/floateixf.zig deleted file mode 100644 index dafefa4e8f11b978f26b5e4d10cc8b0feeed480b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floateixf.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floateixf, "__floateixf"); -} - -pub fn __floateixf(a: [*]const u8, bits: usize) callconv(.c) f80 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f80, .signed, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatsidf.zig b/lib/compiler_rt/floatsidf.zig deleted file mode 100644 index dc5a261a08f1e86155d7af20b62b43b02c99bbe5..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsidf.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_i2d, "__aeabi_i2d"); - } else { - symbol(&__floatsidf, "__floatsidf"); - } -} - -pub fn __floatsidf(a: i32) callconv(.c) f64 { - return floatFromInt(f64, a); -} - -fn __aeabi_i2d(a: i32) callconv(.{ .arm_aapcs = .{} }) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatsihf.zig b/lib/compiler_rt/floatsihf.zig deleted file mode 100644 index e1d588cfb0da1ed1007496f3d32db0fcdd8612ef..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsihf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatsihf, "__floatsihf"); -} - -fn __floatsihf(a: i32) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatsisf.zig b/lib/compiler_rt/floatsisf.zig deleted file mode 100644 index 0dac860ebfded913a3eacb1666cb34e246f87dde..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsisf.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_i2f, "__aeabi_i2f"); - } else { - symbol(&__floatsisf, "__floatsisf"); - } -} - -pub fn __floatsisf(a: i32) callconv(.c) f32 { - return floatFromInt(f32, a); -} - -fn __aeabi_i2f(a: i32) callconv(.{ .arm_aapcs = .{} }) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatsitf.zig b/lib/compiler_rt/floatsitf.zig deleted file mode 100644 index 865ebce60fddaa5d8234cf76293b08e12be30000..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsitf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__floatsitf, "__floatsikf"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_itoq, "_Qp_itoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__floatsitf, "_Q_itoq"); - } - symbol(&__floatsitf, "__floatsitf"); -} - -pub fn __floatsitf(a: i32) callconv(.c) f128 { - return floatFromInt(f128, a); -} - -fn _Qp_itoq(c: *f128, a: i32) callconv(.c) void { - c.* = floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatsixf.zig b/lib/compiler_rt/floatsixf.zig deleted file mode 100644 index bd28eaf1fa68f9580f63b918bfeea6cc78295699..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatsixf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__floatsixf, "__floatsixf"); -} - -fn __floatsixf(a: i32) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floattidf.zig b/lib/compiler_rt/floattidf.zig deleted file mode 100644 index 02298705324edcd49b36f69a64c0c78873ecb57b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattidf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floattidf, "__floattidf"); -} - -pub fn __floattidf(a: i128) callconv(.c) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floattihf.zig b/lib/compiler_rt/floattihf.zig deleted file mode 100644 index a751e3142c5b273819199105a6848c0280aee3c5..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattihf.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floattihf, "__floattihf"); -} - -pub fn __floattihf(a: i128) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floattisf.zig b/lib/compiler_rt/floattisf.zig deleted file mode 100644 index 72af61c6b6805d9bd03e6d215dd300fe7589c21f..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattisf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__floattisf, "__floattisf"); -} - -pub fn __floattisf(a: i128) callconv(.c) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floattitf.zig b/lib/compiler_rt/floattitf.zig deleted file mode 100644 index 3e49a68fd56912ebe7573346b6b8aea6b98b91ba..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattitf.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_ppc_abi) - symbol(&__floattitf, "__floattikf"); - symbol(&__floattitf, "__floattitf"); -} - -pub fn __floattitf(a: i128) callconv(.c) f128 { - return floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floattixf.zig b/lib/compiler_rt/floattixf.zig deleted file mode 100644 index be05180795aef517800c15d01c928bab4f7f19a0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floattixf.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floattixf, "__floattixf"); -} - -pub fn __floattixf(a: i128) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floatundidf.zig b/lib/compiler_rt/floatundidf.zig deleted file mode 100644 index 852675370503bab154245fd685ff2c2a5449aea0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatundidf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_ul2d, "__aeabi_ul2d"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__floatundidf, "__u64tod"); - } - symbol(&__floatundidf, "__floatundidf"); - } -} - -pub fn __floatundidf(a: u64) callconv(.c) f64 { - return floatFromInt(f64, a); -} - -fn __aeabi_ul2d(a: u64) callconv(.{ .arm_aapcs = .{} }) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatundihf.zig b/lib/compiler_rt/floatundihf.zig deleted file mode 100644 index 064d565d2dc4ec4f118dee8400375de802400f2b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatundihf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatundihf, "__floatundihf"); -} - -fn __floatundihf(a: u64) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatundisf.zig b/lib/compiler_rt/floatundisf.zig deleted file mode 100644 index 827a419fd5315624866af773ea71a9098b2bcb3e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatundisf.zig +++ /dev/null @@ -1,23 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_ul2f, "__aeabi_ul2f"); - } else { - if (compiler_rt.want_windows_arm_abi) { - symbol(&__floatundisf, "__u64tos"); - } - symbol(&__floatundisf, "__floatundisf"); - } -} - -pub fn __floatundisf(a: u64) callconv(.c) f32 { - return floatFromInt(f32, a); -} - -fn __aeabi_ul2f(a: u64) callconv(.{ .arm_aapcs = .{} }) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatunditf.zig b/lib/compiler_rt/floatunditf.zig deleted file mode 100644 index 79f9f54e176f5741bbc901b1790895feaadf1f98..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunditf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__floatunditf, "__floatundikf"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_uxtoq, "_Qp_uxtoq"); - } else if (compiler_rt.want_sparc32_abi) { - @export(&__floatunditf, "_Q_ulltoq"); - } - symbol(&__floatunditf, "__floatunditf"); -} - -pub fn __floatunditf(a: u64) callconv(.c) f128 { - return floatFromInt(f128, a); -} - -fn _Qp_uxtoq(c: *f128, a: u64) callconv(.c) void { - c.* = floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatundixf.zig b/lib/compiler_rt/floatundixf.zig deleted file mode 100644 index ce36d47a4ef225c67e4e45f3695cdb14649cee4c..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatundixf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatundixf, "__floatundixf"); -} - -fn __floatundixf(a: u64) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floatuneidf.zig b/lib/compiler_rt/floatuneidf.zig deleted file mode 100644 index 6e391b7cf1c4baeacb55c731ca24c66750c6d346..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneidf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneidf, "__floatuneidf"); -} - -pub fn __floatuneidf(a: [*]const u8, bits: usize) callconv(.c) f64 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f64, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatuneihf.zig b/lib/compiler_rt/floatuneihf.zig deleted file mode 100644 index 0df0cf155be8e7d39afb5012940fa85ec3211603..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneihf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneihf, "__floatuneihf"); -} - -pub fn __floatuneihf(a: [*]const u8, bits: usize) callconv(.c) f16 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f16, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatuneisf.zig b/lib/compiler_rt/floatuneisf.zig deleted file mode 100644 index e2dadd9ffddc6efe13ffd53bb9f2cdeeffc3530d..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneisf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneisf, "__floatuneisf"); -} - -pub fn __floatuneisf(a: [*]const u8, bits: usize) callconv(.c) f32 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f32, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatuneitf.zig b/lib/compiler_rt/floatuneitf.zig deleted file mode 100644 index ddee65dfb18b793bffe08d850384842fcff5747e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneitf.zig +++ /dev/null @@ -1,15 +0,0 @@ -const builtin = @import("builtin"); - -const std = @import("std"); - -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneitf, "__floatuneitf"); -} - -pub fn __floatuneitf(a: [*]const u8, bits: usize) callconv(.c) f128 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f128, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatuneixf.zig b/lib/compiler_rt/floatuneixf.zig deleted file mode 100644 index 75dd565daffe16ffb4e95230266fca2f5d288603..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuneixf.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromBigInt = @import("float_from_int.zig").floatFromBigInt; - -comptime { - symbol(&__floatuneixf, "__floatuneixf"); -} - -pub fn __floatuneixf(a: [*]const u8, bits: usize) callconv(.c) f80 { - const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); - return floatFromBigInt(f80, .unsigned, @ptrCast(@alignCast(a[0..byte_size]))); -} diff --git a/lib/compiler_rt/floatunsidf.zig b/lib/compiler_rt/floatunsidf.zig deleted file mode 100644 index 94949c7bff4eafff900a0b22e53998a930c3d7ea..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsidf.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_ui2d, "__aeabi_ui2d"); - } else { - symbol(&__floatunsidf, "__floatunsidf"); - } -} - -pub fn __floatunsidf(a: u32) callconv(.c) f64 { - return floatFromInt(f64, a); -} - -fn __aeabi_ui2d(a: u32) callconv(.{ .arm_aapcs = .{} }) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatunsihf.zig b/lib/compiler_rt/floatunsihf.zig deleted file mode 100644 index a2e42ca10f3af950e900f5250fa6a3d23e2b1266..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsihf.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatunsihf, "__floatunsihf"); -} - -pub fn __floatunsihf(a: u32) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatunsisf.zig b/lib/compiler_rt/floatunsisf.zig deleted file mode 100644 index 04da1aa5c03cf76815cccf2273731501d1c8edc0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsisf.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_ui2f, "__aeabi_ui2f"); - } else { - symbol(&__floatunsisf, "__floatunsisf"); - } -} - -pub fn __floatunsisf(a: u32) callconv(.c) f32 { - return floatFromInt(f32, a); -} - -fn __aeabi_ui2f(a: u32) callconv(.{ .arm_aapcs = .{} }) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatunsitf.zig b/lib/compiler_rt/floatunsitf.zig deleted file mode 100644 index 2b7c58eab8bd7c2a238062e0cc123f5ce6b8c9e0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsitf.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__floatunsitf, "__floatunsikf"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_uitoq, "_Qp_uitoq"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__floatunsitf, "_Q_utoq"); - } - symbol(&__floatunsitf, "__floatunsitf"); -} - -pub fn __floatunsitf(a: u32) callconv(.c) f128 { - return floatFromInt(f128, a); -} - -fn _Qp_uitoq(c: *f128, a: u32) callconv(.c) void { - c.* = floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatunsixf.zig b/lib/compiler_rt/floatunsixf.zig deleted file mode 100644 index 906f0270f5c53d28970a0c250b24abcadfa72946..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatunsixf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatunsixf, "__floatunsixf"); -} - -fn __floatunsixf(a: u32) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floatuntidf.zig b/lib/compiler_rt/floatuntidf.zig deleted file mode 100644 index b770457bc4992a5bd6237d832e2ca4c0cbed11e0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntidf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__floatuntidf, "__floatuntidf"); -} - -pub fn __floatuntidf(a: u128) callconv(.c) f64 { - return floatFromInt(f64, a); -} diff --git a/lib/compiler_rt/floatuntihf.zig b/lib/compiler_rt/floatuntihf.zig deleted file mode 100644 index 5b4373cb7c496b0acf1a2fe6ef988872b30e8780..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntihf.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatuntihf, "__floatuntihf"); -} - -pub fn __floatuntihf(a: u128) callconv(.c) f16 { - return floatFromInt(f16, a); -} diff --git a/lib/compiler_rt/floatuntisf.zig b/lib/compiler_rt/floatuntisf.zig deleted file mode 100644 index de9a021476edecfcc26761133c0645d799c677da..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntisf.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatuntisf, "__floatuntisf"); -} - -pub fn __floatuntisf(a: u128) callconv(.c) f32 { - return floatFromInt(f32, a); -} diff --git a/lib/compiler_rt/floatuntitf.zig b/lib/compiler_rt/floatuntitf.zig deleted file mode 100644 index 47cd65cc3ff4460d937e0ccd7acabb2455ae704a..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntitf.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const floatFromInt = @import("./float_from_int.zig").floatFromInt; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) - symbol(&__floatuntitf, "__floatuntikf"); - symbol(&__floatuntitf, "__floatuntitf"); -} - -pub fn __floatuntitf(a: u128) callconv(.c) f128 { - return floatFromInt(f128, a); -} diff --git a/lib/compiler_rt/floatuntixf.zig b/lib/compiler_rt/floatuntixf.zig deleted file mode 100644 index 41fb45b3a3a1b8e213c03a4ef5e847feb8d31211..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/floatuntixf.zig +++ /dev/null @@ -1,12 +0,0 @@ -const builtin = @import("builtin"); -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const floatFromInt = @import("./float_from_int.zig").floatFromInt; - -comptime { - symbol(&__floatuntixf, "__floatuntixf"); -} - -pub fn __floatuntixf(a: u128) callconv(.c) f80 { - return floatFromInt(f80, a); -} diff --git a/lib/compiler_rt/floor_ceil.zig b/lib/compiler_rt/floor_ceil.zig index f81d2e0011286a1ea45a3ef147fc704eadac4b4e..8bd82275e3787ae52587eb84c1391ee5949f616b 100644 --- a/lib/compiler_rt/floor_ceil.zig +++ b/lib/compiler_rt/floor_ceil.zig @@ -15,7 +15,7 @@ const mem = std.mem; const expect = std.testing.expect; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { // floor @@ -23,10 +23,7 @@ comptime { symbol(&floorf, "floorf"); symbol(&floor, "floor"); symbol(&__floorx, "__floorx"); - if (compiler_rt.want_ppc_abi) { - symbol(&floorq, "floorf128"); - } - symbol(&floorq, "floorq"); + symbol(&floorq, "floorf128"); symbol(&floorl, "floorl"); // ceil @@ -34,59 +31,96 @@ comptime { symbol(&ceilf, "ceilf"); symbol(&ceil, "ceil"); symbol(&__ceilx, "__ceilx"); - if (compiler_rt.want_ppc_abi) { - symbol(&ceilq, "ceilf128"); - } - symbol(&ceilq, "ceilq"); + symbol(&ceilq, "ceilf128"); symbol(&ceill, "ceill"); } -pub fn __floorh(x: f16) callconv(.c) f16 { +fn __floorh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(floor_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn floor_f16(x: f16) f16 { return impl(f16, .floor, x); } -pub fn floorf(x: f32) callconv(.c) f32 { +fn floorf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(floor_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn floor_f32(x: f32) f32 { return impl(f32, .floor, x); } -pub fn floor(x: f64) callconv(.c) f64 { +fn floor(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(floor_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn floor_f64(x: f64) f64 { return impl(f64, .floor, x); } -pub fn __floorx(x: f80) callconv(.c) f80 { +fn __floorx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(floor_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn floor_f80(x: f80) f80 { return impl(f80, .floor, x); } -pub fn floorq(x: f128) callconv(.c) f128 { +fn floorq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(floor_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn floor_f128(x: f128) f128 { return impl(f128, .floor, x); } pub fn floorl(x: c_longdouble) callconv(.c) c_longdouble { - return impl(std.meta.Float(@bitSizeOf(c_longdouble)), .floor, x); + switch (@typeInfo(c_longdouble).float.bits) { + 64 => return floor_f64(x), + 80 => return floor_f80(x), + 128 => return floor_f128(x), + else => comptime unreachable, + } } -pub fn __ceilh(x: f16) callconv(.c) f16 { +fn __ceilh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(ceil_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn ceil_f16(x: f16) f16 { return impl(f16, .ceil, x); } -pub fn ceilf(x: f32) callconv(.c) f32 { +fn ceilf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(ceil_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn ceil_f32(x: f32) f32 { return impl(f32, .ceil, x); } -pub fn ceil(x: f64) callconv(.c) f64 { +fn ceil(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(ceil_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn ceil_f64(x: f64) f64 { return impl(f64, .ceil, x); } -pub fn __ceilx(x: f80) callconv(.c) f80 { +fn __ceilx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(ceil_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn ceil_f80(x: f80) f80 { return impl(f80, .ceil, x); } -pub fn ceilq(x: f128) callconv(.c) f128 { +fn ceilq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(ceil_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn ceil_f128(x: f128) f128 { return impl(f128, .ceil, x); } pub fn ceill(x: c_longdouble) callconv(.c) c_longdouble { - return impl(std.meta.Float(@bitSizeOf(c_longdouble)), .ceil, x); + switch (@typeInfo(c_longdouble).float.bits) { + 64 => return ceil_f64(x), + 80 => return ceil_f80(x), + 128 => return ceil_f128(x), + else => comptime unreachable, + } } inline fn impl(comptime T: type, comptime op: enum { floor, ceil }, x: T) T { @@ -144,142 +178,122 @@ inline fn impl(comptime T: type, comptime op: enum { floor, ceil }, x: T) T { } } -test "floor16" { - try expect(__floorh(1.3) == 1.0); - try expect(__floorh(-1.3) == -2.0); - try expect(__floorh(0.2) == 0.0); -} - -test "floor32" { - try expect(floorf(1.3) == 1.0); - try expect(floorf(-1.3) == -2.0); - try expect(floorf(0.2) == 0.0); -} - -test "floor64" { - try expect(floor(1.3) == 1.0); - try expect(floor(-1.3) == -2.0); - try expect(floor(0.2) == 0.0); -} - -test "floor80" { - try expect(__floorx(1.3) == 1.0); - try expect(__floorx(-1.3) == -2.0); - try expect(__floorx(0.2) == 0.0); -} - -test "floor128" { - try expect(floorq(1.3) == 1.0); - try expect(floorq(-1.3) == -2.0); - try expect(floorq(0.2) == 0.0); -} - -test "floor16.special" { - try expect(__floorh(0.0) == 0.0); - try expect(__floorh(-0.0) == -0.0); - try expect(math.isPositiveInf(__floorh(math.inf(f16)))); - try expect(math.isNegativeInf(__floorh(-math.inf(f16)))); - try expect(math.isNan(__floorh(math.nan(f16)))); -} - -test "floor32.special" { - try expect(floorf(0.0) == 0.0); - try expect(floorf(-0.0) == -0.0); - try expect(math.isPositiveInf(floorf(math.inf(f32)))); - try expect(math.isNegativeInf(floorf(-math.inf(f32)))); - try expect(math.isNan(floorf(math.nan(f32)))); -} - -test "floor64.special" { - try expect(floor(0.0) == 0.0); - try expect(floor(-0.0) == -0.0); - try expect(math.isPositiveInf(floor(math.inf(f64)))); - try expect(math.isNegativeInf(floor(-math.inf(f64)))); - try expect(math.isNan(floor(math.nan(f64)))); -} - -test "floor80.special" { - try expect(__floorx(0.0) == 0.0); - try expect(__floorx(-0.0) == -0.0); - try expect(math.isPositiveInf(__floorx(math.inf(f80)))); - try expect(math.isNegativeInf(__floorx(-math.inf(f80)))); - try expect(math.isNan(__floorx(math.nan(f80)))); -} - -test "floor128.special" { - try expect(floorq(0.0) == 0.0); - try expect(floorq(-0.0) == -0.0); - try expect(math.isPositiveInf(floorq(math.inf(f128)))); - try expect(math.isNegativeInf(floorq(-math.inf(f128)))); - try expect(math.isNan(floorq(math.nan(f128)))); -} - -test "ceil16" { - try expect(__ceilh(1.3) == 2.0); - try expect(__ceilh(-1.3) == -1.0); - try expect(__ceilh(0.2) == 1.0); -} - -test "ceil32" { - try expect(ceilf(1.3) == 2.0); - try expect(ceilf(-1.3) == -1.0); - try expect(ceilf(0.2) == 1.0); -} - -test "ceil64" { - try expect(ceil(1.3) == 2.0); - try expect(ceil(-1.3) == -1.0); - try expect(ceil(0.2) == 1.0); -} - -test "ceil80" { - try expect(__ceilx(1.3) == 2.0); - try expect(__ceilx(-1.3) == -1.0); - try expect(__ceilx(0.2) == 1.0); -} - -test "ceil128" { - try expect(ceilq(1.3) == 2.0); - try expect(ceilq(-1.3) == -1.0); - try expect(ceilq(0.2) == 1.0); -} - -test "ceil16.special" { - try expect(__ceilh(0.0) == 0.0); - try expect(__ceilh(-0.0) == -0.0); - try expect(math.isPositiveInf(__ceilh(math.inf(f16)))); - try expect(math.isNegativeInf(__ceilh(-math.inf(f16)))); - try expect(math.isNan(__ceilh(math.nan(f16)))); -} - -test "ceil32.special" { - try expect(ceilf(0.0) == 0.0); - try expect(ceilf(-0.0) == -0.0); - try expect(math.isPositiveInf(ceilf(math.inf(f32)))); - try expect(math.isNegativeInf(ceilf(-math.inf(f32)))); - try expect(math.isNan(ceilf(math.nan(f32)))); -} - -test "ceil64.special" { - try expect(ceil(0.0) == 0.0); - try expect(ceil(-0.0) == -0.0); - try expect(math.isPositiveInf(ceil(math.inf(f64)))); - try expect(math.isNegativeInf(ceil(-math.inf(f64)))); - try expect(math.isNan(ceil(math.nan(f64)))); -} - -test "ceil80.special" { - try expect(__ceilx(0.0) == 0.0); - try expect(__ceilx(-0.0) == -0.0); - try expect(math.isPositiveInf(__ceilx(math.inf(f80)))); - try expect(math.isNegativeInf(__ceilx(-math.inf(f80)))); - try expect(math.isNan(__ceilx(math.nan(f80)))); -} - -test "ceil128.special" { - try expect(ceilq(0.0) == 0.0); - try expect(ceilq(-0.0) == -0.0); - try expect(math.isPositiveInf(ceilq(math.inf(f128)))); - try expect(math.isNegativeInf(ceilq(-math.inf(f128)))); - try expect(math.isNan(ceilq(math.nan(f128)))); +test floor_f16 { + try expect(floor_f16(1.3) == 1.0); + try expect(floor_f16(-1.3) == -2.0); + try expect(floor_f16(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f16(0.2))); + try expect(math.isPositiveZero(floor_f16(0.0))); + try expect(math.isNegativeZero(floor_f16(-0.0))); + try expect(math.isPositiveInf(floor_f16(math.inf(f16)))); + try expect(math.isNegativeInf(floor_f16(-math.inf(f16)))); + try expect(math.isNan(floor_f16(math.nan(f16)))); +} + +test floor_f32 { + try expect(floor_f32(1.3) == 1.0); + try expect(floor_f32(-1.3) == -2.0); + try expect(floor_f32(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f32(0.2))); + try expect(math.isPositiveZero(floor_f32(0.0))); + try expect(math.isNegativeZero(floor_f32(-0.0))); + try expect(math.isPositiveInf(floor_f32(math.inf(f32)))); + try expect(math.isNegativeInf(floor_f32(-math.inf(f32)))); + try expect(math.isNan(floor_f32(math.nan(f32)))); +} + +test floor_f64 { + try expect(floor_f64(1.3) == 1.0); + try expect(floor_f64(-1.3) == -2.0); + try expect(floor_f64(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f64(0.2))); + try expect(math.isPositiveZero(floor_f64(0.0))); + try expect(math.isNegativeZero(floor_f64(-0.0))); + try expect(math.isPositiveInf(floor_f64(math.inf(f64)))); + try expect(math.isNegativeInf(floor_f64(-math.inf(f64)))); + try expect(math.isNan(floor_f64(math.nan(f64)))); +} + +test floor_f80 { + try expect(floor_f80(1.3) == 1.0); + try expect(floor_f80(-1.3) == -2.0); + try expect(floor_f80(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f80(0.2))); + try expect(math.isPositiveZero(floor_f80(0.0))); + try expect(math.isNegativeZero(floor_f80(-0.0))); + try expect(math.isPositiveInf(floor_f80(math.inf(f80)))); + try expect(math.isNegativeInf(floor_f80(-math.inf(f80)))); + try expect(math.isNan(floor_f80(math.nan(f80)))); +} + +test floor_f128 { + try expect(floor_f128(1.3) == 1.0); + try expect(floor_f128(-1.3) == -2.0); + try expect(floor_f128(-0.2) == -1.0); + try expect(math.isPositiveZero(floor_f128(0.2))); + try expect(math.isPositiveZero(floor_f128(0.0))); + try expect(math.isNegativeZero(floor_f128(-0.0))); + try expect(math.isPositiveInf(floor_f128(math.inf(f128)))); + try expect(math.isNegativeInf(floor_f128(-math.inf(f128)))); + try expect(math.isNan(floor_f128(math.nan(f128)))); +} + +test ceil_f16 { + try expect(ceil_f16(1.3) == 2.0); + try expect(ceil_f16(-1.3) == -1.0); + try expect(ceil_f16(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f16(-0.2))); + try expect(math.isPositiveZero(ceil_f16(0.0))); + try expect(math.isNegativeZero(ceil_f16(-0.0))); + try expect(math.isPositiveInf(ceil_f16(math.inf(f16)))); + try expect(math.isNegativeInf(ceil_f16(-math.inf(f16)))); + try expect(math.isNan(ceil_f16(math.nan(f16)))); +} + +test ceil_f32 { + try expect(ceil_f32(1.3) == 2.0); + try expect(ceil_f32(-1.3) == -1.0); + try expect(ceil_f32(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f32(-0.2))); + try expect(math.isPositiveZero(ceil_f32(0.0))); + try expect(math.isNegativeZero(ceil_f32(-0.0))); + try expect(math.isPositiveInf(ceil_f32(math.inf(f32)))); + try expect(math.isNegativeInf(ceil_f32(-math.inf(f32)))); + try expect(math.isNan(ceil_f32(math.nan(f32)))); +} + +test ceil_f64 { + try expect(ceil_f64(1.3) == 2.0); + try expect(ceil_f64(-1.3) == -1.0); + try expect(ceil_f64(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f64(-0.2))); + try expect(math.isPositiveZero(ceil_f64(0.0))); + try expect(math.isNegativeZero(ceil_f64(-0.0))); + try expect(math.isPositiveInf(ceil_f64(math.inf(f64)))); + try expect(math.isNegativeInf(ceil_f64(-math.inf(f64)))); + try expect(math.isNan(ceil_f64(math.nan(f64)))); +} + +test ceil_f80 { + try expect(ceil_f80(1.3) == 2.0); + try expect(ceil_f80(-1.3) == -1.0); + try expect(ceil_f80(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f80(-0.2))); + try expect(math.isPositiveZero(ceil_f80(0.0))); + try expect(math.isNegativeZero(ceil_f80(-0.0))); + try expect(math.isPositiveInf(ceil_f80(math.inf(f80)))); + try expect(math.isNegativeInf(ceil_f80(-math.inf(f80)))); + try expect(math.isNan(ceil_f80(math.nan(f80)))); +} + +test ceil_f128 { + try expect(ceil_f128(1.3) == 2.0); + try expect(ceil_f128(-1.3) == -1.0); + try expect(ceil_f128(0.2) == 1.0); + try expect(math.isNegativeZero(ceil_f128(-0.2))); + try expect(math.isPositiveZero(ceil_f128(0.0))); + try expect(math.isNegativeZero(ceil_f128(-0.0))); + try expect(math.isPositiveInf(ceil_f128(math.inf(f128)))); + try expect(math.isNegativeInf(ceil_f128(-math.inf(f128)))); + try expect(math.isNan(ceil_f128(math.nan(f128)))); } diff --git a/lib/compiler_rt/fma.zig b/lib/compiler_rt/fma.zig index 61732585db2ece3fb84c3029293cab41662781d2..97bb57d4aae5aebe74c34925abacdb84f3aeef82 100644 --- a/lib/compiler_rt/fma.zig +++ b/lib/compiler_rt/fma.zig @@ -16,19 +16,22 @@ comptime { symbol(&fmaf, "fmaf"); symbol(&fma, "fma"); symbol(&__fmax, "__fmax"); - if (compiler_rt.want_ppc_abi) { - symbol(&fmaq, "fmaf128"); - } - symbol(&fmaq, "fmaq"); + symbol(&fmaq, "fmaf128"); symbol(&fmal, "fmal"); } -pub fn __fmah(x: f16, y: f16, z: f16) callconv(.c) f16 { +fn __fmah(x: compiler_rt.f16.Abi, y: compiler_rt.f16.Abi, z: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fma_f16(compiler_rt.f16.fromAbi(x), compiler_rt.f16.fromAbi(y), compiler_rt.f16.fromAbi(z))); +} +pub fn fma_f16(x: f16, y: f16, z: f16) f16 { // TODO: more efficient implementation - return @floatCast(fmaf(x, y, z)); + return @floatCast(fma_f32(x, y, z)); } -pub fn fmaf(x: f32, y: f32, z: f32) callconv(.c) f32 { +fn fmaf(x: compiler_rt.f32.Abi, y: compiler_rt.f32.Abi, z: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fma_f32(compiler_rt.f32.fromAbi(x), compiler_rt.f32.fromAbi(y), compiler_rt.f32.fromAbi(z))); +} +pub fn fma_f32(x: f32, y: f32, z: f32) f32 { const xy = @as(f64, x) * y; const xy_z = xy + z; const u = @as(u64, @bitCast(xy_z)); @@ -42,8 +45,11 @@ pub fn fmaf(x: f32, y: f32, z: f32) callconv(.c) f32 { } } +fn fma(x: compiler_rt.f64.Abi, y: compiler_rt.f64.Abi, z: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fma_f64(compiler_rt.f64.fromAbi(x), compiler_rt.f64.fromAbi(y), compiler_rt.f64.fromAbi(z))); +} /// NOTE: Upstream fma.c has been rewritten completely to raise fp exceptions more accurately. -pub fn fma(x: f64, y: f64, z: f64) callconv(.c) f64 { +pub fn fma_f64(x: f64, y: f64, z: f64) f64 { if (!math.isFinite(x) or !math.isFinite(y)) { return x * y + z; } @@ -90,11 +96,17 @@ pub fn fma(x: f64, y: f64, z: f64) callconv(.c) f64 { } } -pub fn __fmax(a: f80, b: f80, c: f80) callconv(.c) f80 { +fn __fmax(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi, c: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fma_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b), compiler_rt.f80.fromAbi(c))); +} +pub fn fma_f80(a: f80, b: f80, c: f80) f80 { // TODO: more efficient implementation - return @floatCast(fmaq(a, b, c)); + return @floatCast(fma_f128(a, b, c)); } +fn fmaq(x: compiler_rt.f128.Abi, y: compiler_rt.f128.Abi, z: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fma_f128(compiler_rt.f128.fromAbi(x), compiler_rt.f128.fromAbi(y), compiler_rt.f128.fromAbi(z))); +} /// Fused multiply-add: Compute x * y + z with a single rounding error. /// /// We use scaling to avoid overflow/underflow, along with the @@ -102,7 +114,7 @@ pub fn __fmax(a: f80, b: f80, c: f80) callconv(.c) f80 { /// /// Dekker, T. A Floating-Point Technique for Extending the /// Available Precision. Numer. Math. 18, 224-242 (1971). -pub fn fmaq(x: f128, y: f128, z: f128) callconv(.c) f128 { +pub fn fma_f128(x: f128, y: f128, z: f128) f128 { if (!math.isFinite(x) or !math.isFinite(y)) { return x * y + z; } @@ -151,10 +163,10 @@ pub fn fmaq(x: f128, y: f128, z: f128) callconv(.c) f128 { pub fn fmal(x: c_longdouble, y: c_longdouble, z: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fma(x, y, z), - 80 => return __fmax(x, y, z), - 128 => return fmaq(x, y, z), - else => @compileError("unreachable"), + 64 => return fma_f64(x, y, z), + 80 => return fma_f80(x, y, z), + 128 => return fma_f128(x, y, z), + else => comptime unreachable, } } @@ -316,35 +328,35 @@ fn dd_mul128(a: f128, b: f128) dd128 { test "32" { const epsilon = 0.000001; - try expect(math.approxEqAbs(f32, fmaf(0.0, 5.0, 9.124), 9.124, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(0.2, 5.0, 9.124), 10.124, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(0.8923, 5.0, 9.124), 13.5855, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(1.5, 5.0, 9.124), 16.624, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(37.45, 5.0, 9.124), 196.374004, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(89.123, 5.0, 9.124), 454.739005, epsilon)); - try expect(math.approxEqAbs(f32, fmaf(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(0.0, 5.0, 9.124), 9.124, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(0.2, 5.0, 9.124), 10.124, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(0.8923, 5.0, 9.124), 13.5855, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(1.5, 5.0, 9.124), 16.624, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(37.45, 5.0, 9.124), 196.374004, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(89.123, 5.0, 9.124), 454.739005, epsilon)); + try expect(math.approxEqAbs(f32, fma_f32(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } test "64" { const epsilon = 0.000001; - try expect(math.approxEqAbs(f64, fma(0.0, 5.0, 9.124), 9.124, epsilon)); - try expect(math.approxEqAbs(f64, fma(0.2, 5.0, 9.124), 10.124, epsilon)); - try expect(math.approxEqAbs(f64, fma(0.8923, 5.0, 9.124), 13.5855, epsilon)); - try expect(math.approxEqAbs(f64, fma(1.5, 5.0, 9.124), 16.624, epsilon)); - try expect(math.approxEqAbs(f64, fma(37.45, 5.0, 9.124), 196.374, epsilon)); - try expect(math.approxEqAbs(f64, fma(89.123, 5.0, 9.124), 454.739, epsilon)); - try expect(math.approxEqAbs(f64, fma(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(0.0, 5.0, 9.124), 9.124, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(0.2, 5.0, 9.124), 10.124, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(0.8923, 5.0, 9.124), 13.5855, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(1.5, 5.0, 9.124), 16.624, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(37.45, 5.0, 9.124), 196.374, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(89.123, 5.0, 9.124), 454.739, epsilon)); + try expect(math.approxEqAbs(f64, fma_f64(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } test "128" { const epsilon = 0.000001; - try expect(math.approxEqAbs(f128, fmaq(0.0, 5.0, 9.124), 9.124, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(0.2, 5.0, 9.124), 10.124, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(0.8923, 5.0, 9.124), 13.5855, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(1.5, 5.0, 9.124), 16.624, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(37.45, 5.0, 9.124), 196.374, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(89.123, 5.0, 9.124), 454.739, epsilon)); - try expect(math.approxEqAbs(f128, fmaq(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(0.0, 5.0, 9.124), 9.124, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(0.2, 5.0, 9.124), 10.124, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(0.8923, 5.0, 9.124), 13.5855, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(1.5, 5.0, 9.124), 16.624, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(37.45, 5.0, 9.124), 196.374, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(89.123, 5.0, 9.124), 454.739, epsilon)); + try expect(math.approxEqAbs(f128, fma_f128(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } diff --git a/lib/compiler_rt/fmax.zig b/lib/compiler_rt/fmax.zig index 317d93f2d3e42fcfb88c4f36fe2203dab6bfeed2..f69912472044f62c50733968b382fec866d069c7 100644 --- a/lib/compiler_rt/fmax.zig +++ b/lib/compiler_rt/fmax.zig @@ -10,39 +10,51 @@ comptime { symbol(&fmaxf, "fmaxf"); symbol(&fmax, "fmax"); symbol(&__fmaxx, "__fmaxx"); - if (compiler_rt.want_ppc_abi) { - symbol(&fmaxq, "fmaxf128"); - } - symbol(&fmaxq, "fmaxq"); + symbol(&fmaxq, "fmaxf128"); symbol(&fmaxl, "fmaxl"); } -pub fn __fmaxh(x: f16, y: f16) callconv(.c) f16 { +fn __fmaxh(x: compiler_rt.f16.Abi, y: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fmax_f16(compiler_rt.f16.fromAbi(x), compiler_rt.f16.fromAbi(y))); +} +pub fn fmax_f16(x: f16, y: f16) f16 { return generic_fmax(f16, x, y); } -pub fn fmaxf(x: f32, y: f32) callconv(.c) f32 { +fn fmaxf(x: compiler_rt.f32.Abi, y: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fmax_f32(compiler_rt.f32.fromAbi(x), compiler_rt.f32.fromAbi(y))); +} +pub fn fmax_f32(x: f32, y: f32) f32 { return generic_fmax(f32, x, y); } -pub fn fmax(x: f64, y: f64) callconv(.c) f64 { +fn fmax(x: compiler_rt.f64.Abi, y: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fmax_f64(compiler_rt.f64.fromAbi(x), compiler_rt.f64.fromAbi(y))); +} +pub fn fmax_f64(x: f64, y: f64) f64 { return generic_fmax(f64, x, y); } -pub fn __fmaxx(x: f80, y: f80) callconv(.c) f80 { +fn __fmaxx(x: compiler_rt.f80.Abi, y: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fmax_f80(compiler_rt.f80.fromAbi(x), compiler_rt.f80.fromAbi(y))); +} +pub fn fmax_f80(x: f80, y: f80) f80 { return generic_fmax(f80, x, y); } -pub fn fmaxq(x: f128, y: f128) callconv(.c) f128 { +fn fmaxq(x: compiler_rt.f128.Abi, y: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fmax_f128(compiler_rt.f128.fromAbi(x), compiler_rt.f128.fromAbi(y))); +} +pub fn fmax_f128(x: f128, y: f128) f128 { return generic_fmax(f128, x, y); } pub fn fmaxl(x: c_longdouble, y: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fmax(x, y), - 80 => return __fmaxx(x, y), - 128 => return fmaxq(x, y), - else => @compileError("unreachable"), + 64 => return fmax_f64(x, y), + 80 => return fmax_f80(x, y), + 128 => return fmax_f128(x, y), + else => comptime unreachable, } } diff --git a/lib/compiler_rt/fmin.zig b/lib/compiler_rt/fmin.zig index 36cf9c121bbf17c1e282cfcf982f69ce7f1ec17c..bece9262f2a673919e33260576c2ce7d8730cdee 100644 --- a/lib/compiler_rt/fmin.zig +++ b/lib/compiler_rt/fmin.zig @@ -10,39 +10,51 @@ comptime { symbol(&fminf, "fminf"); symbol(&fmin, "fmin"); symbol(&__fminx, "__fminx"); - if (compiler_rt.want_ppc_abi) { - symbol(&fminq, "fminf128"); - } - symbol(&fminq, "fminq"); + symbol(&fminq, "fminf128"); symbol(&fminl, "fminl"); } -pub fn __fminh(x: f16, y: f16) callconv(.c) f16 { +fn __fminh(x: compiler_rt.f16.Abi, y: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fmin_f16(compiler_rt.f16.fromAbi(x), compiler_rt.f16.fromAbi(y))); +} +pub fn fmin_f16(x: f16, y: f16) f16 { return generic_fmin(f16, x, y); } -pub fn fminf(x: f32, y: f32) callconv(.c) f32 { +fn fminf(x: compiler_rt.f32.Abi, y: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fmin_f32(compiler_rt.f32.fromAbi(x), compiler_rt.f32.fromAbi(y))); +} +pub fn fmin_f32(x: f32, y: f32) f32 { return generic_fmin(f32, x, y); } -pub fn fmin(x: f64, y: f64) callconv(.c) f64 { +fn fmin(x: compiler_rt.f64.Abi, y: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fmin_f64(compiler_rt.f64.fromAbi(x), compiler_rt.f64.fromAbi(y))); +} +pub fn fmin_f64(x: f64, y: f64) f64 { return generic_fmin(f64, x, y); } -pub fn __fminx(x: f80, y: f80) callconv(.c) f80 { +fn __fminx(x: compiler_rt.f80.Abi, y: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fmin_f80(compiler_rt.f80.fromAbi(x), compiler_rt.f80.fromAbi(y))); +} +pub fn fmin_f80(x: f80, y: f80) f80 { return generic_fmin(f80, x, y); } -pub fn fminq(x: f128, y: f128) callconv(.c) f128 { +fn fminq(x: compiler_rt.f128.Abi, y: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fmin_f128(compiler_rt.f128.fromAbi(x), compiler_rt.f128.fromAbi(y))); +} +pub fn fmin_f128(x: f128, y: f128) f128 { return generic_fmin(f128, x, y); } pub fn fminl(x: c_longdouble, y: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fmin(x, y), - 80 => return __fminx(x, y), - 128 => return fminq(x, y), - else => @compileError("unreachable"), + 64 => return fmin_f64(x, y), + 80 => return fmin_f80(x, y), + 128 => return fmin_f128(x, y), + else => comptime unreachable, } } diff --git a/lib/compiler_rt/fmod.zig b/lib/compiler_rt/fmod.zig index 009eedd8ac84ab7eb905a74900fc17d07e8be421..951b90d06e529e8a3a2606d7fe0eff1dcd9d667a 100644 --- a/lib/compiler_rt/fmod.zig +++ b/lib/compiler_rt/fmod.zig @@ -12,29 +12,38 @@ comptime { symbol(&fmodf, "fmodf"); symbol(&fmod, "fmod"); symbol(&__fmodx, "__fmodx"); - if (compiler_rt.want_ppc_abi) { - symbol(&fmodq, "fmodf128"); - } - symbol(&fmodq, "fmodq"); + symbol(&fmodq, "fmodf128"); symbol(&fmodl, "fmodl"); } -pub fn __fmodh(x: f16, y: f16) callconv(.c) f16 { +fn __fmodh(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(fmod_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn fmod_f16(x: f16, y: f16) f16 { // TODO: more efficient implementation - return @floatCast(fmodf(x, y)); + return @floatCast(fmod_f32(x, y)); } -pub fn fmodf(x: f32, y: f32) callconv(.c) f32 { +fn fmodf(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(fmod_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); +} +pub fn fmod_f32(x: f32, y: f32) f32 { return generic_fmod(f32, x, y); } -pub fn fmod(x: f64, y: f64) callconv(.c) f64 { +fn fmod(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(fmod_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +pub fn fmod_f64(x: f64, y: f64) f64 { return generic_fmod(f64, x, y); } +fn __fmodx(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(fmod_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} /// fmodx - floating modulo large, returns the remainder of division for f80 types /// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits -pub fn __fmodx(a: f80, b: f80) callconv(.c) f80 { +pub fn fmod_f80(a: f80, b: f80) f80 { const T = f80; const Z = @Int(.unsigned, @bitSizeOf(T)); @@ -130,9 +139,12 @@ pub fn __fmodx(a: f80, b: f80) callconv(.c) f80 { } } +fn fmodq(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(fmod_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} /// fmodq - floating modulo large, returns the remainder of division for f128 types /// Logic and flow heavily inspired by MUSL fmodl for 113 mantissa digits -pub fn fmodq(a: f128, b: f128) callconv(.c) f128 { +pub fn fmod_f128(a: f128, b: f128) f128 { var amod = a; var bmod = b; const aPtr_u64: [*]u64 = @ptrCast(&amod); @@ -251,10 +263,10 @@ pub fn fmodq(a: f128, b: f128) callconv(.c) f128 { pub fn fmodl(a: c_longdouble, b: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return fmod(a, b), - 80 => return __fmodx(a, b), - 128 => return fmodq(a, b), - else => @compileError("unreachable"), + 64 => return fmod_f64(a, b), + 80 => return fmod_f80(a, b), + 128 => return fmod_f128(a, b), + else => comptime unreachable, } } @@ -342,42 +354,42 @@ inline fn generic_fmod(comptime T: type, x: T, y: T) T { return @bitCast(ux); } -test "fmodf" { +test fmod_f32 { const nan_val = math.nan(f32); const inf_val = math.inf(f32); - try std.testing.expect(math.isNan(fmodf(nan_val, 1.0))); - try std.testing.expect(math.isNan(fmodf(1.0, nan_val))); - try std.testing.expect(math.isNan(fmodf(inf_val, 1.0))); - try std.testing.expect(math.isNan(fmodf(0.0, 0.0))); - try std.testing.expect(math.isNan(fmodf(1.0, 0.0))); + try std.testing.expect(math.isNan(fmod_f32(nan_val, 1.0))); + try std.testing.expect(math.isNan(fmod_f32(1.0, nan_val))); + try std.testing.expect(math.isNan(fmod_f32(inf_val, 1.0))); + try std.testing.expect(math.isNan(fmod_f32(0.0, 0.0))); + try std.testing.expect(math.isNan(fmod_f32(1.0, 0.0))); - try std.testing.expectEqual(@as(f32, 0.0), fmodf(0.0, 2.0)); - try std.testing.expectEqual(@as(f32, -0.0), fmodf(-0.0, 2.0)); + try std.testing.expectEqual(@as(f32, 0.0), fmod_f32(0.0, 2.0)); + try std.testing.expectEqual(@as(f32, -0.0), fmod_f32(-0.0, 2.0)); - try std.testing.expectEqual(@as(f32, -2.0), fmodf(-32.0, 10.0)); - try std.testing.expectEqual(@as(f32, -2.0), fmodf(-32.0, -10.0)); - try std.testing.expectEqual(@as(f32, 2.0), fmodf(32.0, 10.0)); - try std.testing.expectEqual(@as(f32, 2.0), fmodf(32.0, -10.0)); + try std.testing.expectEqual(@as(f32, -2.0), fmod_f32(-32.0, 10.0)); + try std.testing.expectEqual(@as(f32, -2.0), fmod_f32(-32.0, -10.0)); + try std.testing.expectEqual(@as(f32, 2.0), fmod_f32(32.0, 10.0)); + try std.testing.expectEqual(@as(f32, 2.0), fmod_f32(32.0, -10.0)); } -test "fmod" { +test fmod_f64 { const nan_val = math.nan(f64); const inf_val = math.inf(f64); - try std.testing.expect(math.isNan(fmod(nan_val, 1.0))); - try std.testing.expect(math.isNan(fmod(1.0, nan_val))); - try std.testing.expect(math.isNan(fmod(inf_val, 1.0))); - try std.testing.expect(math.isNan(fmod(0.0, 0.0))); - try std.testing.expect(math.isNan(fmod(1.0, 0.0))); + try std.testing.expect(math.isNan(fmod_f64(nan_val, 1.0))); + try std.testing.expect(math.isNan(fmod_f64(1.0, nan_val))); + try std.testing.expect(math.isNan(fmod_f64(inf_val, 1.0))); + try std.testing.expect(math.isNan(fmod_f64(0.0, 0.0))); + try std.testing.expect(math.isNan(fmod_f64(1.0, 0.0))); - try std.testing.expectEqual(@as(f64, 0.0), fmod(0.0, 2.0)); - try std.testing.expectEqual(@as(f64, -0.0), fmod(-0.0, 2.0)); + try std.testing.expectEqual(@as(f64, 0.0), fmod_f64(0.0, 2.0)); + try std.testing.expectEqual(@as(f64, -0.0), fmod_f64(-0.0, 2.0)); - try std.testing.expectEqual(@as(f64, -2.0), fmod(-32.0, 10.0)); - try std.testing.expectEqual(@as(f64, -2.0), fmod(-32.0, -10.0)); - try std.testing.expectEqual(@as(f64, 2.0), fmod(32.0, 10.0)); - try std.testing.expectEqual(@as(f64, 2.0), fmod(32.0, -10.0)); + try std.testing.expectEqual(@as(f64, -2.0), fmod_f64(-32.0, 10.0)); + try std.testing.expectEqual(@as(f64, -2.0), fmod_f64(-32.0, -10.0)); + try std.testing.expectEqual(@as(f64, 2.0), fmod_f64(32.0, 10.0)); + try std.testing.expectEqual(@as(f64, 2.0), fmod_f64(32.0, -10.0)); } test { diff --git a/lib/compiler_rt/fmodq_test.zig b/lib/compiler_rt/fmodq_test.zig index 07ddb8d182e41fe2ff80414aeff256728e1ce365..b98dc0762e664f09b0d648e290658bf4502da416 100644 --- a/lib/compiler_rt/fmodq_test.zig +++ b/lib/compiler_rt/fmodq_test.zig @@ -1,52 +1,52 @@ const std = @import("std"); -const fmod = @import("fmod.zig"); +const fmod_f128 = @import("fmod.zig").fmod_f128; const testing = std.testing; -fn test_fmodq(a: f128, b: f128, exp: f128) !void { - const res = fmod.fmodq(a, b); +fn test_fmod_f128(a: f128, b: f128, exp: f128) !void { + const res = fmod_f128(a, b); try testing.expect(exp == res); } -fn test_fmodq_nans() !void { - try testing.expect(std.math.isNan(fmod.fmodq(1.0, std.math.nan(f128)))); - try testing.expect(std.math.isNan(fmod.fmodq(1.0, -std.math.nan(f128)))); - try testing.expect(std.math.isNan(fmod.fmodq(std.math.nan(f128), 1.0))); - try testing.expect(std.math.isNan(fmod.fmodq(-std.math.nan(f128), 1.0))); +fn test_fmod_f128_nans() !void { + try testing.expect(std.math.isNan(fmod_f128(1.0, std.math.nan(f128)))); + try testing.expect(std.math.isNan(fmod_f128(1.0, -std.math.nan(f128)))); + try testing.expect(std.math.isNan(fmod_f128(std.math.nan(f128), 1.0))); + try testing.expect(std.math.isNan(fmod_f128(-std.math.nan(f128), 1.0))); } -fn test_fmodq_infs() !void { - try testing.expect(fmod.fmodq(1.0, std.math.inf(f128)) == 1.0); - try testing.expect(fmod.fmodq(1.0, -std.math.inf(f128)) == 1.0); - try testing.expect(std.math.isNan(fmod.fmodq(std.math.inf(f128), 1.0))); - try testing.expect(std.math.isNan(fmod.fmodq(-std.math.inf(f128), 1.0))); +fn test_fmod_f128_infs() !void { + try testing.expect(fmod_f128(1.0, std.math.inf(f128)) == 1.0); + try testing.expect(fmod_f128(1.0, -std.math.inf(f128)) == 1.0); + try testing.expect(std.math.isNan(fmod_f128(std.math.inf(f128), 1.0))); + try testing.expect(std.math.isNan(fmod_f128(-std.math.inf(f128), 1.0))); } -test "fmodq" { - try test_fmodq(6.8, 4.0, 2.8); - try test_fmodq(6.8, -4.0, 2.8); - try test_fmodq(-6.8, 4.0, -2.8); - try test_fmodq(-6.8, -4.0, -2.8); - try test_fmodq(3.0, 2.0, 1.0); - try test_fmodq(-5.0, 3.0, -2.0); - try test_fmodq(3.0, 2.0, 1.0); - try test_fmodq(1.0, 2.0, 1.0); - try test_fmodq(0.0, 1.0, 0.0); - try test_fmodq(-0.0, 1.0, -0.0); - try test_fmodq(7046119.0, 5558362.0, 1487757.0); - try test_fmodq(9010357.0, 1957236.0, 1181413.0); - try test_fmodq(5192296858534827628530496329220095, 10.0, 5.0); - try test_fmodq(5192296858534827628530496329220095, 922337203681230954775807, 220474884073715748246157); +test fmod_f128 { + try test_fmod_f128(6.8, 4.0, 2.8); + try test_fmod_f128(6.8, -4.0, 2.8); + try test_fmod_f128(-6.8, 4.0, -2.8); + try test_fmod_f128(-6.8, -4.0, -2.8); + try test_fmod_f128(3.0, 2.0, 1.0); + try test_fmod_f128(-5.0, 3.0, -2.0); + try test_fmod_f128(3.0, 2.0, 1.0); + try test_fmod_f128(1.0, 2.0, 1.0); + try test_fmod_f128(0.0, 1.0, 0.0); + try test_fmod_f128(-0.0, 1.0, -0.0); + try test_fmod_f128(7046119.0, 5558362.0, 1487757.0); + try test_fmod_f128(9010357.0, 1957236.0, 1181413.0); + try test_fmod_f128(5192296858534827628530496329220095, 10.0, 5.0); + try test_fmod_f128(5192296858534827628530496329220095, 922337203681230954775807, 220474884073715748246157); // Denormals const a1: f128 = 0xedcb34a235253948765432134674p-16494; const b1: f128 = 0x5d2e38791cfbc0737402da5a9518p-16494; const exp1: f128 = 0x336ec3affb2db8618e4e7d5e1c44p-16494; - try test_fmodq(a1, b1, exp1); + try test_fmod_f128(a1, b1, exp1); const a2: f128 = 0x0.7654_3210_fdec_ba98_7654_3210_fdecp-16382; const b2: f128 = 0x0.0012_fdac_bdef_1234_fdec_3222_1111p-16382; const exp2: f128 = 0x0.0001_aecd_9d66_4a6e_67b7_d7d0_a901p-16382; - try test_fmodq(a2, b2, exp2); + try test_fmod_f128(a2, b2, exp2); - try test_fmodq_nans(); - try test_fmodq_infs(); + try test_fmod_f128_nans(); + try test_fmod_f128_infs(); } diff --git a/lib/compiler_rt/fmodx_test.zig b/lib/compiler_rt/fmodx_test.zig index ca8229147ab693264b555676af664e7bf8acccbc..b32d354094ed97a1ab8d7c9d840610b9a8ac12a7 100644 --- a/lib/compiler_rt/fmodx_test.zig +++ b/lib/compiler_rt/fmodx_test.zig @@ -1,52 +1,52 @@ const std = @import("std"); const builtin = @import("builtin"); -const fmod = @import("fmod.zig"); +const fmod_f80 = @import("fmod.zig").fmod_f80; const testing = std.testing; -fn test_fmodx(a: f80, b: f80, exp: f80) !void { - const res = fmod.__fmodx(a, b); +fn test_fmod_f80(a: f80, b: f80, exp: f80) !void { + const res = fmod_f80(a, b); try testing.expect(exp == res); } -fn test_fmodx_nans() !void { - try testing.expect(std.math.isNan(fmod.__fmodx(1.0, std.math.nan(f80)))); - try testing.expect(std.math.isNan(fmod.__fmodx(1.0, -std.math.nan(f80)))); - try testing.expect(std.math.isNan(fmod.__fmodx(std.math.nan(f80), 1.0))); - try testing.expect(std.math.isNan(fmod.__fmodx(-std.math.nan(f80), 1.0))); +fn test_fmod_f80_nans() !void { + try testing.expect(std.math.isNan(fmod_f80(1.0, std.math.nan(f80)))); + try testing.expect(std.math.isNan(fmod_f80(1.0, -std.math.nan(f80)))); + try testing.expect(std.math.isNan(fmod_f80(std.math.nan(f80), 1.0))); + try testing.expect(std.math.isNan(fmod_f80(-std.math.nan(f80), 1.0))); } -fn test_fmodx_infs() !void { - try testing.expect(fmod.__fmodx(1.0, std.math.inf(f80)) == 1.0); - try testing.expect(fmod.__fmodx(1.0, -std.math.inf(f80)) == 1.0); - try testing.expect(std.math.isNan(fmod.__fmodx(std.math.inf(f80), 1.0))); - try testing.expect(std.math.isNan(fmod.__fmodx(-std.math.inf(f80), 1.0))); +fn test_fmod_f80_infs() !void { + try testing.expect(fmod_f80(1.0, std.math.inf(f80)) == 1.0); + try testing.expect(fmod_f80(1.0, -std.math.inf(f80)) == 1.0); + try testing.expect(std.math.isNan(fmod_f80(std.math.inf(f80), 1.0))); + try testing.expect(std.math.isNan(fmod_f80(-std.math.inf(f80), 1.0))); } -test "fmodx" { - try test_fmodx(6.4, 4.0, 2.4); - try test_fmodx(6.4, -4.0, 2.4); - try test_fmodx(-6.4, 4.0, -2.4); - try test_fmodx(-6.4, -4.0, -2.4); - try test_fmodx(3.0, 2.0, 1.0); - try test_fmodx(-5.0, 3.0, -2.0); - try test_fmodx(3.0, 2.0, 1.0); - try test_fmodx(1.0, 2.0, 1.0); - try test_fmodx(0.0, 1.0, 0.0); - try test_fmodx(-0.0, 1.0, -0.0); - try test_fmodx(7046119.0, 5558362.0, 1487757.0); - try test_fmodx(9010357.0, 1957236.0, 1181413.0); - try test_fmodx(9223372036854775807, 10.0, 7.0); +test fmod_f80 { + try test_fmod_f80(6.4, 4.0, 2.4); + try test_fmod_f80(6.4, -4.0, 2.4); + try test_fmod_f80(-6.4, 4.0, -2.4); + try test_fmod_f80(-6.4, -4.0, -2.4); + try test_fmod_f80(3.0, 2.0, 1.0); + try test_fmod_f80(-5.0, 3.0, -2.0); + try test_fmod_f80(3.0, 2.0, 1.0); + try test_fmod_f80(1.0, 2.0, 1.0); + try test_fmod_f80(0.0, 1.0, 0.0); + try test_fmod_f80(-0.0, 1.0, -0.0); + try test_fmod_f80(7046119.0, 5558362.0, 1487757.0); + try test_fmod_f80(9010357.0, 1957236.0, 1181413.0); + try test_fmod_f80(9223372036854775807, 10.0, 7.0); // Denormals const a1: f80 = 0x0.76e5_9a51_1a92_9ca4p-16381; const b1: f80 = 0x0.2e97_1c3c_8e7d_e03ap-16381; const exp1: f80 = 0x0.19b7_61d7_fd96_dc30p-16381; - try test_fmodx(a1, b1, exp1); + try test_fmod_f80(a1, b1, exp1); const a2: f80 = 0x0.76e5_9a51_1a92_9ca4p-16381; const b2: f80 = 0x0.0e97_1c3c_8e7d_e03ap-16381; const exp2: f80 = 0x0.022c_b86c_a6a3_9ad4p-16381; - try test_fmodx(a2, b2, exp2); + try test_fmod_f80(a2, b2, exp2); - try test_fmodx_nans(); - try test_fmodx_infs(); + try test_fmod_f80_nans(); + try test_fmod_f80_infs(); } diff --git a/lib/compiler_rt/gedf2.zig b/lib/compiler_rt/gedf2.zig deleted file mode 100644 index f6b4b6d718fd20d8068244cfa6250f030f890e92..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/gedf2.zig +++ /dev/null @@ -1,35 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const comparef = @import("./comparef.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dcmpge, "__aeabi_dcmpge"); - symbol(&__aeabi_dcmpgt, "__aeabi_dcmpgt"); - } else { - symbol(&__gedf2, "__gedf2"); - symbol(&__gtdf2, "__gtdf2"); - } -} - -/// "These functions return a value greater than or equal to zero if neither -/// argument is NaN, and a is greater than or equal to b." -pub fn __gedf2(a: f64, b: f64) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f64, comparef.GE, a, b)); -} - -/// "These functions return a value greater than zero if neither argument is NaN, -/// and a is strictly greater than b." -pub fn __gtdf2(a: f64, b: f64) callconv(.c) i32 { - return __gedf2(a, b); -} - -fn __aeabi_dcmpge(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.GE, a, b) != .Less); -} - -fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f64, comparef.GE, a, b) == .Greater); -} diff --git a/lib/compiler_rt/gehf2.zig b/lib/compiler_rt/gehf2.zig deleted file mode 100644 index 8008a06849887d2f317be4517a5cb6c485c2675a..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/gehf2.zig +++ /dev/null @@ -1,21 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const symbol = @import("../compiler_rt.zig").symbol; -const comparef = @import("./comparef.zig"); - -comptime { - symbol(&__gehf2, "__gehf2"); - symbol(&__gthf2, "__gthf2"); -} - -/// "These functions return a value greater than or equal to zero if neither -/// argument is NaN, and a is greater than or equal to b." -pub fn __gehf2(a: f16, b: f16) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f16, comparef.GE, a, b)); -} - -/// "These functions return a value greater than zero if neither argument is NaN, -/// and a is strictly greater than b." -pub fn __gthf2(a: f16, b: f16) callconv(.c) i32 { - return __gehf2(a, b); -} diff --git a/lib/compiler_rt/gesf2.zig b/lib/compiler_rt/gesf2.zig deleted file mode 100644 index 7f5022104eba9378efe6184befcd7f40f479306f..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/gesf2.zig +++ /dev/null @@ -1,35 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const comparef = @import("./comparef.zig"); - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fcmpge, "__aeabi_fcmpge"); - symbol(&__aeabi_fcmpgt, "__aeabi_fcmpgt"); - } else { - symbol(&__gesf2, "__gesf2"); - symbol(&__gtsf2, "__gtsf2"); - } -} - -/// "These functions return a value greater than or equal to zero if neither -/// argument is NaN, and a is greater than or equal to b." -pub fn __gesf2(a: f32, b: f32) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f32, comparef.GE, a, b)); -} - -/// "These functions return a value greater than zero if neither argument is NaN, -/// and a is strictly greater than b." -pub fn __gtsf2(a: f32, b: f32) callconv(.c) i32 { - return __gesf2(a, b); -} - -fn __aeabi_fcmpge(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f32, comparef.GE, a, b) != .Less); -} - -fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) i32 { - return @intFromBool(comparef.cmpf2(f32, comparef.LE, a, b) == .Greater); -} diff --git a/lib/compiler_rt/getf2.zig b/lib/compiler_rt/getf2.zig deleted file mode 100644 index 88a91600f1e32c5f7124f5e9be9d5828b2471f2e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/getf2.zig +++ /dev/null @@ -1,26 +0,0 @@ -///! The quoted behavior definitions are from -///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const comparef = @import("./comparef.zig"); - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__getf2, "__gekf2"); - symbol(&__gttf2, "__gtkf2"); - } - symbol(&__getf2, "__getf2"); - symbol(&__gttf2, "__gttf2"); -} - -/// "These functions return a value greater than or equal to zero if neither -/// argument is NaN, and a is greater than or equal to b." -fn __getf2(a: f128, b: f128) callconv(.c) i32 { - return @backingInt(comparef.cmpf2(f128, comparef.GE, a, b)); -} - -/// "These functions return a value greater than zero if neither argument is NaN, -/// and a is strictly greater than b." -fn __gttf2(a: f128, b: f128) callconv(.c) i32 { - return __getf2(a, b); -} diff --git a/lib/compiler_rt/gexf2.zig b/lib/compiler_rt/gexf2.zig deleted file mode 100644 index 9f1f356187cdf9c7b85be2d49f9e2e73439f381b..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/gexf2.zig +++ /dev/null @@ -1,15 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const comparef = @import("./comparef.zig"); - -comptime { - symbol(&__gexf2, "__gexf2"); - symbol(&__gtxf2, "__gtxf2"); -} - -fn __gexf2(a: f80, b: f80) callconv(.c) i32 { - return @backingInt(comparef.cmp_f80(comparef.GE, a, b)); -} - -fn __gtxf2(a: f80, b: f80) callconv(.c) i32 { - return __gexf2(a, b); -} diff --git a/lib/compiler_rt/int.zig b/lib/compiler_rt/int.zig index 48c900207bce8946adf6bb9cafe9407b214946d4..e387be858213a7afb575bd3b81f62e016e16a19e 100644 --- a/lib/compiler_rt/int.zig +++ b/lib/compiler_rt/int.zig @@ -36,7 +36,7 @@ comptime { pub fn __divmodti4(a: i128, b: i128, rem: *i128) callconv(.c) i128 { const d = __divti3(a, b); - rem.* = a -% (d * b); + rem.* = a - d *% b; return d; } @@ -69,7 +69,7 @@ fn test_one_divmodti4(a: i128, b: i128, expected_q: i128, expected_r: i128) !voi pub fn __divmoddi4(a: i64, b: i64, rem: *i64) callconv(.c) i64 { const d = __divdi3(a, b); - rem.* = a -% (d * b); + rem.* = a - d *% b; return d; } @@ -79,21 +79,20 @@ fn test_one_divmoddi4(a: i64, b: i64, expected_q: i64, expected_r: i64) !void { try testing.expect(q == expected_q and r == expected_r); } -const cases__divmoddi4 = - [_][4]i64{ - [_]i64{ 0, 1, 0, 0 }, - [_]i64{ 0, -1, 0, 0 }, - [_]i64{ 2, 1, 2, 0 }, - [_]i64{ 2, -1, -2, 0 }, - [_]i64{ -2, 1, -2, 0 }, - [_]i64{ -2, -1, 2, 0 }, - [_]i64{ 7, 5, 1, 2 }, - [_]i64{ -7, 5, -1, -2 }, - [_]i64{ 19, 5, 3, 4 }, - [_]i64{ 19, -5, -3, 4 }, - [_]i64{ @as(i64, @bitCast(@as(u64, 0x8000000000000000))), 8, @as(i64, @bitCast(@as(u64, 0xf000000000000000))), 0 }, - [_]i64{ @as(i64, @bitCast(@as(u64, 0x8000000000000007))), 8, @as(i64, @bitCast(@as(u64, 0xf000000000000001))), -1 }, - }; +const cases__divmoddi4 = [_][4]i64{ + [_]i64{ 0, 1, 0, 0 }, + [_]i64{ 0, -1, 0, 0 }, + [_]i64{ 2, 1, 2, 0 }, + [_]i64{ 2, -1, -2, 0 }, + [_]i64{ -2, 1, -2, 0 }, + [_]i64{ -2, -1, 2, 0 }, + [_]i64{ 7, 5, 1, 2 }, + [_]i64{ -7, 5, -1, -2 }, + [_]i64{ 19, 5, 3, 4 }, + [_]i64{ 19, -5, -3, 4 }, + [_]i64{ @as(i64, @bitCast(@as(u64, 0x8000000000000000))), 8, @as(i64, @bitCast(@as(u64, 0xf000000000000000))), 0 }, + [_]i64{ @as(i64, @bitCast(@as(u64, 0x8000000000000007))), 8, @as(i64, @bitCast(@as(u64, 0xf000000000000001))), -1 }, +}; test "test_divmoddi4" { for (cases__divmoddi4) |case| { @@ -105,10 +104,6 @@ pub fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?*u64) callconv(.c) u64 { return udivmod(u64, a, b, maybe_rem); } -test "test_udivmoddi4" { - _ = @import("udivmoddi4_test.zig"); -} - pub fn __divdi3(a: i64, b: i64) callconv(.c) i64 { // Set aside the sign of the quotient. const sign: u64 = @bitCast((a ^ b) >> 63); @@ -209,25 +204,24 @@ fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) !void { pub fn __divmodsi4(a: i32, b: i32, rem: *i32) callconv(.c) i32 { const d = __divsi3(a, b); - rem.* = a -% (d * b); + rem.* = a - d *% b; return d; } -const cases__divmodsi4 = - [_][4]i32{ - [_]i32{ 0, 1, 0, 0 }, - [_]i32{ 0, -1, 0, 0 }, - [_]i32{ 2, 1, 2, 0 }, - [_]i32{ 2, -1, -2, 0 }, - [_]i32{ -2, 1, -2, 0 }, - [_]i32{ -2, -1, 2, 0 }, - [_]i32{ 7, 5, 1, 2 }, - [_]i32{ -7, 5, -1, -2 }, - [_]i32{ 19, 5, 3, 4 }, - [_]i32{ 19, -5, -3, 4 }, - [_]i32{ @bitCast(@as(u32, 0x80000000)), 8, @bitCast(@as(u32, 0xf0000000)), 0 }, - [_]i32{ @bitCast(@as(u32, 0x80000007)), 8, @bitCast(@as(u32, 0xf0000001)), -1 }, - }; +const cases__divmodsi4 = [_][4]i32{ + [_]i32{ 0, 1, 0, 0 }, + [_]i32{ 0, -1, 0, 0 }, + [_]i32{ 2, 1, 2, 0 }, + [_]i32{ 2, -1, -2, 0 }, + [_]i32{ -2, 1, -2, 0 }, + [_]i32{ -2, -1, 2, 0 }, + [_]i32{ 7, 5, 1, 2 }, + [_]i32{ -7, 5, -1, -2 }, + [_]i32{ 19, 5, 3, 4 }, + [_]i32{ 19, -5, -3, 4 }, + [_]i32{ @bitCast(@as(u32, 0x80000000)), 8, @bitCast(@as(u32, 0xf0000000)), 0 }, + [_]i32{ @bitCast(@as(u32, 0x80000007)), 8, @bitCast(@as(u32, 0xf0000001)), -1 }, +}; fn test_one_divmodsi4(a: i32, b: i32, expected_q: i32, expected_r: i32) !void { var r: i32 = undefined; @@ -243,7 +237,7 @@ test "test_divmodsi4" { pub fn __udivmodsi4(a: u32, b: u32, rem: *u32) callconv(.c) u32 { const d = __udivsi3(a, b); - rem.* = @bitCast(@as(i32, @bitCast(a)) -% (@as(i32, @bitCast(d)) * @as(i32, @bitCast(b)))); + rem.* = a - d * b; return d; } @@ -486,7 +480,7 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) !void { } pub fn __modsi3(n: i32, d: i32) callconv(.c) i32 { - return n -% __divsi3(n, d) * d; + return n - __divsi3(n, d) *% d; } test "test_modsi3" { @@ -515,7 +509,7 @@ fn test_one_modsi3(a: i32, b: i32, expected_r: i32) !void { } pub fn __umodsi3(n: u32, d: u32) callconv(.c) u32 { - return n -% __udivsi3(n, d) * d; + return n - __udivsi3(n, d) * d; } test "test_umodsi3" { @@ -663,3 +657,8 @@ fn test_one_umodsi3(a: u32, b: u32, expected_r: u32) !void { const r: u32 = __umodsi3(a, b); try testing.expect(r == expected_r); } + +test { + _ = @import("udivmodsi4_test.zig"); + _ = @import("udivmoddi4_test.zig"); +} diff --git a/lib/compiler_rt/int_from_float.zig b/lib/compiler_rt/int_from_float.zig index 5445e7fb7c6d36111d89112350b5bfc9ced375c8..20d87eb3f9b927b41a5e59aea8602405ffdb0b58 100644 --- a/lib/compiler_rt/int_from_float.zig +++ b/lib/compiler_rt/int_from_float.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("std"); const math = std.math; const Log2Int = std.math.Log2Int; @@ -6,29 +7,532 @@ const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; comptime { - symbol(&__fixxfti, "__fixxfti"); symbol(&__fixhfsi, "__fixhfsi"); symbol(&__fixhfdi, "__fixhfdi"); symbol(&__fixhfti, "__fixhfti"); + symbol(&__fixhfei, "__fixhfei"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_f2iz, "__aeabi_f2iz"); + symbol(&__aeabi_f2lz, "__aeabi_f2lz"); + symbol(&__aeabi_fixsfti, "__fixsfti"); + } else { + symbol(&__fixsfsi, "__fixsfsi"); + symbol(&__fixsfdi, "__fixsfdi"); + if (compiler_rt.want_windows_arm_abi) symbol(&__fixsfdi, "__stoi64"); + symbol(&__fixsfti, "__fixsfti"); + } + symbol(&__fixsfei, "__fixsfei"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_d2iz, "__aeabi_d2iz"); + symbol(&__aeabi_d2lz, "__aeabi_d2lz"); + symbol(&__aeabi_fixdfti, "__fixdfti"); + } else { + symbol(&__fixdfsi, "__fixdfsi"); + symbol(&__fixdfdi, "__fixdfdi"); + if (compiler_rt.want_windows_arm_abi) symbol(&__fixdfdi, "__dtoi64"); + symbol(&__fixdfti, "__fixdfti"); + } + symbol(&__fixdfei, "__fixdfei"); + + symbol(&__fixxfsi, "__fixxfsi"); + symbol(&__fixxfdi, "__fixxfdi"); + symbol(&__fixxfti, "__fixxfti"); + symbol(&__fixxfei, "__fixxfei"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__fixtfsi, "__fixkfsi"); + symbol(&__fixtfdi, "__fixkfdi"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_qtoi, "_Qp_qtoi"); + symbol(&_Qp_qtox, "_Qp_qtox"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__fixtfsi, "_Q_qtoi"); + symbol(&__fixtfdi, "_Q_qtoll"); + } else { + symbol(&__fixtfsi, "__fixtfsi"); + symbol(&__fixtfdi, "__fixtfdi"); + } + if (compiler_rt.want_ppc_abi) { + symbol(&__fixtfti, "__fixkfti"); + symbol(&__fixtfei, "__fixkfei"); + } else { + symbol(&__fixtfti, "__fixtfti"); + symbol(&__fixtfei, "__fixtfei"); + } +} + +fn __fixhfsi(a: compiler_rt.f16.Abi) callconv(.c) i32 { + return i32_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn i32_intFromFloat_f16(a: f16) i32 { + return intFromFloat(i32, a); } -pub fn __fixhfti(a: f16) callconv(.c) i128 { +fn __fixhfdi(a: compiler_rt.f16.Abi) callconv(.c) i64 { + return i64_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn i64_intFromFloat_f16(a: f16) i64 { + return intFromFloat(i64, a); +} + +fn __fixhfti(a: compiler_rt.f16.Abi) callconv(.c) i128 { + return i128_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn i128_intFromFloat_f16(a: f16) i128 { return intFromFloat(i128, a); } -fn __fixhfdi(a: f16) callconv(.c) i64 { +fn __fixhfei(r: [*]u8, bits: usize, a: compiler_rt.f16.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f16(r[0..byte_size], compiler_rt.f16.fromAbi(a)); +} +pub fn signed_intFromFloat_f16(result: []u8, a: f16) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +fn __fixsfsi(a: compiler_rt.f32.Abi) callconv(.c) i32 { + return i32_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_f2iz(a: f32) callconv(.{ .arm_aapcs = .{} }) i32 { + return i32_intFromFloat_f32(a); +} +pub fn i32_intFromFloat_f32(a: f32) i32 { + return intFromFloat(i32, a); +} + +fn __fixsfdi(a: compiler_rt.f32.Abi) callconv(.c) i64 { + return i64_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_f2lz(a: f32) callconv(.{ .arm_aapcs = .{} }) i64 { + return i64_intFromFloat_f32(a); +} +pub fn i64_intFromFloat_f32(a: f32) i64 { return intFromFloat(i64, a); } -fn __fixhfsi(a: f16) callconv(.c) i32 { +fn __fixsfti(a: compiler_rt.f32.Abi) callconv(.c) i128 { + return i128_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_fixsfti(_: compiler_rt.f32.Abi) callconv(.naked) i128 { + switch (builtin.abi.float()) { + .soft => asm volatile ( + \\ push {r0-r4, lr} + \\ movs r1, r0 + \\ mov r0, sp + \\ bl %[__fixsfti] + \\ pop {r0-r4, pc} + : + : [__fixsfti] "X" (&__fixsfti), + ), + .hard => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r0, sp + \\ bl %[__fixsfti] + \\ pop {r0-r4, pc} + : + : [__fixsfti] "X" (&__fixsfti), + ), + } +} +pub fn i128_intFromFloat_f32(a: f32) i128 { + return intFromFloat(i128, a); +} + +fn __fixsfei(r: [*]u8, bits: usize, a: compiler_rt.f32.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f32(r[0..byte_size], compiler_rt.f32.fromAbi(a)); +} +pub fn signed_intFromFloat_f32(result: []u8, a: f32) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +fn __fixdfsi(a: compiler_rt.f64.Abi) callconv(.c) i32 { + return i32_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_d2iz(a: f64) callconv(.{ .arm_aapcs = .{} }) i32 { + return i32_intFromFloat_f64(a); +} +pub fn i32_intFromFloat_f64(a: f64) i32 { return intFromFloat(i32, a); } -pub fn __fixxfti(a: f80) callconv(.c) i128 { +fn __fixdfdi(a: compiler_rt.f64.Abi) callconv(.c) i64 { + return i64_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_d2lz(a: f64) callconv(.{ .arm_aapcs = .{} }) i64 { + return i64_intFromFloat_f64(a); +} +pub fn i64_intFromFloat_f64(a: f64) i64 { + return intFromFloat(i64, a); +} + +fn __fixdfti(a: compiler_rt.f64.Abi) callconv(.c) i128 { + return i128_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_fixdfti(_: compiler_rt.f64.Abi) callconv(.naked) i128 { + switch (builtin.abi.float()) { + .soft => asm volatile ( + \\ push {r0-r4, lr} + \\ movs r3, r1 + \\ movs r2, r0 + \\ mov r0, sp + \\ bl %[__fixdfti] + \\ pop {r0-r4, pc} + : + : [__fixdfti] "X" (&__fixdfti), + ), + .hard => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r0, sp + \\ bl %[__fixdfti] + \\ pop {r0-r4, pc} + : + : [__fixdfti] "X" (&__fixdfti), + ), + } +} +pub fn i128_intFromFloat_f64(a: f64) i128 { return intFromFloat(i128, a); } -pub inline fn intFromFloat(comptime I: type, a: anytype) I { +fn __fixdfei(r: [*]u8, bits: usize, a: compiler_rt.f64.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f64(r[0..byte_size], compiler_rt.f64.fromAbi(a)); +} +pub fn signed_intFromFloat_f64(result: []u8, a: f64) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +fn __fixxfsi(a: compiler_rt.f80.Abi) callconv(.c) i32 { + return i32_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn i32_intFromFloat_f80(a: f80) i32 { + return intFromFloat(i32, a); +} + +fn __fixxfdi(a: compiler_rt.f80.Abi) callconv(.c) i64 { + return i64_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn i64_intFromFloat_f80(a: f80) i64 { + return intFromFloat(i64, a); +} + +fn __fixxfti(a: compiler_rt.f80.Abi) callconv(.c) i128 { + return i128_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn i128_intFromFloat_f80(a: f80) i128 { + return intFromFloat(i128, a); +} + +fn __fixxfei(r: [*]u8, bits: usize, a: compiler_rt.f80.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f80(r[0..byte_size], compiler_rt.f80.fromAbi(a)); +} +pub fn signed_intFromFloat_f80(result: []u8, a: f80) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +fn __fixtfsi(a: compiler_rt.f128.Abi) callconv(.c) i32 { + return i32_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +fn _Qp_qtoi(a: *const f128) callconv(.c) i32 { + return i32_intFromFloat_f128(a.*); +} +pub fn i32_intFromFloat_f128(a: f128) i32 { + return intFromFloat(i32, a); +} + +fn __fixtfdi(a: compiler_rt.f128.Abi) callconv(.c) i64 { + return i64_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +fn _Qp_qtox(a: *const f128) callconv(.c) i64 { + return i64_intFromFloat_f128(a.*); +} +pub fn i64_intFromFloat_f128(a: f128) i64 { + return intFromFloat(i64, a); +} + +fn __fixtfti(a: compiler_rt.f128.Abi) callconv(.c) i128 { + return i128_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +pub fn i128_intFromFloat_f128(a: f128) i128 { + return intFromFloat(i128, a); +} + +fn __fixtfei(r: [*]u8, bits: usize, a: compiler_rt.f128.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return signed_intFromFloat_f128(r[0..byte_size], compiler_rt.f128.fromAbi(a)); +} +pub fn signed_intFromFloat_f128(result: []u8, a: f128) void { + bigIntFromFloat(.signed, @ptrCast(@alignCast(result)), a); +} + +comptime { + symbol(&__fixunshfsi, "__fixunshfsi"); + symbol(&__fixunshfdi, "__fixunshfdi"); + symbol(&__fixunshfti, "__fixunshfti"); + symbol(&__fixunshfei, "__fixunshfei"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_f2uiz, "__aeabi_f2uiz"); + symbol(&__aeabi_f2ulz, "__aeabi_f2ulz"); + symbol(&__aeabi_fixunssfti, "__fixunssfti"); + } else { + symbol(&__fixunssfsi, "__fixunssfsi"); + symbol(&__fixunssfdi, "__fixunssfdi"); + if (compiler_rt.want_windows_arm_abi) symbol(&__fixunssfdi, "__stou64"); + symbol(&__fixunssfti, "__fixunssfti"); + } + symbol(&__fixunssfei, "__fixunssfei"); + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_d2uiz, "__aeabi_d2uiz"); + symbol(&__aeabi_d2ulz, "__aeabi_d2ulz"); + symbol(&__aeabi_fixunsdfti, "__fixunsdfti"); + } else { + symbol(&__fixunsdfsi, "__fixunsdfsi"); + symbol(&__fixunsdfdi, "__fixunsdfdi"); + if (compiler_rt.want_windows_arm_abi) symbol(&__fixunsdfdi, "__dtou64"); + symbol(&__fixunsdfti, "__fixunsdfti"); + } + symbol(&__fixunsdfei, "__fixunsdfei"); + + symbol(&__fixunsxfsi, "__fixunsxfsi"); + symbol(&__fixunsxfdi, "__fixunsxfdi"); + symbol(&__fixunsxfti, "__fixunsxfti"); + symbol(&__fixunsxfei, "__fixunsxfei"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__fixunstfsi, "__fixunskfsi"); + symbol(&__fixunstfdi, "__fixunskfdi"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_qtoui, "_Qp_qtoui"); + symbol(&_Qp_qtoux, "_Qp_qtoux"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__fixunstfsi, "_Q_qtou"); + symbol(&__fixunstfdi, "_Q_qtoull"); + } else { + symbol(&__fixunstfsi, "__fixunstfsi"); + symbol(&__fixunstfdi, "__fixunstfdi"); + } + if (compiler_rt.want_ppc_abi) { + symbol(&__fixunstfti, "__fixunskfti"); + symbol(&__fixunstfei, "__fixunskfei"); + } else { + symbol(&__fixunstfti, "__fixunstfti"); + symbol(&__fixunstfei, "__fixunstfei"); + } +} + +fn __fixunshfsi(a: compiler_rt.f16.Abi) callconv(.c) u32 { + return u32_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn u32_intFromFloat_f16(a: f16) u32 { + return intFromFloat(u32, a); +} + +fn __fixunshfdi(a: compiler_rt.f16.Abi) callconv(.c) u64 { + return u64_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn u64_intFromFloat_f16(a: f16) u64 { + return intFromFloat(u64, a); +} + +fn __fixunshfti(a: compiler_rt.f16.Abi) callconv(.c) u128 { + return u128_intFromFloat_f16(compiler_rt.f16.fromAbi(a)); +} +pub fn u128_intFromFloat_f16(a: f16) u128 { + return intFromFloat(u128, a); +} + +fn __fixunshfei(r: [*]u8, bits: usize, a: compiler_rt.f16.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f16(r[0..byte_size], compiler_rt.f16.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f16(result: []u8, a: f16) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +fn __fixunssfsi(a: compiler_rt.f32.Abi) callconv(.c) u32 { + return u32_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_f2uiz(a: f32) callconv(.{ .arm_aapcs = .{} }) u32 { + return u32_intFromFloat_f32(a); +} +pub fn u32_intFromFloat_f32(a: f32) u32 { + return intFromFloat(u32, a); +} + +fn __fixunssfdi(a: compiler_rt.f32.Abi) callconv(.c) u64 { + return u64_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_f2ulz(a: f32) callconv(.{ .arm_aapcs = .{} }) u64 { + return u64_intFromFloat_f32(a); +} +pub fn u64_intFromFloat_f32(a: f32) u64 { + return intFromFloat(u64, a); +} + +fn __fixunssfti(a: compiler_rt.f32.Abi) callconv(.c) u128 { + return u128_intFromFloat_f32(compiler_rt.f32.fromAbi(a)); +} +fn __aeabi_fixunssfti(_: compiler_rt.f32.Abi) callconv(.naked) u128 { + switch (builtin.abi.float()) { + .soft => asm volatile ( + \\ push {r0-r4, lr} + \\ movs r1, r0 + \\ mov r0, sp + \\ bl %[__fixunssfti] + \\ pop {r0-r4, pc} + : + : [__fixunssfti] "X" (&__fixunssfti), + ), + .hard => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r0, sp + \\ bl %[__fixunssfti] + \\ pop {r0-r4, pc} + : + : [__fixunssfti] "X" (&__fixunssfti), + ), + } +} +pub fn u128_intFromFloat_f32(a: f32) u128 { + return intFromFloat(u128, a); +} + +fn __fixunssfei(r: [*]u8, bits: usize, a: compiler_rt.f32.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f32(r[0..byte_size], compiler_rt.f32.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f32(result: []u8, a: f32) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +fn __fixunsdfsi(a: compiler_rt.f64.Abi) callconv(.c) u32 { + return u32_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_d2uiz(a: f64) callconv(.{ .arm_aapcs = .{} }) u32 { + return u32_intFromFloat_f64(a); +} +pub fn u32_intFromFloat_f64(a: f64) u32 { + return intFromFloat(u32, a); +} + +fn __fixunsdfdi(a: compiler_rt.f64.Abi) callconv(.c) u64 { + return u64_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_d2ulz(a: f64) callconv(.{ .arm_aapcs = .{} }) u64 { + return u64_intFromFloat_f64(a); +} +pub fn u64_intFromFloat_f64(a: f64) u64 { + return intFromFloat(u64, a); +} + +fn __fixunsdfti(a: compiler_rt.f64.Abi) callconv(.c) u128 { + return u128_intFromFloat_f64(compiler_rt.f64.fromAbi(a)); +} +fn __aeabi_fixunsdfti(_: compiler_rt.f64.Abi) callconv(.naked) u128 { + switch (builtin.abi.float()) { + .soft => asm volatile ( + \\ push {r0-r4, lr} + \\ movs r3, r1 + \\ movs r2, r0 + \\ mov r0, sp + \\ bl %[__fixunsdfti] + \\ pop {r0-r4, pc} + : + : [__fixunsdfti] "X" (&__fixunsdfti), + ), + .hard => asm volatile ( + \\ push {r0-r4, lr} + \\ mov r0, sp + \\ bl %[__fixunsdfti] + \\ pop {r0-r4, pc} + : + : [__fixunsdfti] "X" (&__fixunsdfti), + ), + } +} +pub fn u128_intFromFloat_f64(a: f64) u128 { + return intFromFloat(u128, a); +} + +fn __fixunsdfei(r: [*]u8, bits: usize, a: compiler_rt.f64.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f64(r[0..byte_size], compiler_rt.f64.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f64(result: []u8, a: f64) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +fn __fixunsxfsi(a: compiler_rt.f80.Abi) callconv(.c) u32 { + return u32_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn u32_intFromFloat_f80(a: f80) u32 { + return intFromFloat(u32, a); +} + +fn __fixunsxfdi(a: compiler_rt.f80.Abi) callconv(.c) u64 { + return u64_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn u64_intFromFloat_f80(a: f80) u64 { + return intFromFloat(u64, a); +} + +fn __fixunsxfti(a: compiler_rt.f80.Abi) callconv(.c) u128 { + return u128_intFromFloat_f80(compiler_rt.f80.fromAbi(a)); +} +pub fn u128_intFromFloat_f80(a: f80) u128 { + return intFromFloat(u128, a); +} + +fn __fixunsxfei(r: [*]u8, bits: usize, a: compiler_rt.f80.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f80(r[0..byte_size], compiler_rt.f80.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f80(result: []u8, a: f80) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +fn __fixunstfsi(a: compiler_rt.f128.Abi) callconv(.c) u32 { + return u32_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +fn _Qp_qtoui(a: *const f128) callconv(.c) u32 { + return u32_intFromFloat_f128(a.*); +} +pub fn u32_intFromFloat_f128(a: f128) u32 { + return intFromFloat(u32, a); +} + +fn __fixunstfdi(a: compiler_rt.f128.Abi) callconv(.c) u64 { + return u64_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +fn _Qp_qtoux(a: *const f128) callconv(.c) u64 { + return u64_intFromFloat_f128(a.*); +} +pub fn u64_intFromFloat_f128(a: f128) u64 { + return intFromFloat(u64, a); +} + +fn __fixunstfti(a: compiler_rt.f128.Abi) callconv(.c) u128 { + return u128_intFromFloat_f128(compiler_rt.f128.fromAbi(a)); +} +pub fn u128_intFromFloat_f128(a: f128) u128 { + return intFromFloat(u128, a); +} + +fn __fixunstfei(r: [*]u8, bits: usize, a: compiler_rt.f128.Abi) callconv(.c) void { + const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); + return unsigned_intFromFloat_f128(r[0..byte_size], compiler_rt.f128.fromAbi(a)); +} +pub fn unsigned_intFromFloat_f128(result: []u8, a: f128) void { + bigIntFromFloat(.unsigned, @ptrCast(@alignCast(result)), a); +} + +inline fn intFromFloat(comptime I: type, a: anytype) I { const F = @TypeOf(a); const float_bits = @typeInfo(F).float.bits; const int_bits = @typeInfo(I).int.bits; @@ -76,13 +580,14 @@ pub inline fn intFromFloat(comptime I: type, a: anytype) I { return result; } -pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, result: []u32, a: anytype) void { +inline fn bigIntFromFloat(comptime signedness: std.lang.Signedness, result: []u32, a: anytype) void { + const endian = builtin.cpu.arch.endian(); switch (result.len) { 0 => return, inline 1...4 => |limbs_len| { const I = @Int(signedness, 32 * limbs_len); const low_to_high: [limbs_len]u32 = @bitCast(@as(I, @intFromFloat(a))); - result[0..limbs_len].* = switch (@import("builtin").cpu.arch.endian()) { + result[0..limbs_len].* = switch (endian) { .little => low_to_high, .big => switch (limbs_len) { 1 => .{low_to_high[0]}, @@ -111,7 +616,6 @@ pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, resul }); switch (signedness) { .signed => { - const endian = @import("builtin").cpu.arch.endian(); const exponent_limb = switch (endian) { .little => exponent / 32, .big => result.len - 1 - exponent / 32, diff --git a/lib/compiler_rt/int_from_float_test.zig b/lib/compiler_rt/int_from_float_test.zig index de96954dd15474c6d9f9c5109c717b3d5b6417c2..23f04e2b88a2a01756ad608cb2d9774b54d38c25 100644 --- a/lib/compiler_rt/int_from_float_test.zig +++ b/lib/compiler_rt/int_from_float_test.zig @@ -2,1023 +2,1039 @@ const std = @import("std"); const testing = std.testing; const math = std.math; -const __fixunshfti = @import("fixunshfti.zig").__fixunshfti; -const __fixunsxfti = @import("fixunsxfti.zig").__fixunsxfti; - -// Conversion from f32 -const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; -const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; -const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; -const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; -const __fixsfti = @import("fixsfti.zig").__fixsfti; -const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; -const __fixsfei = @import("fixsfei.zig").__fixsfei; -const __fixunssfei = @import("fixunssfei.zig").__fixunssfei; - -// Conversion from f64 -const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; -const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; -const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; -const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; -const __fixdfti = @import("fixdfti.zig").__fixdfti; -const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; -const __fixdfei = @import("fixdfei.zig").__fixdfei; -const __fixunsdfei = @import("fixunsdfei.zig").__fixunsdfei; - -// Conversion from f128 -const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; -const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; -const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; -const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; -const __fixtfti = @import("fixtfti.zig").__fixtfti; -const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; - -fn test__fixsfsi(a: f32, expected: i32) !void { - const x = __fixsfsi(a); +const impl = @import("int_from_float.zig"); + +const i32_intFromFloat_f16 = impl.i32_intFromFloat_f16; +const u32_intFromFloat_f16 = impl.u32_intFromFloat_f16; +const i64_intFromFloat_f16 = impl.i64_intFromFloat_f16; +const u64_intFromFloat_f16 = impl.u64_intFromFloat_f16; +const i128_intFromFloat_f16 = impl.i128_intFromFloat_f16; +const u128_intFromFloat_f16 = impl.u128_intFromFloat_f16; +const signed_intFromFloat_f16 = impl.signed_intFromFloat_f16; +const unsigned_intFromFloat_f16 = impl.unsigned_intFromFloat_f16; + +const i32_intFromFloat_f32 = impl.i32_intFromFloat_f32; +const u32_intFromFloat_f32 = impl.u32_intFromFloat_f32; +const i64_intFromFloat_f32 = impl.i64_intFromFloat_f32; +const u64_intFromFloat_f32 = impl.u64_intFromFloat_f32; +const i128_intFromFloat_f32 = impl.i128_intFromFloat_f32; +const u128_intFromFloat_f32 = impl.u128_intFromFloat_f32; +const signed_intFromFloat_f32 = impl.signed_intFromFloat_f32; +const unsigned_intFromFloat_f32 = impl.unsigned_intFromFloat_f32; + +const i32_intFromFloat_f64 = impl.i32_intFromFloat_f64; +const u32_intFromFloat_f64 = impl.u32_intFromFloat_f64; +const i64_intFromFloat_f64 = impl.i64_intFromFloat_f64; +const u64_intFromFloat_f64 = impl.u64_intFromFloat_f64; +const i128_intFromFloat_f64 = impl.i128_intFromFloat_f64; +const u128_intFromFloat_f64 = impl.u128_intFromFloat_f64; +const signed_intFromFloat_f64 = impl.signed_intFromFloat_f64; +const unsigned_intFromFloat_f64 = impl.unsigned_intFromFloat_f64; + +const i32_intFromFloat_f80 = impl.i32_intFromFloat_f80; +const u32_intFromFloat_f80 = impl.u32_intFromFloat_f80; +const i64_intFromFloat_f80 = impl.i64_intFromFloat_f80; +const u64_intFromFloat_f80 = impl.u64_intFromFloat_f80; +const i128_intFromFloat_f80 = impl.i128_intFromFloat_f80; +const u128_intFromFloat_f80 = impl.u128_intFromFloat_f80; +const signed_intFromFloat_f80 = impl.signed_intFromFloat_f80; +const unsigned_intFromFloat_f80 = impl.unsigned_intFromFloat_f80; + +const i32_intFromFloat_f128 = impl.i32_intFromFloat_f128; +const u32_intFromFloat_f128 = impl.u32_intFromFloat_f128; +const i64_intFromFloat_f128 = impl.i64_intFromFloat_f128; +const u64_intFromFloat_f128 = impl.u64_intFromFloat_f128; +const i128_intFromFloat_f128 = impl.i128_intFromFloat_f128; +const u128_intFromFloat_f128 = impl.u128_intFromFloat_f128; +const signed_intFromFloat_f128 = impl.signed_intFromFloat_f128; +const unsigned_intFromFloat_f128 = impl.unsigned_intFromFloat_f128; + +fn test_i32_intFromFloat_f32(a: f32, expected: i32) !void { + const x = i32_intFromFloat_f32(a); try testing.expect(x == expected); } -fn test__fixunssfsi(a: f32, expected: u32) !void { - const x = __fixunssfsi(a); +fn test_u32_intFromFloat_f32(a: f32, expected: u32) !void { + const x = u32_intFromFloat_f32(a); try testing.expect(x == expected); } -test "fixsfsi" { - try test__fixsfsi(-math.floatMax(f32), math.minInt(i32)); - - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); - - try test__fixsfsi(-0x1.0000000000000p+127, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); - - try test__fixsfsi(-0x1.0000000000001p+63, -0x80000000); - try test__fixsfsi(-0x1.0000000000000p+63, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); - - try test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000); - try test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000); - - try test__fixsfsi(-0x1.000000p+31, -0x80000000); - try test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000); - try test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixsfsi(-2.01, -2); - try test__fixsfsi(-2.0, -2); - try test__fixsfsi(-1.99, -1); - try test__fixsfsi(-1.0, -1); - try test__fixsfsi(-0.99, 0); - try test__fixsfsi(-0.5, 0); - - try test__fixsfsi(-math.floatMin(f32), 0); - try test__fixsfsi(0.0, 0); - try test__fixsfsi(math.floatMin(f32), 0); - try test__fixsfsi(0.5, 0); - try test__fixsfsi(0.99, 0); - try test__fixsfsi(1.0, 1); - try test__fixsfsi(1.5, 1); - try test__fixsfsi(1.99, 1); - try test__fixsfsi(2.0, 2); - try test__fixsfsi(2.01, 2); - - try test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF); - try test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); - try test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF); - try test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); - try test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF); - - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); - try test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); - - try test__fixsfsi(math.floatMax(f32), math.maxInt(i32)); -} - -test "fixunssfsi" { - try test__fixunssfsi(0.0, 0); - - try test__fixunssfsi(0.5, 0); - try test__fixunssfsi(0.99, 0); - try test__fixunssfsi(1.0, 1); - try test__fixunssfsi(1.5, 1); - try test__fixunssfsi(1.99, 1); - try test__fixunssfsi(2.0, 2); - try test__fixunssfsi(2.01, 2); - try test__fixunssfsi(-0.5, 0); - try test__fixunssfsi(-0.99, 0); - - try test__fixunssfsi(-1.0, 0); - try test__fixunssfsi(-1.5, 0); - try test__fixunssfsi(-1.99, 0); - try test__fixunssfsi(-2.0, 0); - try test__fixunssfsi(-2.01, 0); - - try test__fixunssfsi(0x1.000000p+31, 0x80000000); - try test__fixunssfsi(0x1.000000p+32, 0xFFFFFFFF); - try test__fixunssfsi(0x1.FFFFFEp+31, 0xFFFFFF00); - try test__fixunssfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixunssfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - - try test__fixunssfsi(-0x1.FFFFFEp+30, 0); - try test__fixunssfsi(-0x1.FFFFFCp+30, 0); -} - -fn test__fixsfdi(a: f32, expected: i64) !void { - const x = __fixsfdi(a); +test i32_intFromFloat_f32 { + try test_i32_intFromFloat_f32(-math.floatMax(f32), math.minInt(i32)); + + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + try test_i32_intFromFloat_f32(-0x1.0000000000000p+127, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + try test_i32_intFromFloat_f32(-0x1.0000000000001p+63, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.0000000000000p+63, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + try test_i32_intFromFloat_f32(-0x1.FFFFFEp+62, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFCp+62, -0x80000000); + + try test_i32_intFromFloat_f32(-0x1.000000p+31, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFFp+30, -0x80000000); + try test_i32_intFromFloat_f32(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test_i32_intFromFloat_f32(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test_i32_intFromFloat_f32(-2.01, -2); + try test_i32_intFromFloat_f32(-2.0, -2); + try test_i32_intFromFloat_f32(-1.99, -1); + try test_i32_intFromFloat_f32(-1.0, -1); + try test_i32_intFromFloat_f32(-0.99, 0); + try test_i32_intFromFloat_f32(-0.5, 0); + + try test_i32_intFromFloat_f32(-math.floatMin(f32), 0); + try test_i32_intFromFloat_f32(0.0, 0); + try test_i32_intFromFloat_f32(math.floatMin(f32), 0); + try test_i32_intFromFloat_f32(0.5, 0); + try test_i32_intFromFloat_f32(0.99, 0); + try test_i32_intFromFloat_f32(1.0, 1); + try test_i32_intFromFloat_f32(1.5, 1); + try test_i32_intFromFloat_f32(1.99, 1); + try test_i32_intFromFloat_f32(2.0, 2); + try test_i32_intFromFloat_f32(2.01, 2); + + try test_i32_intFromFloat_f32(0x1.FFFFFCp+30, 0x7FFFFF00); + try test_i32_intFromFloat_f32(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i32_intFromFloat_f32(0x1.FFFFFFp+30, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.000000p+31, 0x7FFFFFFF); + + try test_i32_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFFFF); + + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.0000000000000p+63, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.0000000000001p+63, 0x7FFFFFFF); + + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.0000000000000p+127, 0x7FFFFFFF); + + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + try test_i32_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + try test_i32_intFromFloat_f32(math.floatMax(f32), math.maxInt(i32)); +} + +test u32_intFromFloat_f32 { + try test_u32_intFromFloat_f32(0.0, 0); + + try test_u32_intFromFloat_f32(0.5, 0); + try test_u32_intFromFloat_f32(0.99, 0); + try test_u32_intFromFloat_f32(1.0, 1); + try test_u32_intFromFloat_f32(1.5, 1); + try test_u32_intFromFloat_f32(1.99, 1); + try test_u32_intFromFloat_f32(2.0, 2); + try test_u32_intFromFloat_f32(2.01, 2); + try test_u32_intFromFloat_f32(-0.5, 0); + try test_u32_intFromFloat_f32(-0.99, 0); + + try test_u32_intFromFloat_f32(-1.0, 0); + try test_u32_intFromFloat_f32(-1.5, 0); + try test_u32_intFromFloat_f32(-1.99, 0); + try test_u32_intFromFloat_f32(-2.0, 0); + try test_u32_intFromFloat_f32(-2.01, 0); + + try test_u32_intFromFloat_f32(0x1.000000p+31, 0x80000000); + try test_u32_intFromFloat_f32(0x1.000000p+32, 0xFFFFFFFF); + try test_u32_intFromFloat_f32(0x1.FFFFFEp+31, 0xFFFFFF00); + try test_u32_intFromFloat_f32(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_u32_intFromFloat_f32(0x1.FFFFFCp+30, 0x7FFFFF00); + + try test_u32_intFromFloat_f32(-0x1.FFFFFEp+30, 0); + try test_u32_intFromFloat_f32(-0x1.FFFFFCp+30, 0); +} + +fn test_i64_intFromFloat_f32(a: f32, expected: i64) !void { + const x = i64_intFromFloat_f32(a); try testing.expect(x == expected); } -fn test__fixunssfdi(a: f32, expected: u64) !void { - const x = __fixunssfdi(a); +fn test_u64_intFromFloat_f32(a: f32, expected: u64) !void { + const x = u64_intFromFloat_f32(a); try testing.expect(x == expected); } -test "fixsfdi" { - try test__fixsfdi(-math.floatMax(f32), math.minInt(i64)); - - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); - - try test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); - - try test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); - - try test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000); - try test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixsfdi(-2.01, -2); - try test__fixsfdi(-2.0, -2); - try test__fixsfdi(-1.99, -1); - try test__fixsfdi(-1.0, -1); - try test__fixsfdi(-0.99, 0); - try test__fixsfdi(-0.5, 0); - try test__fixsfdi(-math.floatMin(f32), 0); - try test__fixsfdi(0.0, 0); - try test__fixsfdi(math.floatMin(f32), 0); - try test__fixsfdi(0.5, 0); - try test__fixsfdi(0.99, 0); - try test__fixsfdi(1.0, 1); - try test__fixsfdi(1.5, 1); - try test__fixsfdi(1.99, 1); - try test__fixsfdi(2.0, 2); - try test__fixsfdi(2.01, 2); - - try test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); - - try test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); - - try test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); - - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); - try test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); - - try test__fixsfdi(math.floatMax(f32), math.maxInt(i64)); -} - -test "fixunssfdi" { - try test__fixunssfdi(0.0, 0); - - try test__fixunssfdi(0.5, 0); - try test__fixunssfdi(0.99, 0); - try test__fixunssfdi(1.0, 1); - try test__fixunssfdi(1.5, 1); - try test__fixunssfdi(1.99, 1); - try test__fixunssfdi(2.0, 2); - try test__fixunssfdi(2.01, 2); - try test__fixunssfdi(-0.5, 0); - try test__fixunssfdi(-0.99, 0); - - try test__fixunssfdi(-1.0, 0); - try test__fixunssfdi(-1.5, 0); - try test__fixunssfdi(-1.99, 0); - try test__fixunssfdi(-2.0, 0); - try test__fixunssfdi(-2.01, 0); - - try test__fixunssfdi(0x1.FFFFFEp+63, 0xFFFFFF0000000000); - try test__fixunssfdi(0x1.000000p+63, 0x8000000000000000); - try test__fixunssfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunssfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunssfdi(-0x1.FFFFFEp+62, 0x0000000000000000); - try test__fixunssfdi(-0x1.FFFFFCp+62, 0x0000000000000000); -} - -fn test__fixsfti(a: f32, expected: i128) !void { - const x = __fixsfti(a); +test i64_intFromFloat_f32 { + try test_i64_intFromFloat_f32(-math.floatMax(f32), math.minInt(i64)); + + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + try test_i64_intFromFloat_f32(-0x1.0000000000000p+127, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + try test_i64_intFromFloat_f32(-0x1.0000000000001p+63, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + try test_i64_intFromFloat_f32(-0x1.FFFFFFp+62, -0x8000000000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i64_intFromFloat_f32(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i64_intFromFloat_f32(-2.01, -2); + try test_i64_intFromFloat_f32(-2.0, -2); + try test_i64_intFromFloat_f32(-1.99, -1); + try test_i64_intFromFloat_f32(-1.0, -1); + try test_i64_intFromFloat_f32(-0.99, 0); + try test_i64_intFromFloat_f32(-0.5, 0); + try test_i64_intFromFloat_f32(-math.floatMin(f32), 0); + try test_i64_intFromFloat_f32(0.0, 0); + try test_i64_intFromFloat_f32(math.floatMin(f32), 0); + try test_i64_intFromFloat_f32(0.5, 0); + try test_i64_intFromFloat_f32(0.99, 0); + try test_i64_intFromFloat_f32(1.0, 1); + try test_i64_intFromFloat_f32(1.5, 1); + try test_i64_intFromFloat_f32(1.99, 1); + try test_i64_intFromFloat_f32(2.0, 2); + try test_i64_intFromFloat_f32(2.01, 2); + + try test_i64_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i64_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_i64_intFromFloat_f32(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + try test_i64_intFromFloat_f32(math.floatMax(f32), math.maxInt(i64)); +} + +test u64_intFromFloat_f32 { + try test_u64_intFromFloat_f32(0.0, 0); + + try test_u64_intFromFloat_f32(0.5, 0); + try test_u64_intFromFloat_f32(0.99, 0); + try test_u64_intFromFloat_f32(1.0, 1); + try test_u64_intFromFloat_f32(1.5, 1); + try test_u64_intFromFloat_f32(1.99, 1); + try test_u64_intFromFloat_f32(2.0, 2); + try test_u64_intFromFloat_f32(2.01, 2); + try test_u64_intFromFloat_f32(-0.5, 0); + try test_u64_intFromFloat_f32(-0.99, 0); + + try test_u64_intFromFloat_f32(-1.0, 0); + try test_u64_intFromFloat_f32(-1.5, 0); + try test_u64_intFromFloat_f32(-1.99, 0); + try test_u64_intFromFloat_f32(-2.0, 0); + try test_u64_intFromFloat_f32(-2.01, 0); + + try test_u64_intFromFloat_f32(0x1.FFFFFEp+63, 0xFFFFFF0000000000); + try test_u64_intFromFloat_f32(0x1.000000p+63, 0x8000000000000000); + try test_u64_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u64_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test_u64_intFromFloat_f32(-0x1.FFFFFEp+62, 0x0000000000000000); + try test_u64_intFromFloat_f32(-0x1.FFFFFCp+62, 0x0000000000000000); +} + +fn test_i128_intFromFloat_f32(a: f32, expected: i128) !void { + const x = i128_intFromFloat_f32(a); try testing.expect(x == expected); } -fn test__fixunssfti(a: f32, expected: u128) !void { - const x = __fixunssfti(a); +fn test_u128_intFromFloat_f32(a: f32, expected: u128) !void { + const x = u128_intFromFloat_f32(a); try testing.expect(x == expected); } -test "fixsfti" { - try test__fixsfti(-math.floatMax(f32), math.minInt(i128)); - - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); - - try test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); - try test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); - try test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); - - try test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); - try test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); - - try test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000); - try test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixsfti(-0x1.000000p+31, -0x80000000); - try test__fixsfti(-0x1.FFFFFFp+30, -0x80000000); - try test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixsfti(-2.01, -2); - try test__fixsfti(-2.0, -2); - try test__fixsfti(-1.99, -1); - try test__fixsfti(-1.0, -1); - try test__fixsfti(-0.99, 0); - try test__fixsfti(-0.5, 0); - try test__fixsfti(-math.floatMin(f32), 0); - try test__fixsfti(0.0, 0); - try test__fixsfti(math.floatMin(f32), 0); - try test__fixsfti(0.5, 0); - try test__fixsfti(0.99, 0); - try test__fixsfti(1.0, 1); - try test__fixsfti(1.5, 1); - try test__fixsfti(1.99, 1); - try test__fixsfti(2.0, 2); - try test__fixsfti(2.01, 2); - - try test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixsfti(0x1.FFFFFFp+30, 0x80000000); - try test__fixsfti(0x1.000000p+31, 0x80000000); - - try test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000); - - try test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); - try test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); - try test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000); - - try test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); - try test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); - try test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); - - try test__fixsfti(math.floatMax(f32), math.maxInt(i128)); -} - -test "fixunssfti" { - try test__fixunssfti(0.0, 0); - - try test__fixunssfti(0.5, 0); - try test__fixunssfti(0.99, 0); - try test__fixunssfti(1.0, 1); - try test__fixunssfti(1.5, 1); - try test__fixunssfti(1.99, 1); - try test__fixunssfti(2.0, 2); - try test__fixunssfti(2.01, 2); - try test__fixunssfti(-0.5, 0); - try test__fixunssfti(-0.99, 0); - - try test__fixunssfti(-1.0, 0); - try test__fixunssfti(-1.5, 0); - try test__fixunssfti(-1.99, 0); - try test__fixunssfti(-2.0, 0); - try test__fixunssfti(-2.01, 0); - - try test__fixunssfti(0x1.FFFFFEp+63, 0xFFFFFF0000000000); - try test__fixunssfti(0x1.000000p+63, 0x8000000000000000); - try test__fixunssfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunssfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixunssfti(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000); - try test__fixunssfti(0x1.000000p+127, 0x80000000000000000000000000000000); - try test__fixunssfti(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000); - try test__fixunssfti(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000); - - try test__fixunssfti(-0x1.FFFFFEp+62, 0x0000000000000000); - try test__fixunssfti(-0x1.FFFFFCp+62, 0x0000000000000000); - try test__fixunssfti(-0x1.FFFFFEp+126, 0x0000000000000000); - try test__fixunssfti(-0x1.FFFFFCp+126, 0x0000000000000000); - try test__fixunssfti(math.floatMax(f32), 0xffffff00000000000000000000000000); - try test__fixunssfti(math.inf(f32), math.maxInt(u128)); -} - -fn test_fixsfei(comptime T: type, expected: T, a: f32) !void { +test i128_intFromFloat_f32 { + try test_i128_intFromFloat_f32(-math.floatMax(f32), math.minInt(i128)); + + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + try test_i128_intFromFloat_f32(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); + + try test_i128_intFromFloat_f32(-0x1.0000000000001p+63, -0x8000000000000000); + try test_i128_intFromFloat_f32(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + try test_i128_intFromFloat_f32(-0x1.FFFFFFp+62, -0x8000000000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i128_intFromFloat_f32(-0x1.000000p+31, -0x80000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFFp+30, -0x80000000); + try test_i128_intFromFloat_f32(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test_i128_intFromFloat_f32(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test_i128_intFromFloat_f32(-2.01, -2); + try test_i128_intFromFloat_f32(-2.0, -2); + try test_i128_intFromFloat_f32(-1.99, -1); + try test_i128_intFromFloat_f32(-1.0, -1); + try test_i128_intFromFloat_f32(-0.99, 0); + try test_i128_intFromFloat_f32(-0.5, 0); + try test_i128_intFromFloat_f32(-math.floatMin(f32), 0); + try test_i128_intFromFloat_f32(0.0, 0); + try test_i128_intFromFloat_f32(math.floatMin(f32), 0); + try test_i128_intFromFloat_f32(0.5, 0); + try test_i128_intFromFloat_f32(0.99, 0); + try test_i128_intFromFloat_f32(1.0, 1); + try test_i128_intFromFloat_f32(1.5, 1); + try test_i128_intFromFloat_f32(1.99, 1); + try test_i128_intFromFloat_f32(2.0, 2); + try test_i128_intFromFloat_f32(2.01, 2); + + try test_i128_intFromFloat_f32(0x1.FFFFFCp+30, 0x7FFFFF00); + try test_i128_intFromFloat_f32(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i128_intFromFloat_f32(0x1.FFFFFFp+30, 0x80000000); + try test_i128_intFromFloat_f32(0x1.000000p+31, 0x80000000); + + try test_i128_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFFp+62, 0x8000000000000000); + + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); + try test_i128_intFromFloat_f32(0x1.0000000000000p+63, 0x8000000000000000); + try test_i128_intFromFloat_f32(0x1.0000000000001p+63, 0x8000000000000000); + + try test_i128_intFromFloat_f32(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); + try test_i128_intFromFloat_f32(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f32(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f32(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test_i128_intFromFloat_f32(math.floatMax(f32), math.maxInt(i128)); +} + +test u128_intFromFloat_f32 { + try test_u128_intFromFloat_f32(0.0, 0); + + try test_u128_intFromFloat_f32(0.5, 0); + try test_u128_intFromFloat_f32(0.99, 0); + try test_u128_intFromFloat_f32(1.0, 1); + try test_u128_intFromFloat_f32(1.5, 1); + try test_u128_intFromFloat_f32(1.99, 1); + try test_u128_intFromFloat_f32(2.0, 2); + try test_u128_intFromFloat_f32(2.01, 2); + try test_u128_intFromFloat_f32(-0.5, 0); + try test_u128_intFromFloat_f32(-0.99, 0); + + try test_u128_intFromFloat_f32(-1.0, 0); + try test_u128_intFromFloat_f32(-1.5, 0); + try test_u128_intFromFloat_f32(-1.99, 0); + try test_u128_intFromFloat_f32(-2.0, 0); + try test_u128_intFromFloat_f32(-2.01, 0); + + try test_u128_intFromFloat_f32(0x1.FFFFFEp+63, 0xFFFFFF0000000000); + try test_u128_intFromFloat_f32(0x1.000000p+63, 0x8000000000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000); + try test_u128_intFromFloat_f32(0x1.000000p+127, 0x80000000000000000000000000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000); + try test_u128_intFromFloat_f32(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000); + + try test_u128_intFromFloat_f32(-0x1.FFFFFEp+62, 0x0000000000000000); + try test_u128_intFromFloat_f32(-0x1.FFFFFCp+62, 0x0000000000000000); + try test_u128_intFromFloat_f32(-0x1.FFFFFEp+126, 0x0000000000000000); + try test_u128_intFromFloat_f32(-0x1.FFFFFCp+126, 0x0000000000000000); + try test_u128_intFromFloat_f32(math.floatMax(f32), 0xffffff00000000000000000000000000); + try test_u128_intFromFloat_f32(math.inf(f32), math.maxInt(u128)); +} + +fn test_intFromFloat_f32(comptime T: type, expected: T, a: f32) !void { const int = @typeInfo(T).int; var actual: T = undefined; _ = switch (int.signedness) { - .signed => __fixsfei, - .unsigned => __fixunssfei, - }(@ptrCast(&actual), int.bits, a); + .signed => signed_intFromFloat_f32, + .unsigned => unsigned_intFromFloat_f32, + }(@ptrCast(&actual), a); try testing.expect(expected == actual); } -test "fixsfei" { - try test_fixsfei(i256, -1 << 127, -0x1p127); - try test_fixsfei(i256, -1 << 100, -0x1p100); - try test_fixsfei(i256, -1 << 50, -0x1p50); - try test_fixsfei(i256, -1 << 1, -0x1p1); - try test_fixsfei(i256, -1 << 0, -0x1p0); - try test_fixsfei(i256, 0, 0); - try test_fixsfei(i256, 1 << 0, 0x1p0); - try test_fixsfei(i256, 1 << 1, 0x1p1); - try test_fixsfei(i256, 1 << 50, 0x1p50); - try test_fixsfei(i256, 1 << 100, 0x1p100); - try test_fixsfei(i256, 1 << 127, 0x1p127); +test signed_intFromFloat_f32 { + try test_intFromFloat_f32(i256, -1 << 127, -0x1p127); + try test_intFromFloat_f32(i256, -1 << 100, -0x1p100); + try test_intFromFloat_f32(i256, -1 << 50, -0x1p50); + try test_intFromFloat_f32(i256, -1 << 1, -0x1p1); + try test_intFromFloat_f32(i256, -1 << 0, -0x1p0); + try test_intFromFloat_f32(i256, 0, 0); + try test_intFromFloat_f32(i256, 1 << 0, 0x1p0); + try test_intFromFloat_f32(i256, 1 << 1, 0x1p1); + try test_intFromFloat_f32(i256, 1 << 50, 0x1p50); + try test_intFromFloat_f32(i256, 1 << 100, 0x1p100); + try test_intFromFloat_f32(i256, 1 << 127, 0x1p127); } -test "fixunsfei" { - try test_fixsfei(u256, 0, 0); - try test_fixsfei(u256, 1 << 0, 0x1p0); - try test_fixsfei(u256, 1 << 1, 0x1p1); - try test_fixsfei(u256, 1 << 50, 0x1p50); - try test_fixsfei(u256, 1 << 100, 0x1p100); - try test_fixsfei(u256, 1 << 127, 0x1p127); +test unsigned_intFromFloat_f32 { + try test_intFromFloat_f32(u256, 0, 0); + try test_intFromFloat_f32(u256, 1 << 0, 0x1p0); + try test_intFromFloat_f32(u256, 1 << 1, 0x1p1); + try test_intFromFloat_f32(u256, 1 << 50, 0x1p50); + try test_intFromFloat_f32(u256, 1 << 100, 0x1p100); + try test_intFromFloat_f32(u256, 1 << 127, 0x1p127); } -fn test__fixdfsi(a: f64, expected: i32) !void { - const x = __fixdfsi(a); +fn test_i32_intFromFloat_f64(a: f64, expected: i32) !void { + const x = i32_intFromFloat_f64(a); try testing.expect(x == expected); } -fn test__fixunsdfsi(a: f64, expected: u32) !void { - const x = __fixunsdfsi(a); +fn test_u32_intFromFloat_f64(a: f64, expected: u32) !void { + const x = u32_intFromFloat_f64(a); try testing.expect(x == expected); } -test "fixdfsi" { - try test__fixdfsi(-math.floatMax(f64), math.minInt(i32)); - - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); - - try test__fixdfsi(-0x1.0000000000000p+127, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); - - try test__fixdfsi(-0x1.0000000000001p+63, -0x80000000); - try test__fixdfsi(-0x1.0000000000000p+63, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); - - try test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000); - try test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000); - - try test__fixdfsi(-0x1.000000p+31, -0x80000000); - try test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); - try test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); - - try test__fixdfsi(-2.01, -2); - try test__fixdfsi(-2.0, -2); - try test__fixdfsi(-1.99, -1); - try test__fixdfsi(-1.0, -1); - try test__fixdfsi(-0.99, 0); - try test__fixdfsi(-0.5, 0); - try test__fixdfsi(-math.floatMin(f64), 0); - try test__fixdfsi(0.0, 0); - try test__fixdfsi(math.floatMin(f64), 0); - try test__fixdfsi(0.5, 0); - try test__fixdfsi(0.99, 0); - try test__fixdfsi(1.0, 1); - try test__fixdfsi(1.5, 1); - try test__fixdfsi(1.99, 1); - try test__fixdfsi(2.0, 2); - try test__fixdfsi(2.01, 2); - - try test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); - try test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); - try test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF); - try test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); - try test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF); - - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); - try test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); - - try test__fixdfsi(math.floatMax(f64), math.maxInt(i32)); -} - -test "fixunsdfsi" { - try test__fixunsdfsi(0.0, 0); - - try test__fixunsdfsi(0.5, 0); - try test__fixunsdfsi(0.99, 0); - try test__fixunsdfsi(1.0, 1); - try test__fixunsdfsi(1.5, 1); - try test__fixunsdfsi(1.99, 1); - try test__fixunsdfsi(2.0, 2); - try test__fixunsdfsi(2.01, 2); - try test__fixunsdfsi(-0.5, 0); - try test__fixunsdfsi(-0.99, 0); - try test__fixunsdfsi(-1.0, 0); - try test__fixunsdfsi(-1.5, 0); - try test__fixunsdfsi(-1.99, 0); - try test__fixunsdfsi(-2.0, 0); - try test__fixunsdfsi(-2.01, 0); - - try test__fixunsdfsi(0x1.000000p+31, 0x80000000); - try test__fixunsdfsi(0x1.000000p+32, 0xFFFFFFFF); - try test__fixunsdfsi(0x1.FFFFFEp+31, 0xFFFFFF00); - try test__fixunsdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixunsdfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - - try test__fixunsdfsi(-0x1.FFFFFEp+30, 0); - try test__fixunsdfsi(-0x1.FFFFFCp+30, 0); - - try test__fixunsdfsi(0x1.FFFFFFFEp+31, 0xFFFFFFFF); - try test__fixunsdfsi(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF); - try test__fixunsdfsi(0x1.FFFFFFF800000p+30, 0x7FFFFFFE); -} - -fn test__fixdfdi(a: f64, expected: i64) !void { - const x = __fixdfdi(a); +test i32_intFromFloat_f64 { + try test_i32_intFromFloat_f64(-math.floatMax(f64), math.minInt(i32)); + + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + try test_i32_intFromFloat_f64(-0x1.0000000000000p+127, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + try test_i32_intFromFloat_f64(-0x1.0000000000001p+63, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.0000000000000p+63, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + try test_i32_intFromFloat_f64(-0x1.FFFFFEp+62, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFCp+62, -0x80000000); + + try test_i32_intFromFloat_f64(-0x1.000000p+31, -0x80000000); + try test_i32_intFromFloat_f64(-0x1.FFFFFFp+30, -0x7FFFFFC0); + try test_i32_intFromFloat_f64(-0x1.FFFFFEp+30, -0x7FFFFF80); + + try test_i32_intFromFloat_f64(-2.01, -2); + try test_i32_intFromFloat_f64(-2.0, -2); + try test_i32_intFromFloat_f64(-1.99, -1); + try test_i32_intFromFloat_f64(-1.0, -1); + try test_i32_intFromFloat_f64(-0.99, 0); + try test_i32_intFromFloat_f64(-0.5, 0); + try test_i32_intFromFloat_f64(-math.floatMin(f64), 0); + try test_i32_intFromFloat_f64(0.0, 0); + try test_i32_intFromFloat_f64(math.floatMin(f64), 0); + try test_i32_intFromFloat_f64(0.5, 0); + try test_i32_intFromFloat_f64(0.99, 0); + try test_i32_intFromFloat_f64(1.0, 1); + try test_i32_intFromFloat_f64(1.5, 1); + try test_i32_intFromFloat_f64(1.99, 1); + try test_i32_intFromFloat_f64(2.0, 2); + try test_i32_intFromFloat_f64(2.01, 2); + + try test_i32_intFromFloat_f64(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i32_intFromFloat_f64(0x1.FFFFFFp+30, 0x7FFFFFC0); + try test_i32_intFromFloat_f64(0x1.000000p+31, 0x7FFFFFFF); + + try test_i32_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFFFF); + + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.0000000000000p+63, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.0000000000001p+63, 0x7FFFFFFF); + + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.0000000000000p+127, 0x7FFFFFFF); + + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + try test_i32_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + try test_i32_intFromFloat_f64(math.floatMax(f64), math.maxInt(i32)); +} + +test u32_intFromFloat_f64 { + try test_u32_intFromFloat_f64(0.0, 0); + + try test_u32_intFromFloat_f64(0.5, 0); + try test_u32_intFromFloat_f64(0.99, 0); + try test_u32_intFromFloat_f64(1.0, 1); + try test_u32_intFromFloat_f64(1.5, 1); + try test_u32_intFromFloat_f64(1.99, 1); + try test_u32_intFromFloat_f64(2.0, 2); + try test_u32_intFromFloat_f64(2.01, 2); + try test_u32_intFromFloat_f64(-0.5, 0); + try test_u32_intFromFloat_f64(-0.99, 0); + try test_u32_intFromFloat_f64(-1.0, 0); + try test_u32_intFromFloat_f64(-1.5, 0); + try test_u32_intFromFloat_f64(-1.99, 0); + try test_u32_intFromFloat_f64(-2.0, 0); + try test_u32_intFromFloat_f64(-2.01, 0); + + try test_u32_intFromFloat_f64(0x1.000000p+31, 0x80000000); + try test_u32_intFromFloat_f64(0x1.000000p+32, 0xFFFFFFFF); + try test_u32_intFromFloat_f64(0x1.FFFFFEp+31, 0xFFFFFF00); + try test_u32_intFromFloat_f64(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_u32_intFromFloat_f64(0x1.FFFFFCp+30, 0x7FFFFF00); + + try test_u32_intFromFloat_f64(-0x1.FFFFFEp+30, 0); + try test_u32_intFromFloat_f64(-0x1.FFFFFCp+30, 0); + + try test_u32_intFromFloat_f64(0x1.FFFFFFFEp+31, 0xFFFFFFFF); + try test_u32_intFromFloat_f64(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF); + try test_u32_intFromFloat_f64(0x1.FFFFFFF800000p+30, 0x7FFFFFFE); +} + +fn test_i64_intFromFloat_f64(a: f64, expected: i64) !void { + const x = i64_intFromFloat_f64(a); try testing.expect(x == expected); } -fn test__fixunsdfdi(a: f64, expected: u64) !void { - const x = __fixunsdfdi(a); +fn test_u64_intFromFloat_f64(a: f64, expected: u64) !void { + const x = u64_intFromFloat_f64(a); try testing.expect(x == expected); } -test "fixdfdi" { - try test__fixdfdi(-math.floatMax(f64), math.minInt(i64)); - - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); - - try test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000); - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); - try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); - - try test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixdfdi(-2.01, -2); - try test__fixdfdi(-2.0, -2); - try test__fixdfdi(-1.99, -1); - try test__fixdfdi(-1.0, -1); - try test__fixdfdi(-0.99, 0); - try test__fixdfdi(-0.5, 0); - try test__fixdfdi(-math.floatMin(f64), 0); - try test__fixdfdi(0.0, 0); - try test__fixdfdi(math.floatMin(f64), 0); - try test__fixdfdi(0.5, 0); - try test__fixdfdi(0.99, 0); - try test__fixdfdi(1.0, 1); - try test__fixdfdi(1.5, 1); - try test__fixdfdi(1.99, 1); - try test__fixdfdi(2.0, 2); - try test__fixdfdi(2.01, 2); - - try test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); - - try test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); - - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); - try test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); - - try test__fixdfdi(math.floatMax(f64), math.maxInt(i64)); -} - -test "fixunsdfdi" { - try test__fixunsdfdi(0.0, 0); - try test__fixunsdfdi(0.5, 0); - try test__fixunsdfdi(0.99, 0); - try test__fixunsdfdi(1.0, 1); - try test__fixunsdfdi(1.5, 1); - try test__fixunsdfdi(1.99, 1); - try test__fixunsdfdi(2.0, 2); - try test__fixunsdfdi(2.01, 2); - try test__fixunsdfdi(-0.5, 0); - try test__fixunsdfdi(-0.99, 0); - try test__fixunsdfdi(-1.0, 0); - try test__fixunsdfdi(-1.5, 0); - try test__fixunsdfdi(-1.99, 0); - try test__fixunsdfdi(-2.0, 0); - try test__fixunsdfdi(-2.01, 0); - - try test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunsdfdi(-0x1.FFFFFEp+62, 0); - try test__fixunsdfdi(-0x1.FFFFFCp+62, 0); - - try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); - try test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - - try test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0); - try test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0); -} - -fn test__fixdfti(a: f64, expected: i128) !void { - const x = __fixdfti(a); +test i64_intFromFloat_f64 { + try test_i64_intFromFloat_f64(-math.floatMax(f64), math.minInt(i64)); + + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + try test_i64_intFromFloat_f64(-0x1.0000000000000p+127, -0x8000000000000000); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + try test_i64_intFromFloat_f64(-0x1.0000000000001p+63, -0x8000000000000000); + try test_i64_intFromFloat_f64(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test_i64_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test_i64_intFromFloat_f64(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i64_intFromFloat_f64(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i64_intFromFloat_f64(-2.01, -2); + try test_i64_intFromFloat_f64(-2.0, -2); + try test_i64_intFromFloat_f64(-1.99, -1); + try test_i64_intFromFloat_f64(-1.0, -1); + try test_i64_intFromFloat_f64(-0.99, 0); + try test_i64_intFromFloat_f64(-0.5, 0); + try test_i64_intFromFloat_f64(-math.floatMin(f64), 0); + try test_i64_intFromFloat_f64(0.0, 0); + try test_i64_intFromFloat_f64(math.floatMin(f64), 0); + try test_i64_intFromFloat_f64(0.5, 0); + try test_i64_intFromFloat_f64(0.99, 0); + try test_i64_intFromFloat_f64(1.0, 1); + try test_i64_intFromFloat_f64(1.5, 1); + try test_i64_intFromFloat_f64(1.99, 1); + try test_i64_intFromFloat_f64(2.0, 2); + try test_i64_intFromFloat_f64(2.01, 2); + + try test_i64_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i64_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_i64_intFromFloat_f64(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f64(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f64(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + try test_i64_intFromFloat_f64(math.floatMax(f64), math.maxInt(i64)); +} + +test u64_intFromFloat_f64 { + try test_u64_intFromFloat_f64(0.0, 0); + try test_u64_intFromFloat_f64(0.5, 0); + try test_u64_intFromFloat_f64(0.99, 0); + try test_u64_intFromFloat_f64(1.0, 1); + try test_u64_intFromFloat_f64(1.5, 1); + try test_u64_intFromFloat_f64(1.99, 1); + try test_u64_intFromFloat_f64(2.0, 2); + try test_u64_intFromFloat_f64(2.01, 2); + try test_u64_intFromFloat_f64(-0.5, 0); + try test_u64_intFromFloat_f64(-0.99, 0); + try test_u64_intFromFloat_f64(-1.0, 0); + try test_u64_intFromFloat_f64(-1.5, 0); + try test_u64_intFromFloat_f64(-1.99, 0); + try test_u64_intFromFloat_f64(-2.0, 0); + try test_u64_intFromFloat_f64(-2.01, 0); + + try test_u64_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u64_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test_u64_intFromFloat_f64(-0x1.FFFFFEp+62, 0); + try test_u64_intFromFloat_f64(-0x1.FFFFFCp+62, 0); + + try test_u64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); + try test_u64_intFromFloat_f64(0x1.0000000000000p+63, 0x8000000000000000); + try test_u64_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_u64_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + try test_u64_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, 0); + try test_u64_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, 0); +} + +fn test_i128_intFromFloat_f64(a: f64, expected: i128) !void { + const x = i128_intFromFloat_f64(a); try testing.expect(x == expected); } -fn test__fixunsdfti(a: f64, expected: u128) !void { - const x = __fixunsdfti(a); +fn test_u128_intFromFloat_f64(a: f64, expected: u128) !void { + const x = u128_intFromFloat_f64(a); try testing.expect(x == expected); } -test "fixdfti" { - try test__fixdfti(-math.floatMax(f64), math.minInt(i128)); - - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); - - try test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); - try test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); - - try test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800); - try test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); - - try test__fixdfti(-2.01, -2); - try test__fixdfti(-2.0, -2); - try test__fixdfti(-1.99, -1); - try test__fixdfti(-1.0, -1); - try test__fixdfti(-0.99, 0); - try test__fixdfti(-0.5, 0); - try test__fixdfti(-math.floatMin(f64), 0); - try test__fixdfti(0.0, 0); - try test__fixdfti(math.floatMin(f64), 0); - try test__fixdfti(0.5, 0); - try test__fixdfti(0.99, 0); - try test__fixdfti(1.0, 1); - try test__fixdfti(1.5, 1); - try test__fixdfti(1.99, 1); - try test__fixdfti(2.0, 2); - try test__fixdfti(2.01, 2); - - try test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800); - - try test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); - - try test__fixdfti(math.floatMax(f64), math.maxInt(i128)); -} - -test "fixunsdfti" { - try test__fixunsdfti(0.0, 0); - - try test__fixunsdfti(0.5, 0); - try test__fixunsdfti(0.99, 0); - try test__fixunsdfti(1.0, 1); - try test__fixunsdfti(1.5, 1); - try test__fixunsdfti(1.99, 1); - try test__fixunsdfti(2.0, 2); - try test__fixunsdfti(2.01, 2); - try test__fixunsdfti(-0.5, 0); - try test__fixunsdfti(-0.99, 0); - try test__fixunsdfti(-1.0, 0); - try test__fixunsdfti(-1.5, 0); - try test__fixunsdfti(-1.99, 0); - try test__fixunsdfti(-2.0, 0); - try test__fixunsdfti(-2.01, 0); - - try test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunsdfti(-0x1.FFFFFEp+62, 0); - try test__fixunsdfti(-0x1.FFFFFCp+62, 0); - - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); - try test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000); - try test__fixunsdfti(0x1.0000000000000p+127, 0x80000000000000000000000000000000); - try test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixunsdfti(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - - try test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0); - try test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0); -} - -fn test_fixdfei(comptime T: type, expected: T, a: f64) !void { +test i128_intFromFloat_f64 { + try test_i128_intFromFloat_f64(-math.floatMax(f64), math.minInt(i128)); + + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + try test_i128_intFromFloat_f64(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + try test_i128_intFromFloat_f64(-0x1.0000000000001p+63, -0x8000000000000800); + try test_i128_intFromFloat_f64(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test_i128_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test_i128_intFromFloat_f64(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i128_intFromFloat_f64(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i128_intFromFloat_f64(-2.01, -2); + try test_i128_intFromFloat_f64(-2.0, -2); + try test_i128_intFromFloat_f64(-1.99, -1); + try test_i128_intFromFloat_f64(-1.0, -1); + try test_i128_intFromFloat_f64(-0.99, 0); + try test_i128_intFromFloat_f64(-0.5, 0); + try test_i128_intFromFloat_f64(-math.floatMin(f64), 0); + try test_i128_intFromFloat_f64(0.0, 0); + try test_i128_intFromFloat_f64(math.floatMin(f64), 0); + try test_i128_intFromFloat_f64(0.5, 0); + try test_i128_intFromFloat_f64(0.99, 0); + try test_i128_intFromFloat_f64(1.0, 1); + try test_i128_intFromFloat_f64(1.5, 1); + try test_i128_intFromFloat_f64(1.99, 1); + try test_i128_intFromFloat_f64(2.0, 2); + try test_i128_intFromFloat_f64(2.01, 2); + + try test_i128_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i128_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_i128_intFromFloat_f64(0x1.0000000000000p+63, 0x8000000000000000); + try test_i128_intFromFloat_f64(0x1.0000000000001p+63, 0x8000000000000800); + + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test_i128_intFromFloat_f64(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test_i128_intFromFloat_f64(math.floatMax(f64), math.maxInt(i128)); +} + +test u128_intFromFloat_f64 { + try test_u128_intFromFloat_f64(0.0, 0); + + try test_u128_intFromFloat_f64(0.5, 0); + try test_u128_intFromFloat_f64(0.99, 0); + try test_u128_intFromFloat_f64(1.0, 1); + try test_u128_intFromFloat_f64(1.5, 1); + try test_u128_intFromFloat_f64(1.99, 1); + try test_u128_intFromFloat_f64(2.0, 2); + try test_u128_intFromFloat_f64(2.01, 2); + try test_u128_intFromFloat_f64(-0.5, 0); + try test_u128_intFromFloat_f64(-0.99, 0); + try test_u128_intFromFloat_f64(-1.0, 0); + try test_u128_intFromFloat_f64(-1.5, 0); + try test_u128_intFromFloat_f64(-1.99, 0); + try test_u128_intFromFloat_f64(-2.0, 0); + try test_u128_intFromFloat_f64(-2.01, 0); + + try test_u128_intFromFloat_f64(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u128_intFromFloat_f64(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test_u128_intFromFloat_f64(-0x1.FFFFFEp+62, 0); + try test_u128_intFromFloat_f64(-0x1.FFFFFCp+62, 0); + + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); + try test_u128_intFromFloat_f64(0x1.0000000000000p+63, 0x8000000000000000); + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000); + try test_u128_intFromFloat_f64(0x1.0000000000000p+127, 0x80000000000000000000000000000000); + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test_u128_intFromFloat_f64(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test_u128_intFromFloat_f64(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test_u128_intFromFloat_f64(-0x1.FFFFFFFFFFFFFp+62, 0); + try test_u128_intFromFloat_f64(-0x1.FFFFFFFFFFFFEp+62, 0); +} + +fn test_intFromFloat_f64(comptime T: type, expected: T, a: f64) !void { const int = @typeInfo(T).int; var actual: T = undefined; _ = switch (int.signedness) { - .signed => __fixdfei, - .unsigned => __fixunsdfei, - }(@ptrCast(&actual), int.bits, a); + .signed => signed_intFromFloat_f64, + .unsigned => unsigned_intFromFloat_f64, + }(@ptrCast(&actual), a); try testing.expect(expected == actual); } -test "fixdfei" { - try test_fixdfei(i256, -1 << 255, -0x1p255); - try test_fixdfei(i256, -1 << 127, -0x1p127); - try test_fixdfei(i256, -1 << 100, -0x1p100); - try test_fixdfei(i256, -1 << 50, -0x1p50); - try test_fixdfei(i256, -1 << 1, -0x1p1); - try test_fixdfei(i256, -1 << 0, -0x1p0); - try test_fixdfei(i256, 0, 0); - try test_fixdfei(i256, 1 << 0, 0x1p0); - try test_fixdfei(i256, 1 << 1, 0x1p1); - try test_fixdfei(i256, 1 << 50, 0x1p50); - try test_fixdfei(i256, 1 << 100, 0x1p100); - try test_fixdfei(i256, 1 << 127, 0x1p127); - try test_fixdfei(i256, 1 << 254, 0x1p254); -} - -test "fixundfei" { - try test_fixdfei(u256, 0, 0); - try test_fixdfei(u256, 1 << 0, 0x1p0); - try test_fixdfei(u256, 1 << 1, 0x1p1); - try test_fixdfei(u256, 1 << 50, 0x1p50); - try test_fixdfei(u256, 1 << 100, 0x1p100); - try test_fixdfei(u256, 1 << 127, 0x1p127); - try test_fixdfei(u256, 1 << 255, 0x1p255); -} - -fn test__fixtfsi(a: f128, expected: i32) !void { - const x = __fixtfsi(a); - try testing.expect(x == expected); +test signed_intFromFloat_f64 { + try test_intFromFloat_f64(i256, -1 << 255, -0x1p255); + try test_intFromFloat_f64(i256, -1 << 127, -0x1p127); + try test_intFromFloat_f64(i256, -1 << 100, -0x1p100); + try test_intFromFloat_f64(i256, -1 << 50, -0x1p50); + try test_intFromFloat_f64(i256, -1 << 1, -0x1p1); + try test_intFromFloat_f64(i256, -1 << 0, -0x1p0); + try test_intFromFloat_f64(i256, 0, 0); + try test_intFromFloat_f64(i256, 1 << 0, 0x1p0); + try test_intFromFloat_f64(i256, 1 << 1, 0x1p1); + try test_intFromFloat_f64(i256, 1 << 50, 0x1p50); + try test_intFromFloat_f64(i256, 1 << 100, 0x1p100); + try test_intFromFloat_f64(i256, 1 << 127, 0x1p127); + try test_intFromFloat_f64(i256, 1 << 254, 0x1p254); } -fn test__fixunstfsi(a: f128, expected: u32) !void { - const x = __fixunstfsi(a); - try testing.expect(x == expected); +test unsigned_intFromFloat_f64 { + try test_intFromFloat_f64(u256, 0, 0); + try test_intFromFloat_f64(u256, 1 << 0, 0x1p0); + try test_intFromFloat_f64(u256, 1 << 1, 0x1p1); + try test_intFromFloat_f64(u256, 1 << 50, 0x1p50); + try test_intFromFloat_f64(u256, 1 << 100, 0x1p100); + try test_intFromFloat_f64(u256, 1 << 127, 0x1p127); + try test_intFromFloat_f64(u256, 1 << 255, 0x1p255); } -test "fixtfsi" { - try test__fixtfsi(-math.floatMax(f128), math.minInt(i32)); - - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); - - try test__fixtfsi(-0x1.0000000000000p+127, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); - - try test__fixtfsi(-0x1.0000000000001p+63, -0x80000000); - try test__fixtfsi(-0x1.0000000000000p+63, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); - - try test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000); - try test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000); - - try test__fixtfsi(-0x1.000000p+31, -0x80000000); - try test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); - try test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixtfsi(-2.01, -2); - try test__fixtfsi(-2.0, -2); - try test__fixtfsi(-1.99, -1); - try test__fixtfsi(-1.0, -1); - try test__fixtfsi(-0.99, 0); - try test__fixtfsi(-0.5, 0); - try test__fixtfsi(-math.floatMin(f32), 0); - try test__fixtfsi(0.0, 0); - try test__fixtfsi(math.floatMin(f32), 0); - try test__fixtfsi(0.5, 0); - try test__fixtfsi(0.99, 0); - try test__fixtfsi(1.0, 1); - try test__fixtfsi(1.5, 1); - try test__fixtfsi(1.99, 1); - try test__fixtfsi(2.0, 2); - try test__fixtfsi(2.01, 2); - - try test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); - try test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); - try test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF); - try test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); - try test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF); - - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); - try test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); - - try test__fixtfsi(math.floatMax(f128), math.maxInt(i32)); -} - -test "fixunstfsi" { - try test__fixunstfsi(math.inf(f128), 0xffffffff); - try test__fixunstfsi(0, 0x0); - try test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); - try test__fixunstfsi(0x1.23456789abcdefp-3, 0x0); - try test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456); - try test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff); - try test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff); - try test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0); - - try test__fixunstfsi(0x1p+32, 0xFFFFFFFF); -} - -fn test__fixtfdi(a: f128, expected: i64) !void { - const x = __fixtfdi(a); +fn test_i32_intFromFloat_f128(a: f128, expected: i32) !void { + const x = i32_intFromFloat_f128(a); try testing.expect(x == expected); } -fn test__fixunstfdi(a: f128, expected: u64) !void { - const x = __fixunstfdi(a); +fn test_u32_intFromFloat_f128(a: f128, expected: u32) !void { + const x = u32_intFromFloat_f128(a); try testing.expect(x == expected); } -test "fixtfdi" { - try test__fixtfdi(-math.floatMax(f128), math.minInt(i64)); - - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); - - try test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000); - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); - try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); - - try test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000); - try test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); - try test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); - - try test__fixtfdi(-0x1.000000p+31, -0x80000000); - try test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0); - try test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80); - try test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00); - - try test__fixtfdi(-2.01, -2); - try test__fixtfdi(-2.0, -2); - try test__fixtfdi(-1.99, -1); - try test__fixtfdi(-1.0, -1); - try test__fixtfdi(-0.99, 0); - try test__fixtfdi(-0.5, 0); - try test__fixtfdi(-math.floatMin(f64), 0); - try test__fixtfdi(0.0, 0); - try test__fixtfdi(math.floatMin(f64), 0); - try test__fixtfdi(0.5, 0); - try test__fixtfdi(0.99, 0); - try test__fixtfdi(1.0, 1); - try test__fixtfdi(1.5, 1); - try test__fixtfdi(1.99, 1); - try test__fixtfdi(2.0, 2); - try test__fixtfdi(2.01, 2); - - try test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00); - try test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80); - try test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0); - try test__fixtfdi(0x1.000000p+31, 0x80000000); - - try test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - - try test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); - - try test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); - - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); - try test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); - - try test__fixtfdi(math.floatMax(f128), math.maxInt(i64)); -} - -test "fixunstfdi" { - try test__fixunstfdi(0.0, 0); - - try test__fixunstfdi(0.5, 0); - try test__fixunstfdi(0.99, 0); - try test__fixunstfdi(1.0, 1); - try test__fixunstfdi(1.5, 1); - try test__fixunstfdi(1.99, 1); - try test__fixunstfdi(2.0, 2); - try test__fixunstfdi(2.01, 2); - try test__fixunstfdi(-0.5, 0); - try test__fixunstfdi(-0.99, 0); - try test__fixunstfdi(-1.0, 0); - try test__fixunstfdi(-1.5, 0); - try test__fixunstfdi(-1.99, 0); - try test__fixunstfdi(-2.0, 0); - try test__fixunstfdi(-2.01, 0); - - try test__fixunstfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); - try test__fixunstfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - - try test__fixunstfdi(-0x1.FFFFFEp+62, 0); - try test__fixunstfdi(-0x1.FFFFFCp+62, 0); - - try test__fixunstfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixunstfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - - try test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0); - try test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0); - - try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); - try test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001); - try test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000); - try test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); - try test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); - try test__fixunstfdi(0x1p+64, 0xFFFFFFFFFFFFFFFF); - - try test__fixunstfdi(-0x1.0000000000000000p+63, 0); - try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0); - try test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0); -} - -fn test__fixtfti(a: f128, expected: i128) !void { - const x = __fixtfti(a); - try testing.expect(x == expected); +test i32_intFromFloat_f128 { + try test_i32_intFromFloat_f128(-math.floatMax(f128), math.minInt(i32)); + + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + try test_i32_intFromFloat_f128(-0x1.0000000000000p+127, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + try test_i32_intFromFloat_f128(-0x1.0000000000001p+63, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.0000000000000p+63, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + try test_i32_intFromFloat_f128(-0x1.FFFFFEp+62, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFCp+62, -0x80000000); + + try test_i32_intFromFloat_f128(-0x1.000000p+31, -0x80000000); + try test_i32_intFromFloat_f128(-0x1.FFFFFFp+30, -0x7FFFFFC0); + try test_i32_intFromFloat_f128(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test_i32_intFromFloat_f128(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test_i32_intFromFloat_f128(-2.01, -2); + try test_i32_intFromFloat_f128(-2.0, -2); + try test_i32_intFromFloat_f128(-1.99, -1); + try test_i32_intFromFloat_f128(-1.0, -1); + try test_i32_intFromFloat_f128(-0.99, 0); + try test_i32_intFromFloat_f128(-0.5, 0); + try test_i32_intFromFloat_f128(-math.floatMin(f32), 0); + try test_i32_intFromFloat_f128(0.0, 0); + try test_i32_intFromFloat_f128(math.floatMin(f32), 0); + try test_i32_intFromFloat_f128(0.5, 0); + try test_i32_intFromFloat_f128(0.99, 0); + try test_i32_intFromFloat_f128(1.0, 1); + try test_i32_intFromFloat_f128(1.5, 1); + try test_i32_intFromFloat_f128(1.99, 1); + try test_i32_intFromFloat_f128(2.0, 2); + try test_i32_intFromFloat_f128(2.01, 2); + + try test_i32_intFromFloat_f128(0x1.FFFFFCp+30, 0x7FFFFF00); + try test_i32_intFromFloat_f128(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i32_intFromFloat_f128(0x1.FFFFFFp+30, 0x7FFFFFC0); + try test_i32_intFromFloat_f128(0x1.000000p+31, 0x7FFFFFFF); + + try test_i32_intFromFloat_f128(0x1.FFFFFCp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.FFFFFEp+62, 0x7FFFFFFF); + + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.0000000000000p+63, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.0000000000001p+63, 0x7FFFFFFF); + + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.0000000000000p+127, 0x7FFFFFFF); + + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + try test_i32_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + try test_i32_intFromFloat_f128(math.floatMax(f128), math.maxInt(i32)); } -fn test__fixunstfti(a: f128, expected: u128) !void { - const x = __fixunstfti(a); - try testing.expect(x == expected); +test u32_intFromFloat_f128 { + try test_u32_intFromFloat_f128(math.inf(f128), 0xffffffff); + try test_u32_intFromFloat_f128(0, 0x0); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp+5, 0x24); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp-3, 0x0); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp+20, 0x123456); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp+40, 0xffffffff); + try test_u32_intFromFloat_f128(0x1.23456789abcdefp+256, 0xffffffff); + try test_u32_intFromFloat_f128(-0x1.23456789abcdefp+3, 0x0); + + try test_u32_intFromFloat_f128(0x1p+32, 0xFFFFFFFF); } -test "fixtfti" { - try test__fixtfti(-math.floatMax(f128), math.minInt(i128)); - - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); - - try test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); - try test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); - - try test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800); - try test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000); - try test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); - try test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); - - try test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); - try test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); +fn test_i64_intFromFloat_f128(a: f128, expected: i64) !void { + const x = i64_intFromFloat_f128(a); + try testing.expect(x == expected); +} - try test__fixtfti(-2.01, -2); - try test__fixtfti(-2.0, -2); - try test__fixtfti(-1.99, -1); - try test__fixtfti(-1.0, -1); - try test__fixtfti(-0.99, 0); - try test__fixtfti(-0.5, 0); - try test__fixtfti(-math.floatMin(f128), 0); - try test__fixtfti(0.0, 0); - try test__fixtfti(math.floatMin(f128), 0); - try test__fixtfti(0.5, 0); - try test__fixtfti(0.99, 0); - try test__fixtfti(1.0, 1); - try test__fixtfti(1.5, 1); - try test__fixtfti(1.99, 1); - try test__fixtfti(2.0, 2); - try test__fixtfti(2.01, 2); +fn test_u64_intFromFloat_f128(a: f128, expected: u64) !void { + const x = u64_intFromFloat_f128(a); + try testing.expect(x == expected); +} - try test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); - try test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); +test i64_intFromFloat_f128 { + try test_i64_intFromFloat_f128(-math.floatMax(f128), math.minInt(i64)); + + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + try test_i64_intFromFloat_f128(-0x1.0000000000000p+127, -0x8000000000000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + try test_i64_intFromFloat_f128(-0x1.0000000000001p+63, -0x8000000000000000); + try test_i64_intFromFloat_f128(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test_i64_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test_i64_intFromFloat_f128(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); + + try test_i64_intFromFloat_f128(-0x1.000000p+31, -0x80000000); + try test_i64_intFromFloat_f128(-0x1.FFFFFFp+30, -0x7FFFFFC0); + try test_i64_intFromFloat_f128(-0x1.FFFFFEp+30, -0x7FFFFF80); + try test_i64_intFromFloat_f128(-0x1.FFFFFCp+30, -0x7FFFFF00); + + try test_i64_intFromFloat_f128(-2.01, -2); + try test_i64_intFromFloat_f128(-2.0, -2); + try test_i64_intFromFloat_f128(-1.99, -1); + try test_i64_intFromFloat_f128(-1.0, -1); + try test_i64_intFromFloat_f128(-0.99, 0); + try test_i64_intFromFloat_f128(-0.5, 0); + try test_i64_intFromFloat_f128(-math.floatMin(f64), 0); + try test_i64_intFromFloat_f128(0.0, 0); + try test_i64_intFromFloat_f128(math.floatMin(f64), 0); + try test_i64_intFromFloat_f128(0.5, 0); + try test_i64_intFromFloat_f128(0.99, 0); + try test_i64_intFromFloat_f128(1.0, 1); + try test_i64_intFromFloat_f128(1.5, 1); + try test_i64_intFromFloat_f128(1.99, 1); + try test_i64_intFromFloat_f128(2.0, 2); + try test_i64_intFromFloat_f128(2.01, 2); + + try test_i64_intFromFloat_f128(0x1.FFFFFCp+30, 0x7FFFFF00); + try test_i64_intFromFloat_f128(0x1.FFFFFEp+30, 0x7FFFFF80); + try test_i64_intFromFloat_f128(0x1.FFFFFFp+30, 0x7FFFFFC0); + try test_i64_intFromFloat_f128(0x1.000000p+31, 0x80000000); + + try test_i64_intFromFloat_f128(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i64_intFromFloat_f128(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_i64_intFromFloat_f128(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f128(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f128(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + try test_i64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + try test_i64_intFromFloat_f128(math.floatMax(f128), math.maxInt(i64)); +} - try test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); - try test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000); - try test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800); +test u64_intFromFloat_f128 { + try test_u64_intFromFloat_f128(0.0, 0); + + try test_u64_intFromFloat_f128(0.5, 0); + try test_u64_intFromFloat_f128(0.99, 0); + try test_u64_intFromFloat_f128(1.0, 1); + try test_u64_intFromFloat_f128(1.5, 1); + try test_u64_intFromFloat_f128(1.99, 1); + try test_u64_intFromFloat_f128(2.0, 2); + try test_u64_intFromFloat_f128(2.01, 2); + try test_u64_intFromFloat_f128(-0.5, 0); + try test_u64_intFromFloat_f128(-0.99, 0); + try test_u64_intFromFloat_f128(-1.0, 0); + try test_u64_intFromFloat_f128(-1.5, 0); + try test_u64_intFromFloat_f128(-1.99, 0); + try test_u64_intFromFloat_f128(-2.0, 0); + try test_u64_intFromFloat_f128(-2.01, 0); + + try test_u64_intFromFloat_f128(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + try test_u64_intFromFloat_f128(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + try test_u64_intFromFloat_f128(-0x1.FFFFFEp+62, 0); + try test_u64_intFromFloat_f128(-0x1.FFFFFCp+62, 0); + + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + try test_u64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+62, 0); + try test_u64_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+62, 0); + + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); + try test_u64_intFromFloat_f128(0x1.0000000000000002p+63, 0x8000000000000001); + try test_u64_intFromFloat_f128(0x1.0000000000000000p+63, 0x8000000000000000); + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); + try test_u64_intFromFloat_f128(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); + try test_u64_intFromFloat_f128(0x1p+64, 0xFFFFFFFFFFFFFFFF); + + try test_u64_intFromFloat_f128(-0x1.0000000000000000p+63, 0); + try test_u64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFFFCp+62, 0); + try test_u64_intFromFloat_f128(-0x1.FFFFFFFFFFFFFFF8p+62, 0); +} - try test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); - try test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); +fn test_i128_intFromFloat_f128(a: f128, expected: i128) !void { + const x = i128_intFromFloat_f128(a); + try testing.expect(x == expected); +} - try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - try test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); +fn test_u128_intFromFloat_f128(a: f128, expected: u128) !void { + const x = u128_intFromFloat_f128(a); + try testing.expect(x == expected); +} - try test__fixtfti(math.floatMax(f128), math.maxInt(i128)); +test i128_intFromFloat_f128 { + try test_i128_intFromFloat_f128(-math.floatMax(f128), math.minInt(i128)); + + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + try test_i128_intFromFloat_f128(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + try test_i128_intFromFloat_f128(-0x1.0000000000001p+63, -0x8000000000000800); + try test_i128_intFromFloat_f128(-0x1.0000000000000p+63, -0x8000000000000000); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + try test_i128_intFromFloat_f128(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + try test_i128_intFromFloat_f128(-0x1.FFFFFEp+62, -0x7fffff8000000000); + try test_i128_intFromFloat_f128(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + try test_i128_intFromFloat_f128(-2.01, -2); + try test_i128_intFromFloat_f128(-2.0, -2); + try test_i128_intFromFloat_f128(-1.99, -1); + try test_i128_intFromFloat_f128(-1.0, -1); + try test_i128_intFromFloat_f128(-0.99, 0); + try test_i128_intFromFloat_f128(-0.5, 0); + try test_i128_intFromFloat_f128(-math.floatMin(f128), 0); + try test_i128_intFromFloat_f128(0.0, 0); + try test_i128_intFromFloat_f128(math.floatMin(f128), 0); + try test_i128_intFromFloat_f128(0.5, 0); + try test_i128_intFromFloat_f128(0.99, 0); + try test_i128_intFromFloat_f128(1.0, 1); + try test_i128_intFromFloat_f128(1.5, 1); + try test_i128_intFromFloat_f128(1.99, 1); + try test_i128_intFromFloat_f128(2.0, 2); + try test_i128_intFromFloat_f128(2.01, 2); + + try test_i128_intFromFloat_f128(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + try test_i128_intFromFloat_f128(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + try test_i128_intFromFloat_f128(0x1.0000000000000p+63, 0x8000000000000000); + try test_i128_intFromFloat_f128(0x1.0000000000001p+63, 0x8000000000000800); + + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + try test_i128_intFromFloat_f128(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + try test_i128_intFromFloat_f128(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + try test_i128_intFromFloat_f128(math.floatMax(f128), math.maxInt(i128)); } -test "fixunstfti" { - try test__fixunstfti(math.inf(f128), 0xffffffffffffffffffffffffffffffff); +test u128_intFromFloat_f128 { + try test_u128_intFromFloat_f128(math.inf(f128), 0xffffffffffffffffffffffffffffffff); - try test__fixunstfti(0.0, 0); + try test_u128_intFromFloat_f128(0.0, 0); - try test__fixunstfti(0.5, 0); - try test__fixunstfti(0.99, 0); - try test__fixunstfti(1.0, 1); - try test__fixunstfti(1.5, 1); - try test__fixunstfti(1.99, 1); - try test__fixunstfti(2.0, 2); - try test__fixunstfti(2.01, 2); - try test__fixunstfti(-0.01, 0); - try test__fixunstfti(-0.99, 0); + try test_u128_intFromFloat_f128(0.5, 0); + try test_u128_intFromFloat_f128(0.99, 0); + try test_u128_intFromFloat_f128(1.0, 1); + try test_u128_intFromFloat_f128(1.5, 1); + try test_u128_intFromFloat_f128(1.99, 1); + try test_u128_intFromFloat_f128(2.0, 2); + try test_u128_intFromFloat_f128(2.01, 2); + try test_u128_intFromFloat_f128(-0.01, 0); + try test_u128_intFromFloat_f128(-0.99, 0); - try test__fixunstfti(0x1p+128, 0xffffffffffffffffffffffffffffffff); + try test_u128_intFromFloat_f128(0x1p+128, 0xffffffffffffffffffffffffffffffff); - try test__fixunstfti(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000); - try test__fixunstfti(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000); - try test__fixunstfti(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff); - try test__fixunstfti(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff); + try test_u128_intFromFloat_f128(0x1.FFFFFEp+126, 0x7fffff80000000000000000000000000); + try test_u128_intFromFloat_f128(0x1.FFFFFEp+127, 0xffffff00000000000000000000000000); + try test_u128_intFromFloat_f128(0x1.FFFFFEp+128, 0xffffffffffffffffffffffffffffffff); + try test_u128_intFromFloat_f128(0x1.FFFFFEp+129, 0xffffffffffffffffffffffffffffffff); } -fn test__fixunshfti(a: f16, expected: u128) !void { - const x = __fixunshfti(a); +fn test_u128_intFromFloat_f16(a: f16, expected: u128) !void { + const x = impl.u128_intFromFloat_f16(a); try testing.expect(x == expected); } -test "fixunshfti for f16" { - try test__fixunshfti(math.inf(f16), math.maxInt(u128)); - try test__fixunshfti(math.floatMax(f16), 65504); +test u128_intFromFloat_f16 { + try test_u128_intFromFloat_f16(math.inf(f16), math.maxInt(u128)); + try test_u128_intFromFloat_f16(math.floatMax(f16), 65504); } -fn test__fixunsxfti(a: f80, expected: u128) !void { - const x = __fixunsxfti(a); +fn test_u128_intFromFloat_f80(a: f80, expected: u128) !void { + const x = impl.u128_intFromFloat_f80(a); try testing.expect(x == expected); } -test "fixunsxfti for f80" { - try test__fixunsxfti(math.inf(f80), math.maxInt(u128)); - try test__fixunsxfti(math.floatMax(f80), math.maxInt(u128)); - try test__fixunsxfti(math.maxInt(u64), math.maxInt(u64)); +test u128_intFromFloat_f80 { + try test_u128_intFromFloat_f80(math.inf(f80), math.maxInt(u128)); + try test_u128_intFromFloat_f80(math.floatMax(f80), math.maxInt(u128)); + try test_u128_intFromFloat_f80(math.maxInt(u64), math.maxInt(u64)); } diff --git a/lib/compiler_rt/limb64.zig b/lib/compiler_rt/limb64.zig index bfe4c441f0525b2e7f5e858e3fa98f81a2e9c865..1d41c0ff1f673c4822b69ccbf0eee69faad19b51 100644 --- a/lib/compiler_rt/limb64.zig +++ b/lib/compiler_rt/limb64.zig @@ -6,7 +6,7 @@ const minInt = std.math.minInt; const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const endian = builtin.cpu.arch.endian(); diff --git a/lib/compiler_rt/log.zig b/lib/compiler_rt/log.zig index da3757d8224c2ab62e88affd269170b5c64cae6b..8b2937921d5998941e7731ac8decce71f60c85cb 100644 --- a/lib/compiler_rt/log.zig +++ b/lib/compiler_rt/log.zig @@ -11,26 +11,29 @@ const expectEqual = std.testing.expectEqual; const expectApproxEqRel = std.testing.expectApproxEqRel; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { symbol(&__logh, "__logh"); symbol(&logf, "logf"); symbol(&log, "log"); symbol(&__logx, "__logx"); - if (compiler_rt.want_ppc_abi) { - symbol(&logq, "logf128"); - } - symbol(&logq, "logq"); + symbol(&logq, "logf128"); symbol(&logl, "logl"); } -pub fn __logh(a: f16) callconv(.c) f16 { +fn __logh(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(log_f16(compiler_rt.f16.fromAbi(a))); +} +pub fn log_f16(a: f16) f16 { // TODO: more efficient implementation - return @floatCast(logf(a)); + return @floatCast(log_f32(a)); } -pub fn logf(x_: f32) callconv(.c) f32 { +fn logf(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(log_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn log_f32(x_: f32) f32 { const ln2_hi: f32 = 6.9313812256e-01; const ln2_lo: f32 = 9.0580006145e-06; const Lg1: f32 = 0xaaaaaa.0p-24; @@ -82,7 +85,10 @@ pub fn logf(x_: f32) callconv(.c) f32 { return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi; } -pub fn log(x: f64) callconv(.c) f64 { +fn log(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(log_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn log_f64(x: f64) f64 { const poly1 = [_]f64{ -0x1p-1, 0x1.5555555555577p-2, @@ -432,11 +438,17 @@ pub fn log(x: f64) callconv(.c) f64 { return @bitCast(y); } -pub fn __logx(a: f80) callconv(.c) f80 { +fn __logx(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(log_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn log_f80(a: f80) f80 { // TODO: more efficient implementation - return @floatCast(logq(a)); + return @floatCast(log_f128(a)); } +fn logq(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(log_f128(compiler_rt.f128.fromAbi(a))); +} /// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic" /// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990 /// @@ -449,7 +461,7 @@ pub fn __logx(a: f80) callconv(.c) f80 { /// /// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case): /// <= 0.5 ulp: 99.96%, worst case <= 0.528 ulp -pub fn logq(x: f128) callconv(.c) f128 { +pub fn log_f128(x: f128) f128 { const impl = @import("log_f128.zig"); if (impl.specialCases(x)) |y| @@ -626,123 +638,123 @@ pub fn logq(x: f128) callconv(.c) f128 { pub fn logl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return log(x), - 80 => return __logx(x), - 128 => return logq(x), - else => @compileError("unreachable"), + 64 => return log_f64(x), + 80 => return log_f80(x), + 128 => return log_f128(x), + else => comptime unreachable, } } test "logf() special" { - try expectEqual(logf(0.0), -math.inf(f32)); - try expectEqual(logf(-0.0), -math.inf(f32)); - try expect(math.isPositiveZero(logf(1.0))); - try expectEqual(logf(math.e), 1.0); - try expectEqual(logf(math.inf(f32)), math.inf(f32)); - try expect(math.isNan(logf(-1.0))); - try expect(math.isNan(logf(-math.inf(f32)))); - try expect(math.isNan(logf(math.nan(f32)))); - try expect(math.isNan(logf(math.snan(f32)))); + try expectEqual(log_f32(0.0), -math.inf(f32)); + try expectEqual(log_f32(-0.0), -math.inf(f32)); + try expect(math.isPositiveZero(log_f32(1.0))); + try expectEqual(log_f32(math.e), 1.0); + try expectEqual(log_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isNan(log_f32(-1.0))); + try expect(math.isNan(log_f32(-math.inf(f32)))); + try expect(math.isNan(log_f32(math.nan(f32)))); + try expect(math.isNan(log_f32(math.snan(f32)))); } test "logf() sanity" { - try expect(math.isNan(logf(-0x1.0223a0p+3))); - try expectEqual(logf(0x1.161868p+2), 0x1.7815b0p+0); - try expect(math.isNan(logf(-0x1.0c34b4p+3))); - try expect(math.isNan(logf(-0x1.a206f0p+2))); - try expectEqual(logf(0x1.288bbcp+3), 0x1.1cfcd6p+1); - try expectEqual(logf(0x1.52efd0p-1), -0x1.a6694cp-2); - try expect(math.isNan(logf(-0x1.a05cc8p-2))); - try expectEqual(logf(0x1.1f9efap-1), -0x1.2742bap-1); - try expectEqual(logf(0x1.8c5db0p-1), -0x1.062160p-2); - try expect(math.isNan(logf(-0x1.5b86eap-1))); + try expect(math.isNan(log_f32(-0x1.0223a0p+3))); + try expectEqual(log_f32(0x1.161868p+2), 0x1.7815b0p+0); + try expect(math.isNan(log_f32(-0x1.0c34b4p+3))); + try expect(math.isNan(log_f32(-0x1.a206f0p+2))); + try expectEqual(log_f32(0x1.288bbcp+3), 0x1.1cfcd6p+1); + try expectEqual(log_f32(0x1.52efd0p-1), -0x1.a6694cp-2); + try expect(math.isNan(log_f32(-0x1.a05cc8p-2))); + try expectEqual(log_f32(0x1.1f9efap-1), -0x1.2742bap-1); + try expectEqual(log_f32(0x1.8c5db0p-1), -0x1.062160p-2); + try expect(math.isNan(log_f32(-0x1.5b86eap-1))); } test "logf() boundary" { - try expectEqual(logf(0x1.fffffep+127), 0x1.62e430p+6); // Max input value - try expectEqual(logf(0x1p-149), -0x1.9d1da0p+6); // Min positive input value - try expect(math.isNan(logf(-0x1p-149))); // Min negative input value - try expectEqual(logf(0x1.000002p+0), 0x1.fffffep-24); // Last value before result reaches +0 - try expectEqual(logf(0x1.fffffep-1), -0x1p-24); // Last value before result reaches -0 - try expectEqual(logf(0x1p-126), -0x1.5d58a0p+6); // First subnormal - try expect(math.isNan(logf(-0x1p-126))); // First negative subnormal + try expectEqual(log_f32(0x1.fffffep+127), 0x1.62e430p+6); // Max input value + try expectEqual(log_f32(0x1p-149), -0x1.9d1da0p+6); // Min positive input value + try expect(math.isNan(log_f32(-0x1p-149))); // Min negative input value + try expectEqual(log_f32(0x1.000002p+0), 0x1.fffffep-24); // Last value before result reaches +0 + try expectEqual(log_f32(0x1.fffffep-1), -0x1p-24); // Last value before result reaches -0 + try expectEqual(log_f32(0x1p-126), -0x1.5d58a0p+6); // First subnormal + try expect(math.isNan(log_f32(-0x1p-126))); // First negative subnormal } test "log() special" { - try expectEqual(log(0.0), -math.inf(f64)); - try expectEqual(log(-0.0), -math.inf(f64)); - try expect(math.isPositiveZero(log(1.0))); - try expectEqual(log(math.e), 1.0); - try expectEqual(log(math.inf(f64)), math.inf(f64)); - try expect(math.isNan(log(-1.0))); - try expect(math.isNan(log(-math.inf(f64)))); - try expect(math.isNan(log(math.nan(f64)))); - try expect(math.isNan(log(math.snan(f64)))); + try expectEqual(log_f64(0.0), -math.inf(f64)); + try expectEqual(log_f64(-0.0), -math.inf(f64)); + try expect(math.isPositiveZero(log_f64(1.0))); + try expectEqual(log_f64(math.e), 1.0); + try expectEqual(log_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isNan(log_f64(-1.0))); + try expect(math.isNan(log_f64(-math.inf(f64)))); + try expect(math.isNan(log_f64(math.nan(f64)))); + try expect(math.isNan(log_f64(math.snan(f64)))); } test "log() sanity" { - try expect(math.isNan(log(-0x1.02239f3c6a8f1p+3))); - try expectEqual(log(0x1.161868e18bc67p+2), 0x1.7815b08f99c65p+0); - try expect(math.isNan(log(-0x1.0c34b3e01e6e7p+3))); - try expect(math.isNan(log(-0x1.a206f0a19dcc4p+2))); - try expectEqual(log(0x1.288bbb0d6a1e6p+3), 0x1.1cfcd53d72604p+1); - try expectEqual(log(0x1.52efd0cd80497p-1), -0x1.a6694a4a85621p-2); - try expect(math.isNan(log(-0x1.a05cc754481d1p-2))); - try expectEqual(log(0x1.1f9ef934745cbp-1), -0x1.2742bc03d02ddp-1); - try expectEqual(log(0x1.8c5db097f7442p-1), -0x1.06215de4a3f92p-2); - try expect(math.isNan(log(-0x1.5b86ea8118a0ep-1))); + try expect(math.isNan(log_f64(-0x1.02239f3c6a8f1p+3))); + try expectEqual(log_f64(0x1.161868e18bc67p+2), 0x1.7815b08f99c65p+0); + try expect(math.isNan(log_f64(-0x1.0c34b3e01e6e7p+3))); + try expect(math.isNan(log_f64(-0x1.a206f0a19dcc4p+2))); + try expectEqual(log_f64(0x1.288bbb0d6a1e6p+3), 0x1.1cfcd53d72604p+1); + try expectEqual(log_f64(0x1.52efd0cd80497p-1), -0x1.a6694a4a85621p-2); + try expect(math.isNan(log_f64(-0x1.a05cc754481d1p-2))); + try expectEqual(log_f64(0x1.1f9ef934745cbp-1), -0x1.2742bc03d02ddp-1); + try expectEqual(log_f64(0x1.8c5db097f7442p-1), -0x1.06215de4a3f92p-2); + try expect(math.isNan(log_f64(-0x1.5b86ea8118a0ep-1))); } test "log() boundary" { - try expectEqual(log(0x1.fffffffffffffp+1023), 0x1.62e42fefa39efp+9); // Max input value - try expectEqual(log(0x1p-1074), -0x1.74385446d71c3p+9); // Min positive input value - try expect(math.isNan(log(-0x1p-1074))); // Min negative input value - try expectEqual(log(0x1.0000000000001p+0), 0x1.fffffffffffffp-53); // Last value before result reaches +0 - try expectEqual(log(0x1.fffffffffffffp-1), -0x1p-53); // Last value before result reaches -0 - try expectEqual(log(0x1p-1022), -0x1.6232bdd7abcd2p+9); // First subnormal - try expect(math.isNan(log(-0x1p-1022))); // First negative subnormal + try expectEqual(log_f64(0x1.fffffffffffffp+1023), 0x1.62e42fefa39efp+9); // Max input value + try expectEqual(log_f64(0x1p-1074), -0x1.74385446d71c3p+9); // Min positive input value + try expect(math.isNan(log_f64(-0x1p-1074))); // Min negative input value + try expectEqual(log_f64(0x1.0000000000001p+0), 0x1.fffffffffffffp-53); // Last value before result reaches +0 + try expectEqual(log_f64(0x1.fffffffffffffp-1), -0x1p-53); // Last value before result reaches -0 + try expectEqual(log_f64(0x1p-1022), -0x1.6232bdd7abcd2p+9); // First subnormal + try expect(math.isNan(log_f64(-0x1p-1022))); // First negative subnormal } test "logq() special" { - try expectEqual(logq(0.0), -math.inf(f128)); - try expectEqual(logq(-0.0), -math.inf(f128)); - try expect(math.isPositiveZero(logq(1.0))); + try expectEqual(log_f128(0.0), -math.inf(f128)); + try expectEqual(log_f128(-0.0), -math.inf(f128)); + try expect(math.isPositiveZero(log_f128(1.0))); // Sadly, the rounding gods decided that 0.9999999999999999999999999999999999 - // is the correctly rounded value of logq(math.e) - try expectApproxEqRel(logq(math.e), 1.0, math.floatEpsAt(f128, 1.0)); - try expectEqual(logq(math.inf(f128)), math.inf(f128)); - try expect(math.isNan(logq(-1.0))); - try expect(math.isNan(logq(-math.inf(f128)))); - try expect(math.isNan(logq(math.nan(f128)))); - try expect(math.isNan(logq(math.snan(f128)))); + // is the correctly rounded value of log_f128(math.e) + try expectApproxEqRel(log_f128(math.e), 1.0, math.floatEpsAt(f128, 1.0)); + try expectEqual(log_f128(math.inf(f128)), math.inf(f128)); + try expect(math.isNan(log_f128(-1.0))); + try expect(math.isNan(log_f128(-math.inf(f128)))); + try expect(math.isNan(log_f128(math.nan(f128)))); + try expect(math.isNan(log_f128(math.snan(f128)))); } test "logq() boundary" { - try expectEqual(logq(0x1.ffffffffffffffffffffffffffffp16383), 0x1.62e42fefa39ef35793c7673007e6p13); // Max input value - try expectEqual(logq(0x1p-16494), -0x1.6546282207802c89d24d65e96274p13); // Min positive input value - try expect(math.isNan(logq(-0x1p-16494))); // Min negative input value - try expectEqual(logq(0x1.0000000000000000000000000001p0), 0x1.ffffffffffffffffffffffffffffp-113); // Last value before result reaches +0 - try expectEqual(logq(0x1.ffffffffffffffffffffffffffffp-1), -0x1p-113); // Last value before result reaches -0 - try expectEqual(logq(0x1p-16382), -0x1.62d918ce2421d65ff90ac8f4ce66p13); // First subnormal - try expect(math.isNan(logq(-0x1p-16382))); // First negative subnormal + try expectEqual(log_f128(0x1.ffffffffffffffffffffffffffffp16383), 0x1.62e42fefa39ef35793c7673007e6p13); // Max input value + try expectEqual(log_f128(0x1p-16494), -0x1.6546282207802c89d24d65e96274p13); // Min positive input value + try expect(math.isNan(log_f128(-0x1p-16494))); // Min negative input value + try expectEqual(log_f128(0x1.0000000000000000000000000001p0), 0x1.ffffffffffffffffffffffffffffp-113); // Last value before result reaches +0 + try expectEqual(log_f128(0x1.ffffffffffffffffffffffffffffp-1), -0x1p-113); // Last value before result reaches -0 + try expectEqual(log_f128(0x1p-16382), -0x1.62d918ce2421d65ff90ac8f4ce66p13); // First subnormal + try expect(math.isNan(log_f128(-0x1p-16382))); // First negative subnormal } test "logq() sanity" { - try expectEqual(logq(4.151135979023751199079583784623537e-4), -7.7869583453055243113993340258295346e0); - try expectEqual(logq(9.614234245933828353176667689130293e-14), -2.9972946567656004014786271559909435e1); - try expectEqual(logq(1.012889803704721484375e13), 2.9946413646144315985379677542014356e1); - try expectEqual(logq(2.397741857206453154086912e24), 5.613656963346284538829358703465392e1); - try expectEqual(logq(3.442377567808290806386655232e27), 6.3405959896920645453203836625419693e1); - try expectEqual(logq(1.0689155158234028407981544637594257e-8), -1.835403614606774451014272772421113e1); - try expectEqual(logq(1.4813913545768791536741499811327596e-10), -2.263286917934202003739900705050399e1); - try expectEqual(logq(4.518948965781299591064453125e10), 2.453413036705097282892685629562292e1); - try expectEqual(logq(1.200355637363589375e14), 3.2418809179272977400408325788186897e1); - try expectEqual(logq(6.6145398293682003021240234375e9), 2.261253606737223221601998075023261e1); - try expectEqual(logq(5.16179116383965741056e20), 4.7692985503915646405875629300054525e1); + try expectEqual(log_f128(4.151135979023751199079583784623537e-4), -7.7869583453055243113993340258295346e0); + try expectEqual(log_f128(9.614234245933828353176667689130293e-14), -2.9972946567656004014786271559909435e1); + try expectEqual(log_f128(1.012889803704721484375e13), 2.9946413646144315985379677542014356e1); + try expectEqual(log_f128(2.397741857206453154086912e24), 5.613656963346284538829358703465392e1); + try expectEqual(log_f128(3.442377567808290806386655232e27), 6.3405959896920645453203836625419693e1); + try expectEqual(log_f128(1.0689155158234028407981544637594257e-8), -1.835403614606774451014272772421113e1); + try expectEqual(log_f128(1.4813913545768791536741499811327596e-10), -2.263286917934202003739900705050399e1); + try expectEqual(log_f128(4.518948965781299591064453125e10), 2.453413036705097282892685629562292e1); + try expectEqual(log_f128(1.200355637363589375e14), 3.2418809179272977400408325788186897e1); + try expectEqual(log_f128(6.6145398293682003021240234375e9), 2.261253606737223221601998075023261e1); + try expectEqual(log_f128(5.16179116383965741056e20), 4.7692985503915646405875629300054525e1); // testing near 1 - try expectEqual(logq(1.026586845186097528392910049888087e0), 2.6239557099466251374193777672800004e-2); - try expectEqual(logq(9.878220373715243107115568932385941e-1), -1.2252721576456821219120474521538944e-2); - try expectEqual(logq(9.417921077517196685541245315675951e-1), -5.997072116986790367958922503195352e-2); - try expectEqual(logq(1.043095786320424537962914257605007e0), 4.219300911769055080390811808602425e-2); - try expectEqual(logq(1.019043049323190694932517175175235e0), 1.8863999985309781522599012445793722e-2); + try expectEqual(log_f128(1.026586845186097528392910049888087e0), 2.6239557099466251374193777672800004e-2); + try expectEqual(log_f128(9.878220373715243107115568932385941e-1), -1.2252721576456821219120474521538944e-2); + try expectEqual(log_f128(9.417921077517196685541245315675951e-1), -5.997072116986790367958922503195352e-2); + try expectEqual(log_f128(1.043095786320424537962914257605007e0), 4.219300911769055080390811808602425e-2); + try expectEqual(log_f128(1.019043049323190694932517175175235e0), 1.8863999985309781522599012445793722e-2); } diff --git a/lib/compiler_rt/log10.zig b/lib/compiler_rt/log10.zig index 18479d534a347721c842b682228f29688213909c..0813c1ae7c0dc6d71ae7aa2699f17e05bdffe039 100644 --- a/lib/compiler_rt/log10.zig +++ b/lib/compiler_rt/log10.zig @@ -18,19 +18,22 @@ comptime { symbol(&log10f, "log10f"); symbol(&log10, "log10"); symbol(&__log10x, "__log10x"); - if (compiler_rt.want_ppc_abi) { - symbol(&log10q, "log10f128"); - } - symbol(&log10q, "log10q"); + symbol(&log10q, "log10f128"); symbol(&log10l, "log10l"); } -pub fn __log10h(a: f16) callconv(.c) f16 { +fn __log10h(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(log10_f16(compiler_rt.f16.fromAbi(a))); +} +pub fn log10_f16(a: f16) f16 { // TODO: more efficient implementation - return @floatCast(log10f(a)); + return @floatCast(log10_f32(a)); } -pub fn log10f(x_: f32) callconv(.c) f32 { +fn log10f(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(log10_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn log10_f32(x_: f32) f32 { const ivln10hi: f32 = 4.3432617188e-01; const ivln10lo: f32 = -3.1689971365e-05; const log10_2hi: f32 = 3.0102920532e-01; @@ -90,7 +93,10 @@ pub fn log10f(x_: f32) callconv(.c) f32 { return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi; } -pub fn log10(x_: f64) callconv(.c) f64 { +fn log10(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(log10_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn log10_f64(x_: f64) f64 { const ivln10hi: f64 = 4.34294481878168880939e-01; const ivln10lo: f64 = 2.50829467116452752298e-11; const log10_2hi: f64 = 3.01029995663611771306e-01; @@ -165,11 +171,17 @@ pub fn log10(x_: f64) callconv(.c) f64 { return val_lo + val_hi; } -pub fn __log10x(a: f80) callconv(.c) f80 { +fn __log10x(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(log10_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn log10_f80(a: f80) f80 { // TODO: more efficient implementation - return @floatCast(log10q(a)); + return @floatCast(log10_f128(a)); } +fn log10q(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(log10_f128(compiler_rt.f128.fromAbi(a))); +} /// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic" /// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990 /// @@ -182,7 +194,7 @@ pub fn __log10x(a: f80) callconv(.c) f80 { /// /// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case): /// <= 0.5 ulp: 99.96%, worst case <= 0.565 ulp -pub fn log10q(x: f128) callconv(.c) f128 { +pub fn log10_f128(x: f128) f128 { const impl = @import("log_f128.zig"); if (impl.specialCases(x)) |y| @@ -359,124 +371,124 @@ pub fn log10q(x: f128) callconv(.c) f128 { pub fn log10l(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return log10(x), - 80 => return __log10x(x), - 128 => return log10q(x), - else => @compileError("unreachable"), + 64 => return log10_f64(x), + 80 => return log10_f80(x), + 128 => return log10_f128(x), + else => comptime unreachable, } } test "log10f() special" { - try expectEqual(log10f(0.0), -math.inf(f32)); - try expectEqual(log10f(-0.0), -math.inf(f32)); - try expect(math.isPositiveZero(log10f(1.0))); - try expectEqual(log10f(10.0), 1.0); - try expectEqual(log10f(0.1), -1.0); - try expectEqual(log10f(math.inf(f32)), math.inf(f32)); - try expect(math.isNan(log10f(-1.0))); - try expect(math.isNan(log10f(-math.inf(f32)))); - try expect(math.isNan(log10f(math.nan(f32)))); - try expect(math.isNan(log10f(math.snan(f32)))); + try expectEqual(log10_f32(0.0), -math.inf(f32)); + try expectEqual(log10_f32(-0.0), -math.inf(f32)); + try expect(math.isPositiveZero(log10_f32(1.0))); + try expectEqual(log10_f32(10.0), 1.0); + try expectEqual(log10_f32(0.1), -1.0); + try expectEqual(log10_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isNan(log10_f32(-1.0))); + try expect(math.isNan(log10_f32(-math.inf(f32)))); + try expect(math.isNan(log10_f32(math.nan(f32)))); + try expect(math.isNan(log10_f32(math.snan(f32)))); } test "log10f() sanity" { - try expect(math.isNan(log10f(-0x1.0223a0p+3))); - try expectEqual(log10f(0x1.161868p+2), 0x1.46a9bcp-1); - try expect(math.isNan(log10f(-0x1.0c34b4p+3))); - try expect(math.isNan(log10f(-0x1.a206f0p+2))); - try expectEqual(log10f(0x1.288bbcp+3), 0x1.ef1300p-1); - try expectEqual(log10f(0x1.52efd0p-1), -0x1.6ee6dcp-3); // Disagrees with GCC in last bit - try expect(math.isNan(log10f(-0x1.a05cc8p-2))); - try expectEqual(log10f(0x1.1f9efap-1), -0x1.0075ccp-2); - try expectEqual(log10f(0x1.8c5db0p-1), -0x1.c75df8p-4); - try expect(math.isNan(log10f(-0x1.5b86eap-1))); + try expect(math.isNan(log10_f32(-0x1.0223a0p+3))); + try expectEqual(log10_f32(0x1.161868p+2), 0x1.46a9bcp-1); + try expect(math.isNan(log10_f32(-0x1.0c34b4p+3))); + try expect(math.isNan(log10_f32(-0x1.a206f0p+2))); + try expectEqual(log10_f32(0x1.288bbcp+3), 0x1.ef1300p-1); + try expectEqual(log10_f32(0x1.52efd0p-1), -0x1.6ee6dcp-3); // Disagrees with GCC in last bit + try expect(math.isNan(log10_f32(-0x1.a05cc8p-2))); + try expectEqual(log10_f32(0x1.1f9efap-1), -0x1.0075ccp-2); + try expectEqual(log10_f32(0x1.8c5db0p-1), -0x1.c75df8p-4); + try expect(math.isNan(log10_f32(-0x1.5b86eap-1))); } test "log10f() boundary" { - try expectEqual(log10f(0x1.fffffep+127), 0x1.344136p+5); // Max input value - try expectEqual(log10f(0x1p-149), -0x1.66d3e8p+5); // Min positive input value - try expect(math.isNan(log10f(-0x1p-149))); // Min negative input value - try expectEqual(log10f(0x1.000002p+0), 0x1.bcb7b0p-25); // Last value before result reaches +0 - try expectEqual(log10f(0x1.fffffep-1), -0x1.bcb7b2p-26); // Last value before result reaches -0 - try expectEqual(log10f(0x1p-126), -0x1.2f7030p+5); // First subnormal - try expect(math.isNan(log10f(-0x1p-126))); // First negative subnormal + try expectEqual(log10_f32(0x1.fffffep+127), 0x1.344136p+5); // Max input value + try expectEqual(log10_f32(0x1p-149), -0x1.66d3e8p+5); // Min positive input value + try expect(math.isNan(log10_f32(-0x1p-149))); // Min negative input value + try expectEqual(log10_f32(0x1.000002p+0), 0x1.bcb7b0p-25); // Last value before result reaches +0 + try expectEqual(log10_f32(0x1.fffffep-1), -0x1.bcb7b2p-26); // Last value before result reaches -0 + try expectEqual(log10_f32(0x1p-126), -0x1.2f7030p+5); // First subnormal + try expect(math.isNan(log10_f32(-0x1p-126))); // First negative subnormal } test "log10() special" { - try expectEqual(log10(0.0), -math.inf(f64)); - try expectEqual(log10(-0.0), -math.inf(f64)); - try expect(math.isPositiveZero(log10(1.0))); - try expectEqual(log10(10.0), 1.0); - try expectEqual(log10(0.1), -1.0); - try expectEqual(log10(math.inf(f64)), math.inf(f64)); - try expect(math.isNan(log10(-1.0))); - try expect(math.isNan(log10(-math.inf(f64)))); - try expect(math.isNan(log10(math.nan(f64)))); - try expect(math.isNan(log10(math.snan(f64)))); + try expectEqual(log10_f64(0.0), -math.inf(f64)); + try expectEqual(log10_f64(-0.0), -math.inf(f64)); + try expect(math.isPositiveZero(log10_f64(1.0))); + try expectEqual(log10_f64(10.0), 1.0); + try expectEqual(log10_f64(0.1), -1.0); + try expectEqual(log10_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isNan(log10_f64(-1.0))); + try expect(math.isNan(log10_f64(-math.inf(f64)))); + try expect(math.isNan(log10_f64(math.nan(f64)))); + try expect(math.isNan(log10_f64(math.snan(f64)))); } test "log10() sanity" { - try expect(math.isNan(log10(-0x1.02239f3c6a8f1p+3))); - try expectEqual(log10(0x1.161868e18bc67p+2), 0x1.46a9bd1d2eb87p-1); - try expect(math.isNan(log10(-0x1.0c34b3e01e6e7p+3))); - try expect(math.isNan(log10(-0x1.a206f0a19dcc4p+2))); - try expectEqual(log10(0x1.288bbb0d6a1e6p+3), 0x1.ef12fff994862p-1); - try expectEqual(log10(0x1.52efd0cd80497p-1), -0x1.6ee6db5a155cbp-3); - try expect(math.isNan(log10(-0x1.a05cc754481d1p-2))); - try expectEqual(log10(0x1.1f9ef934745cbp-1), -0x1.0075cda79d321p-2); - try expectEqual(log10(0x1.8c5db097f7442p-1), -0x1.c75df6442465ap-4); - try expect(math.isNan(log10(-0x1.5b86ea8118a0ep-1))); + try expect(math.isNan(log10_f64(-0x1.02239f3c6a8f1p+3))); + try expectEqual(log10_f64(0x1.161868e18bc67p+2), 0x1.46a9bd1d2eb87p-1); + try expect(math.isNan(log10_f64(-0x1.0c34b3e01e6e7p+3))); + try expect(math.isNan(log10_f64(-0x1.a206f0a19dcc4p+2))); + try expectEqual(log10_f64(0x1.288bbb0d6a1e6p+3), 0x1.ef12fff994862p-1); + try expectEqual(log10_f64(0x1.52efd0cd80497p-1), -0x1.6ee6db5a155cbp-3); + try expect(math.isNan(log10_f64(-0x1.a05cc754481d1p-2))); + try expectEqual(log10_f64(0x1.1f9ef934745cbp-1), -0x1.0075cda79d321p-2); + try expectEqual(log10_f64(0x1.8c5db097f7442p-1), -0x1.c75df6442465ap-4); + try expect(math.isNan(log10_f64(-0x1.5b86ea8118a0ep-1))); } test "log10() boundary" { - try expectEqual(log10(0x1.fffffffffffffp+1023), 0x1.34413509f79ffp+8); // Max input value - try expectEqual(log10(0x1p-1074), -0x1.434e6420f4374p+8); // Min positive input value - try expect(math.isNan(log10(-0x1p-1074))); // Min negative input value - try expectEqual(log10(0x1.0000000000001p+0), 0x1.bcb7b1526e50dp-54); // Last value before result reaches +0 - try expectEqual(log10(0x1.fffffffffffffp-1), -0x1.bcb7b1526e50fp-55); // Last value before result reaches -0 - try expectEqual(log10(0x1p-1022), -0x1.33a7146f72a42p+8); // First subnormal - try expect(math.isNan(log10(-0x1p-1022))); // First negative subnormal + try expectEqual(log10_f64(0x1.fffffffffffffp+1023), 0x1.34413509f79ffp+8); // Max input value + try expectEqual(log10_f64(0x1p-1074), -0x1.434e6420f4374p+8); // Min positive input value + try expect(math.isNan(log10_f64(-0x1p-1074))); // Min negative input value + try expectEqual(log10_f64(0x1.0000000000001p+0), 0x1.bcb7b1526e50dp-54); // Last value before result reaches +0 + try expectEqual(log10_f64(0x1.fffffffffffffp-1), -0x1.bcb7b1526e50fp-55); // Last value before result reaches -0 + try expectEqual(log10_f64(0x1p-1022), -0x1.33a7146f72a42p+8); // First subnormal + try expect(math.isNan(log10_f64(-0x1p-1022))); // First negative subnormal } test "log10q() special" { - try expectEqual(log10q(0.0), -math.inf(f128)); - try expectEqual(log10q(-0.0), -math.inf(f128)); - try expect(math.isPositiveZero(log10q(1.0))); - try expectEqual(log10q(10.0), 1.0); - try expectEqual(log10q(0.1), -1.0); - try expectEqual(log10q(math.inf(f128)), math.inf(f128)); - try expect(math.isNan(log10q(-1.0))); - try expect(math.isNan(log10q(-math.inf(f128)))); - try expect(math.isNan(log10q(math.nan(f128)))); - try expect(math.isNan(log10q(math.snan(f128)))); + try expectEqual(log10_f128(0.0), -math.inf(f128)); + try expectEqual(log10_f128(-0.0), -math.inf(f128)); + try expect(math.isPositiveZero(log10_f128(1.0))); + try expectEqual(log10_f128(10.0), 1.0); + try expectEqual(log10_f128(0.1), -1.0); + try expectEqual(log10_f128(math.inf(f128)), math.inf(f128)); + try expect(math.isNan(log10_f128(-1.0))); + try expect(math.isNan(log10_f128(-math.inf(f128)))); + try expect(math.isNan(log10_f128(math.nan(f128)))); + try expect(math.isNan(log10_f128(math.snan(f128)))); } test "log10q() sanity" { - try expectEqual(log10q(2.1744503117482705706605762784484114e1949), 1.949337349488073972035715318447419e3); - try expectEqual(log10q(2.3695331993665660983204066767386505e2150), 2.1503746627979481420243846411400265e3); - try expectEqual(log10q(1.8071775728314983136779370752110857e612), 6.122570008283284411311428111991705e2); - try expectEqual(log10q(2.612170297226630737309271722008693e-2629), -2.628582998513179919647069989114319e3); - try expectEqual(log10q(8.485091636263895897993044621224502e-3748), -3.7470713434630800881474518447042895e3); - try expectEqual(log10q(4.3668077579803801413736022136116655e-4051), -4.0503598359268068567757367259544416e3); - try expectEqual(log10q(2.9321353260885285826237030859036923e4830), 4.830467184010313310864606285356782e3); - try expectEqual(log10q(6.6119754254652455408442826553161645e-1417), -1.416179668769227128601620567685071e3); - try expectEqual(log10q(5.2459104673488555418645321788108695e4178), 4.178719820874155944446586083585479e3); - try expectEqual(log10q(7.809812890804996586377267218360886e-418), -4.1710735937091966815220294599598215e2); + try expectEqual(log10_f128(2.1744503117482705706605762784484114e1949), 1.949337349488073972035715318447419e3); + try expectEqual(log10_f128(2.3695331993665660983204066767386505e2150), 2.1503746627979481420243846411400265e3); + try expectEqual(log10_f128(1.8071775728314983136779370752110857e612), 6.122570008283284411311428111991705e2); + try expectEqual(log10_f128(2.612170297226630737309271722008693e-2629), -2.628582998513179919647069989114319e3); + try expectEqual(log10_f128(8.485091636263895897993044621224502e-3748), -3.7470713434630800881474518447042895e3); + try expectEqual(log10_f128(4.3668077579803801413736022136116655e-4051), -4.0503598359268068567757367259544416e3); + try expectEqual(log10_f128(2.9321353260885285826237030859036923e4830), 4.830467184010313310864606285356782e3); + try expectEqual(log10_f128(6.6119754254652455408442826553161645e-1417), -1.416179668769227128601620567685071e3); + try expectEqual(log10_f128(5.2459104673488555418645321788108695e4178), 4.178719820874155944446586083585479e3); + try expectEqual(log10_f128(7.809812890804996586377267218360886e-418), -4.1710735937091966815220294599598215e2); // testing near 1 - try expectEqual(log10q(1.0291437165967803055610652052109798e0), 1.2476026819466393459130418401605807e-2); - try expectEqual(log10q(1.043095786320424537962914257605007e0), 1.8324191034706598279642145362763252e-2); - try expectEqual(log10q(9.900264873754467234601150948947179e-1), -4.3531860417287584780652055666513634e-3); - try expectEqual(log10q(1.038295346547007736348611217636062e0), 1.6320907588397540309035279023485962e-2); - try expectEqual(log10q(9.821701941230028324703038578036285e-1), -7.813249520562034832371814409278784e-3); - try expectEqual(log10q(9.593555263530179895381522214847791e-1), -1.8020418356217558657107271163588764e-2); + try expectEqual(log10_f128(1.0291437165967803055610652052109798e0), 1.2476026819466393459130418401605807e-2); + try expectEqual(log10_f128(1.043095786320424537962914257605007e0), 1.8324191034706598279642145362763252e-2); + try expectEqual(log10_f128(9.900264873754467234601150948947179e-1), -4.3531860417287584780652055666513634e-3); + try expectEqual(log10_f128(1.038295346547007736348611217636062e0), 1.6320907588397540309035279023485962e-2); + try expectEqual(log10_f128(9.821701941230028324703038578036285e-1), -7.813249520562034832371814409278784e-3); + try expectEqual(log10_f128(9.593555263530179895381522214847791e-1), -1.8020418356217558657107271163588764e-2); } test "log10q() boundary" { - try expectEqual(log10q(0x1.ffffffffffffffffffffffffffffp16383), 0x1.34413509f79fef311f12b35816f9p12); // Max input value - try expectEqual(log10q(0x1p-16494), -0x1.3653051d20c18a143b801b7c5661p12); // Min positive input value - try expect(math.isNan(log10q(-0x1p-16494))); // Min negative input value - try expectEqual(log10q(0x1.0000000000000000000000000001p0), 0x1.bcb7b1526e50e32a6ab7555f5a67p-114); // Last value before result reaches +0 - try expectEqual(log10q(0x1.ffffffffffffffffffffffffffffp-1), -0x1.bcb7b1526e50e32a6ab7555f5a68p-115); // Last value before result reaches -0 - try expectEqual(log10q(0x1p-16382), -0x1.343793004f503231a589bac27c38p12); // First subnormal - try expect(math.isNan(log10q(-0x1p-16382))); // First negative subnormal + try expectEqual(log10_f128(0x1.ffffffffffffffffffffffffffffp16383), 0x1.34413509f79fef311f12b35816f9p12); // Max input value + try expectEqual(log10_f128(0x1p-16494), -0x1.3653051d20c18a143b801b7c5661p12); // Min positive input value + try expect(math.isNan(log10_f128(-0x1p-16494))); // Min negative input value + try expectEqual(log10_f128(0x1.0000000000000000000000000001p0), 0x1.bcb7b1526e50e32a6ab7555f5a67p-114); // Last value before result reaches +0 + try expectEqual(log10_f128(0x1.ffffffffffffffffffffffffffffp-1), -0x1.bcb7b1526e50e32a6ab7555f5a68p-115); // Last value before result reaches -0 + try expectEqual(log10_f128(0x1p-16382), -0x1.343793004f503231a589bac27c38p12); // First subnormal + try expect(math.isNan(log10_f128(-0x1p-16382))); // First negative subnormal } diff --git a/lib/compiler_rt/log2.zig b/lib/compiler_rt/log2.zig index 8db17aaf3f26f257482af43b7bc125d4747dbfe2..0806fb079419787d33dd3b825b4057aac51f1397 100644 --- a/lib/compiler_rt/log2.zig +++ b/lib/compiler_rt/log2.zig @@ -19,19 +19,22 @@ comptime { symbol(&log2f, "log2f"); symbol(&log2, "log2"); symbol(&__log2x, "__log2x"); - if (compiler_rt.want_ppc_abi) { - symbol(&log2q, "log2f128"); - } - symbol(&log2q, "log2q"); + symbol(&log2q, "log2f128"); symbol(&log2l, "log2l"); } -pub fn __log2h(a: f16) callconv(.c) f16 { +fn __log2h(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(log2_f16(compiler_rt.f16.fromAbi(a))); +} +pub fn log2_f16(a: f16) f16 { // TODO: more efficient implementation - return @floatCast(log2f(a)); + return @floatCast(log2_f32(a)); } -pub fn log2f(x_: f32) callconv(.c) f32 { +fn log2f(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(log2_f32(compiler_rt.f32.fromAbi(a))); +} +pub fn log2_f32(x_: f32) f32 { const ivln2hi: f32 = 1.4428710938e+00; const ivln2lo: f32 = -1.7605285393e-04; const Lg1: f32 = 0xaaaaaa.0p-24; @@ -87,7 +90,10 @@ pub fn log2f(x_: f32) callconv(.c) f32 { return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + @as(f32, @floatFromInt(k)); } -pub fn log2(x_: f64) callconv(.c) f64 { +fn log2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(log2_f64(compiler_rt.f64.fromAbi(a))); +} +pub fn log2_f64(x_: f64) f64 { const ivln2hi: f64 = 1.44269504072144627571e+00; const ivln2lo: f64 = 1.67517131648865118353e-10; const Lg1: f64 = 6.666666666666735130e-01; @@ -158,11 +164,17 @@ pub fn log2(x_: f64) callconv(.c) f64 { return val_lo + val_hi; } -pub fn __log2x(a: f80) callconv(.c) f80 { +fn __log2x(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(log2_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn log2_f80(a: f80) f80 { // TODO: more efficient implementation - return @floatCast(log2q(a)); + return @floatCast(log2_f128(a)); } +fn log2q(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(log2_f128(compiler_rt.f128.fromAbi(a))); +} /// Implementation of "Table-driven implementation of the logarithm function in IEEE floating-point arithmetic" /// by PTP Tang in ACM Transactions on Mathematical Software (TOMS), 1990 /// @@ -175,7 +187,7 @@ pub fn __log2x(a: f80) callconv(.c) f80 { /// /// Accuracy on 10 million random numbers near x = 1 (testing the proc2 case): /// <= 0.5 ulp: 99.86%, worst case <= 0.546 ulp -pub fn log2q(x: f128) callconv(.c) f128 { +pub fn log2_f128(x: f128) f128 { const impl = @import("log_f128.zig"); if (impl.specialCases(x)) |y| @@ -351,117 +363,117 @@ pub fn log2q(x: f128) callconv(.c) f128 { pub fn log2l(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return log2(x), - 80 => return __log2x(x), - 128 => return log2q(x), - else => @compileError("unreachable"), + 64 => return log2_f64(x), + 80 => return log2_f80(x), + 128 => return log2_f128(x), + else => comptime unreachable, } } test "log2f() special" { - try expectEqual(log2f(0.0), -math.inf(f32)); - try expectEqual(log2f(-0.0), -math.inf(f32)); - try expect(math.isPositiveZero(log2f(1.0))); - try expectEqual(log2f(2.0), 1.0); - try expectEqual(log2f(math.inf(f32)), math.inf(f32)); - try expect(math.isNan(log2f(-1.0))); - try expect(math.isNan(log2f(-math.inf(f32)))); - try expect(math.isNan(log2f(math.nan(f32)))); - try expect(math.isNan(log2f(math.snan(f32)))); + try expectEqual(log2_f32(0.0), -math.inf(f32)); + try expectEqual(log2_f32(-0.0), -math.inf(f32)); + try expect(math.isPositiveZero(log2_f32(1.0))); + try expectEqual(log2_f32(2.0), 1.0); + try expectEqual(log2_f32(math.inf(f32)), math.inf(f32)); + try expect(math.isNan(log2_f32(-1.0))); + try expect(math.isNan(log2_f32(-math.inf(f32)))); + try expect(math.isNan(log2_f32(math.nan(f32)))); + try expect(math.isNan(log2_f32(math.snan(f32)))); } test "log2f() sanity" { - try expect(math.isNan(log2f(-0x1.0223a0p+3))); - try expectEqual(log2f(0x1.161868p+2), 0x1.0f49acp+1); - try expect(math.isNan(log2f(-0x1.0c34b4p+3))); - try expect(math.isNan(log2f(-0x1.a206f0p+2))); - try expectEqual(log2f(0x1.288bbcp+3), 0x1.9b2676p+1); - try expectEqual(log2f(0x1.52efd0p-1), -0x1.30b494p-1); // Disagrees with GCC in last bit - try expect(math.isNan(log2f(-0x1.a05cc8p-2))); - try expectEqual(log2f(0x1.1f9efap-1), -0x1.a9f89ap-1); - try expectEqual(log2f(0x1.8c5db0p-1), -0x1.7a2c96p-2); - try expect(math.isNan(log2f(-0x1.5b86eap-1))); + try expect(math.isNan(log2_f32(-0x1.0223a0p+3))); + try expectEqual(log2_f32(0x1.161868p+2), 0x1.0f49acp+1); + try expect(math.isNan(log2_f32(-0x1.0c34b4p+3))); + try expect(math.isNan(log2_f32(-0x1.a206f0p+2))); + try expectEqual(log2_f32(0x1.288bbcp+3), 0x1.9b2676p+1); + try expectEqual(log2_f32(0x1.52efd0p-1), -0x1.30b494p-1); // Disagrees with GCC in last bit + try expect(math.isNan(log2_f32(-0x1.a05cc8p-2))); + try expectEqual(log2_f32(0x1.1f9efap-1), -0x1.a9f89ap-1); + try expectEqual(log2_f32(0x1.8c5db0p-1), -0x1.7a2c96p-2); + try expect(math.isNan(log2_f32(-0x1.5b86eap-1))); } test "log2f() boundary" { - try expectEqual(log2f(0x1.fffffep+127), 0x1p+7); // Max input value - try expectEqual(log2f(0x1p-149), -0x1.2ap+7); // Min positive input value - try expect(math.isNan(log2f(-0x1p-149))); // Min negative input value - try expectEqual(log2f(0x1.000002p+0), 0x1.715474p-23); // Last value before result reaches +0 - try expectEqual(log2f(0x1.fffffep-1), -0x1.715478p-24); // Last value before result reaches -0 - try expectEqual(log2f(0x1p-126), -0x1.f8p+6); // First subnormal - try expect(math.isNan(log2f(-0x1p-126))); // First negative subnormal + try expectEqual(log2_f32(0x1.fffffep+127), 0x1p+7); // Max input value + try expectEqual(log2_f32(0x1p-149), -0x1.2ap+7); // Min positive input value + try expect(math.isNan(log2_f32(-0x1p-149))); // Min negative input value + try expectEqual(log2_f32(0x1.000002p+0), 0x1.715474p-23); // Last value before result reaches +0 + try expectEqual(log2_f32(0x1.fffffep-1), -0x1.715478p-24); // Last value before result reaches -0 + try expectEqual(log2_f32(0x1p-126), -0x1.f8p+6); // First subnormal + try expect(math.isNan(log2_f32(-0x1p-126))); // First negative subnormal } test "log2() special" { - try expectEqual(log2(0.0), -math.inf(f64)); - try expectEqual(log2(-0.0), -math.inf(f64)); - try expect(math.isPositiveZero(log2(1.0))); - try expectEqual(log2(2.0), 1.0); - try expectEqual(log2(math.inf(f64)), math.inf(f64)); - try expect(math.isNan(log2(-1.0))); - try expect(math.isNan(log2(-math.inf(f64)))); - try expect(math.isNan(log2(math.nan(f64)))); - try expect(math.isNan(log2(math.snan(f64)))); + try expectEqual(log2_f64(0.0), -math.inf(f64)); + try expectEqual(log2_f64(-0.0), -math.inf(f64)); + try expect(math.isPositiveZero(log2_f64(1.0))); + try expectEqual(log2_f64(2.0), 1.0); + try expectEqual(log2_f64(math.inf(f64)), math.inf(f64)); + try expect(math.isNan(log2_f64(-1.0))); + try expect(math.isNan(log2_f64(-math.inf(f64)))); + try expect(math.isNan(log2_f64(math.nan(f64)))); + try expect(math.isNan(log2_f64(math.snan(f64)))); } test "log2() sanity" { - try expect(math.isNan(log2(-0x1.02239f3c6a8f1p+3))); - try expectEqual(log2(0x1.161868e18bc67p+2), 0x1.0f49ac3838580p+1); - try expect(math.isNan(log2(-0x1.0c34b3e01e6e7p+3))); - try expect(math.isNan(log2(-0x1.a206f0a19dcc4p+2))); - try expectEqual(log2(0x1.288bbb0d6a1e6p+3), 0x1.9b26760c2a57ep+1); - try expectEqual(log2(0x1.52efd0cd80497p-1), -0x1.30b490ef684c7p-1); - try expect(math.isNan(log2(-0x1.a05cc754481d1p-2))); - try expectEqual(log2(0x1.1f9ef934745cbp-1), -0x1.a9f89b5f5acb8p-1); - try expectEqual(log2(0x1.8c5db097f7442p-1), -0x1.7a2c947173f06p-2); - try expect(math.isNan(log2(-0x1.5b86ea8118a0ep-1))); + try expect(math.isNan(log2_f64(-0x1.02239f3c6a8f1p+3))); + try expectEqual(log2_f64(0x1.161868e18bc67p+2), 0x1.0f49ac3838580p+1); + try expect(math.isNan(log2_f64(-0x1.0c34b3e01e6e7p+3))); + try expect(math.isNan(log2_f64(-0x1.a206f0a19dcc4p+2))); + try expectEqual(log2_f64(0x1.288bbb0d6a1e6p+3), 0x1.9b26760c2a57ep+1); + try expectEqual(log2_f64(0x1.52efd0cd80497p-1), -0x1.30b490ef684c7p-1); + try expect(math.isNan(log2_f64(-0x1.a05cc754481d1p-2))); + try expectEqual(log2_f64(0x1.1f9ef934745cbp-1), -0x1.a9f89b5f5acb8p-1); + try expectEqual(log2_f64(0x1.8c5db097f7442p-1), -0x1.7a2c947173f06p-2); + try expect(math.isNan(log2_f64(-0x1.5b86ea8118a0ep-1))); } test "log2() boundary" { - try expectEqual(log2(0x1.fffffffffffffp+1023), 0x1p+10); // Max input value - try expectEqual(log2(0x1p-1074), -0x1.0c8p+10); // Min positive input value - try expect(math.isNan(log2(-0x1p-1074))); // Min negative input value - try expectEqual(log2(0x1.0000000000001p+0), 0x1.71547652b82fdp-52); // Last value before result reaches +0 - try expectEqual(log2(0x1.fffffffffffffp-1), -0x1.71547652b82fep-53); // Last value before result reaches -0 - try expectEqual(log2(0x1p-1022), -0x1.ffp+9); // First subnormal - try expect(math.isNan(log2(-0x1p-1022))); // First negative subnormal + try expectEqual(log2_f64(0x1.fffffffffffffp+1023), 0x1p+10); // Max input value + try expectEqual(log2_f64(0x1p-1074), -0x1.0c8p+10); // Min positive input value + try expect(math.isNan(log2_f64(-0x1p-1074))); // Min negative input value + try expectEqual(log2_f64(0x1.0000000000001p+0), 0x1.71547652b82fdp-52); // Last value before result reaches +0 + try expectEqual(log2_f64(0x1.fffffffffffffp-1), -0x1.71547652b82fep-53); // Last value before result reaches -0 + try expectEqual(log2_f64(0x1p-1022), -0x1.ffp+9); // First subnormal + try expect(math.isNan(log2_f64(-0x1p-1022))); // First negative subnormal } test "log2q() special" { - try expectEqual(log2q(0.0), -math.inf(f128)); - try expectEqual(log2q(-0.0), -math.inf(f128)); - try expect(math.isPositiveZero(log2q(1.0))); - try expectEqual(log2q(2.0), 1.0); - try expectEqual(log2q(math.inf(f128)), math.inf(f128)); - try expect(math.isNan(log2q(-1.0))); - try expect(math.isNan(log2q(-math.inf(f128)))); - try expect(math.isNan(log2q(math.nan(f128)))); - try expect(math.isNan(log2q(math.snan(f128)))); + try expectEqual(log2_f128(0.0), -math.inf(f128)); + try expectEqual(log2_f128(-0.0), -math.inf(f128)); + try expect(math.isPositiveZero(log2_f128(1.0))); + try expectEqual(log2_f128(2.0), 1.0); + try expectEqual(log2_f128(math.inf(f128)), math.inf(f128)); + try expect(math.isNan(log2_f128(-1.0))); + try expect(math.isNan(log2_f128(-math.inf(f128)))); + try expect(math.isNan(log2_f128(math.nan(f128)))); + try expect(math.isNan(log2_f128(math.snan(f128)))); } test "log2q() boundary" { - try expectEqual(log2q(0x1.ffffffffffffffffffffffffffffp16383), 0x1p14); // Max input value - try expectEqual(log2q(0x1p-16494), -0x1.01b8p14); // Min positive input value - try expect(math.isNan(log2q(-0x1p-16494))); // Min negative input value - try expectEqual(log2q(0x1.0000000000000000000000000001p0), 0x1.71547652b82fe1777d0ffda0d23ap-112); // Last value before result reaches +0 - try expectEqual(log2q(0x1.ffffffffffffffffffffffffffffp-1), -0x1.71547652b82fe1777d0ffda0d23bp-113); // Last value before result reaches -0 - try expectEqual(log2q(0x1p-16382), -0x1.fffp13); // First subnormal - try expect(math.isNan(log2q(-0x1p-16382))); // First negative subnormal + try expectEqual(log2_f128(0x1.ffffffffffffffffffffffffffffp16383), 0x1p14); // Max input value + try expectEqual(log2_f128(0x1p-16494), -0x1.01b8p14); // Min positive input value + try expect(math.isNan(log2_f128(-0x1p-16494))); // Min negative input value + try expectEqual(log2_f128(0x1.0000000000000000000000000001p0), 0x1.71547652b82fe1777d0ffda0d23ap-112); // Last value before result reaches +0 + try expectEqual(log2_f128(0x1.ffffffffffffffffffffffffffffp-1), -0x1.71547652b82fe1777d0ffda0d23bp-113); // Last value before result reaches -0 + try expectEqual(log2_f128(0x1p-16382), -0x1.fffp13); // First subnormal + try expect(math.isNan(log2_f128(-0x1p-16382))); // First negative subnormal } test "log2q() sanity" { - try expectEqual(log2q(8.0965013884643408203125e11), 3.955850767769801288865582596068254e1); - try expectEqual(log2q(8.346531942223744e15), 5.28900982928636641107356163006646e1); - try expectEqual(log2q(9.707809913413123613777865431464565e-20), -6.315941603809020445822192336703809e1); - try expectEqual(log2q(1.9179565888043380306021427656243352e-24), -7.878670421065570557450089031998522e1); - try expectEqual(log2q(2.5260048200126556877075044745936796e-25), -8.17113449801679676275805009400338e1); - try expectEqual(log2q(3.1170134002568967640399932861328125e7), 2.489366102143423848582774267206741e1); + try expectEqual(log2_f128(8.0965013884643408203125e11), 3.955850767769801288865582596068254e1); + try expectEqual(log2_f128(8.346531942223744e15), 5.28900982928636641107356163006646e1); + try expectEqual(log2_f128(9.707809913413123613777865431464565e-20), -6.315941603809020445822192336703809e1); + try expectEqual(log2_f128(1.9179565888043380306021427656243352e-24), -7.878670421065570557450089031998522e1); + try expectEqual(log2_f128(2.5260048200126556877075044745936796e-25), -8.17113449801679676275805009400338e1); + try expectEqual(log2_f128(3.1170134002568967640399932861328125e7), 2.489366102143423848582774267206741e1); // test near 1 - try expectEqual(log2q(1.026586845186097528392910049888087e0), 3.7855678902522753591699367969189364e-2); - try expectEqual(log2q(1.0005582850578053877743656130405725e0), 8.052103367568488432896147152682078e-4); - try expectEqual(log2q(1.0370174103591254835765589348284266e0), 5.244011558596899945639244281954306e-2); - try expectEqual(log2q(1.0429996503525671713075162472250667e0), 6.073867421942172944687194557176633e-2); - try expectEqual(log2q(1.0383384027961064621892184334228659e0), 5.4276706191956281784022630732940314e-2); + try expectEqual(log2_f128(1.026586845186097528392910049888087e0), 3.7855678902522753591699367969189364e-2); + try expectEqual(log2_f128(1.0005582850578053877743656130405725e0), 8.052103367568488432896147152682078e-4); + try expectEqual(log2_f128(1.0370174103591254835765589348284266e0), 5.244011558596899945639244281954306e-2); + try expectEqual(log2_f128(1.0429996503525671713075162472250667e0), 6.073867421942172944687194557176633e-2); + try expectEqual(log2_f128(1.0383384027961064621892184334228659e0), 5.4276706191956281784022630732940314e-2); } diff --git a/lib/compiler_rt/memcpy.zig b/lib/compiler_rt/memcpy.zig index bb3c91eea83601771be7a61f1f4a8cd3d20e2249..b75f40ea4324448579f97f499cfb76493386adcf 100644 --- a/lib/compiler_rt/memcpy.zig +++ b/lib/compiler_rt/memcpy.zig @@ -11,7 +11,7 @@ comptime { .visibility = compiler_rt.visibility, }; - if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64) + if (builtin.mode == .small or builtin.zig_backend == .stage2_aarch64) @export(&memcpySmall, export_options) else @export(&memcpyFast, export_options); diff --git a/lib/compiler_rt/memmove.zig b/lib/compiler_rt/memmove.zig index ad501e758aba4bcd1b2247900369cbeffbd8275a..b02a4c7e54b538c0192a058caa660c465f09db5f 100644 --- a/lib/compiler_rt/memmove.zig +++ b/lib/compiler_rt/memmove.zig @@ -14,7 +14,7 @@ comptime { .visibility = compiler_rt.visibility, }; - if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64) + if (builtin.mode == .small or builtin.zig_backend == .stage2_aarch64) @export(&memmoveSmall, export_options) else @export(&memmoveFast, export_options); diff --git a/lib/compiler_rt/mulc3.zig b/lib/compiler_rt/mulc3.zig index eea753245f7687b2e3e9b65c12bdd278f1a3c757..fc0f2d24b4f603d9c933eb1328dbf5b73e4f41bc 100644 --- a/lib/compiler_rt/mulc3.zig +++ b/lib/compiler_rt/mulc3.zig @@ -3,19 +3,80 @@ const isNan = std.math.isNan; const isInf = std.math.isInf; const copysign = std.math.copysign; -pub fn Complex(comptime T: type) type { - return extern struct { - real: T, - imag: T, - }; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; +const Complex = compiler_rt.Complex; + +comptime { + if (@import("builtin").zig_backend != .stage2_c) { + symbol(&__mulhc3, "__mulhc3"); + symbol(&__mulsc3, "__mulsc3"); + symbol(&__muldc3, "__muldc3"); + symbol(&__mulxc3, "__mulxc3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__multc3, "__mulkc3"); + } else { + symbol(&__multc3, "__multc3"); + } + } +} + +fn __mulhc3(lhs_real: compiler_rt.f16.Abi, lhs_imag: compiler_rt.f16.Abi, rhs_real: compiler_rt.f16.Abi, rhs_imag: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.complex.Abi { + return compiler_rt.f16.complex.toAbi(mul_cf16( + compiler_rt.f16.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f16.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf16(a: Complex(f16), b: Complex(f16)) Complex(f16) { + return mulc3(f16, a, b); +} + +fn __mulsc3(lhs_real: compiler_rt.f32.Abi, lhs_imag: compiler_rt.f32.Abi, rhs_real: compiler_rt.f32.Abi, rhs_imag: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.complex.Abi { + return compiler_rt.f32.complex.toAbi(mul_cf32( + compiler_rt.f32.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f32.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf32(a: Complex(f32), b: Complex(f32)) Complex(f32) { + return mulc3(f32, a, b); +} + +fn __muldc3(lhs_real: compiler_rt.f64.Abi, lhs_imag: compiler_rt.f64.Abi, rhs_real: compiler_rt.f64.Abi, rhs_imag: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.complex.Abi { + return compiler_rt.f64.complex.toAbi(mul_cf64( + compiler_rt.f64.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f64.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf64(a: Complex(f64), b: Complex(f64)) Complex(f64) { + return mulc3(f64, a, b); +} + +fn __mulxc3(lhs_real: compiler_rt.f80.Abi, lhs_imag: compiler_rt.f80.Abi, rhs_real: compiler_rt.f80.Abi, rhs_imag: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.complex.Abi { + return compiler_rt.f80.complex.toAbi(mul_cf80( + compiler_rt.f80.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f80.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf80(a: Complex(f80), b: Complex(f80)) Complex(f80) { + return mulc3(f80, a, b); +} + +fn __multc3(lhs_real: compiler_rt.f128.Abi, lhs_imag: compiler_rt.f128.Abi, rhs_real: compiler_rt.f128.Abi, rhs_imag: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.complex.Abi { + return compiler_rt.f128.complex.toAbi(mul_cf128( + compiler_rt.f128.complex.fromAbi(.{ .real = lhs_real, .imag = lhs_imag }), + compiler_rt.f128.complex.fromAbi(.{ .real = rhs_real, .imag = rhs_imag }), + )); +} +pub fn mul_cf128(a: Complex(f128), b: Complex(f128)) Complex(f128) { + return mulc3(f128, a, b); } /// Implementation based on Annex G of C17 Standard (N2176) -pub inline fn mulc3(comptime T: type, a_in: T, b_in: T, c_in: T, d_in: T) Complex(T) { - var a = a_in; - var b = b_in; - var c = c_in; - var d = d_in; +inline fn mulc3(comptime T: type, lhs: Complex(T), rhs: Complex(T)) Complex(T) { + var a = lhs.real; + var b = lhs.imag; + var c = rhs.real; + var d = rhs.imag; const ac = a * c; const bd = b * d; @@ -77,3 +138,7 @@ pub inline fn mulc3(comptime T: type, a_in: T, b_in: T, c_in: T, d_in: T) Comple } return z; } + +test { + _ = @import("mulc3_test.zig"); +} diff --git a/lib/compiler_rt/mulc3_test.zig b/lib/compiler_rt/mulc3_test.zig index 3872cb34a6f9198dce4b482be03de720dce17696..748a3bc120ad6cfa3f82b2226f537a6bc63771b6 100644 --- a/lib/compiler_rt/mulc3_test.zig +++ b/lib/compiler_rt/mulc3_test.zig @@ -2,64 +2,45 @@ const std = @import("std"); const math = std.math; const expect = std.testing.expect; -const Complex = @import("./mulc3.zig").Complex; -const __mulhc3 = @import("./mulhc3.zig").__mulhc3; -const __mulsc3 = @import("./mulsc3.zig").__mulsc3; -const __muldc3 = @import("./muldc3.zig").__muldc3; -const __mulxc3 = @import("./mulxc3.zig").__mulxc3; -const __multc3 = @import("./multc3.zig").__multc3; +const Complex = @import("../compiler_rt.zig").Complex; +const impl = @import("mulc3.zig"); +const mul_cf16 = impl.mul_cf16; +const mul_cf32 = impl.mul_cf32; +const mul_cf64 = impl.mul_cf64; +const mul_cf80 = impl.mul_cf80; +const mul_cf128 = impl.mul_cf128; test "mulc3" { - try testMul(f16, __mulhc3); - try testMul(f32, __mulsc3); - try testMul(f64, __muldc3); - try testMul(f80, __mulxc3); - try testMul(f128, __multc3); + try testMul(f16, mul_cf16); + try testMul(f32, mul_cf32); + try testMul(f64, mul_cf64); + try testMul(f80, mul_cf80); + try testMul(f128, mul_cf128); } -fn testMul(comptime T: type, comptime f: fn (T, T, T, T) callconv(.c) Complex(T)) !void { +fn testMul(comptime T: type, comptime f: fn (Complex(T), Complex(T)) Complex(T)) !void { { - const a: T = 1.0; - const b: T = 0.0; - const c: T = -1.0; - const d: T = 0.0; - - const result = f(a, b, c, d); + const result = f(.{ .real = 1.0, .imag = 0.0 }, .{ .real = -1.0, .imag = 0.0 }); try expect(result.real == -1.0); - try expect(result.imag == 0.0); + try expect(math.isPositiveZero(result.imag)); } { - const a: T = 1.0; - const b: T = 0.0; - const c: T = -4.0; - const d: T = 0.0; - - const result = f(a, b, c, d); + const result = f(.{ .real = 1.0, .imag = 0.0 }, .{ .real = -4.0, .imag = 0.0 }); try expect(result.real == -4.0); - try expect(result.imag == 0.0); + try expect(math.isPositiveZero(result.imag)); } { // if one operand is an infinity and the other operand is a nonzero finite number or an infinity, // then the result of the * operator is an infinity; - const a: T = math.inf(T); - const b: T = -math.inf(T); - const c: T = 1.0; - const d: T = 0.0; - - const result = f(a, b, c, d); - try expect(result.real == math.inf(T)); - try expect(result.imag == -math.inf(T)); + const result = f(.{ .real = math.inf(T), .imag = -math.inf(T) }, .{ .real = 1.0, .imag = 0.0 }); + try expect(math.isPositiveInf(result.real)); + try expect(math.isNegativeInf(result.imag)); } { // if one operand is an infinity and the other operand is a nonzero finite number or an infinity, // then the result of the * operator is an infinity; - const a: T = math.inf(T); - const b: T = -1.0; - const c: T = 1.0; - const d: T = math.inf(T); - - const result = f(a, b, c, d); - try expect(result.real == math.inf(T)); - try expect(result.imag == math.inf(T)); + const result = f(.{ .real = math.inf(T), .imag = -1.0 }, .{ .real = 1.0, .imag = math.inf(T) }); + try expect(math.isPositiveInf(result.real)); + try expect(math.isPositiveInf(result.imag)); } } diff --git a/lib/compiler_rt/muldc3.zig b/lib/compiler_rt/muldc3.zig deleted file mode 100644 index d5facaa2b645670b6bf6e0953ec6b73342342329..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/muldc3.zig +++ /dev/null @@ -1,12 +0,0 @@ -const mulc3 = @import("./mulc3.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__muldc3, "__muldc3"); - } -} - -pub fn __muldc3(a: f64, b: f64, c: f64, d: f64) callconv(.c) mulc3.Complex(f64) { - return mulc3.mulc3(f64, a, b, c, d); -} diff --git a/lib/compiler_rt/muldf3.zig b/lib/compiler_rt/muldf3.zig deleted file mode 100644 index b8809e76da8d11e04c181d9dea86911aaac1cb29..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/muldf3.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dmul, "__aeabi_dmul"); - } else { - symbol(&__muldf3, "__muldf3"); - } -} - -pub fn __muldf3(a: f64, b: f64) callconv(.c) f64 { - return mulf3(f64, a, b); -} - -fn __aeabi_dmul(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return mulf3(f64, a, b); -} diff --git a/lib/compiler_rt/mulf3.zig b/lib/compiler_rt/mulf3.zig index d6b5a4719068cf2e27345f73e5f29994fc72e6d3..7367339dbc82f74dc99a9f6de7f842e8cbb71968 100644 --- a/lib/compiler_rt/mulf3.zig +++ b/lib/compiler_rt/mulf3.zig @@ -2,10 +2,76 @@ const std = @import("std"); const math = std.math; const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + symbol(&__mulhf3, "__mulhf3"); + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_fmul, "__aeabi_fmul"); + symbol(&__aeabi_dmul, "__aeabi_dmul"); + } else { + symbol(&__mulsf3, "__mulsf3"); + symbol(&__muldf3, "__muldf3"); + } + symbol(&__mulxf3, "__mulxf3"); + if (compiler_rt.want_ppc_abi) { + symbol(&__multf3, "__mulkf3"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_mul, "_Qp_mul"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__multf3, "_Q_mul"); + } else { + symbol(&__multf3, "__multf3"); + } +} + +fn __mulhf3(a: compiler_rt.f16.Abi, b: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(mul_f16(compiler_rt.f16.fromAbi(a), compiler_rt.f16.fromAbi(b))); +} +pub fn mul_f16(a: f16, b: f16) f16 { + return mulf3(f16, a, b); +} + +fn __mulsf3(a: compiler_rt.f32.Abi, b: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(mul_f32(compiler_rt.f32.fromAbi(a), compiler_rt.f32.fromAbi(b))); +} +fn __aeabi_fmul(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { + return mul_f32(a, b); +} +pub fn mul_f32(a: f32, b: f32) f32 { + return mulf3(f32, a, b); +} + +fn __muldf3(a: compiler_rt.f64.Abi, b: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(mul_f64(compiler_rt.f64.fromAbi(a), compiler_rt.f64.fromAbi(b))); +} +fn __aeabi_dmul(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { + return mul_f64(a, b); +} +pub fn mul_f64(a: f64, b: f64) f64 { + return mulf3(f64, a, b); +} + +fn __mulxf3(a: compiler_rt.f80.Abi, b: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(mul_f80(compiler_rt.f80.fromAbi(a), compiler_rt.f80.fromAbi(b))); +} +pub fn mul_f80(a: f80, b: f80) f80 { + return mulf3(f80, a, b); +} + +fn __multf3(a: compiler_rt.f128.Abi, b: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(mul_f128(compiler_rt.f128.fromAbi(a), compiler_rt.f128.fromAbi(b))); +} +fn _Qp_mul(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { + c.* = mul_f128(a.*, b.*); +} +pub fn mul_f128(a: f128, b: f128) f128 { + return mulf3(f128, a, b); +} /// Ported from: /// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc -pub inline fn mulf3(comptime T: type, a: T, b: T) T { +inline fn mulf3(comptime T: type, a: T, b: T) T { @setRuntimeSafety(compiler_rt.test_safety); const typeWidth = @typeInfo(T).float.bits; const significandBits = math.floatMantissaBits(T); diff --git a/lib/compiler_rt/mulf3_test.zig b/lib/compiler_rt/mulf3_test.zig index 751b8933f65bc20e4b630c125fa60f42d5e27529..a2595e21a6d1ca5dd44f1ce67e6dfb6b4ee4cd9f 100644 --- a/lib/compiler_rt/mulf3_test.zig +++ b/lib/compiler_rt/mulf3_test.zig @@ -7,10 +7,12 @@ const math = std.math; const qnan128: f128 = @bitCast(@as(u128, 0x7fff800000000000) << 64); const inf128: f128 = @bitCast(@as(u128, 0x7fff000000000000) << 64); -const __multf3 = @import("multf3.zig").__multf3; -const __mulxf3 = @import("mulxf3.zig").__mulxf3; -const __muldf3 = @import("muldf3.zig").__muldf3; -const __mulsf3 = @import("mulsf3.zig").__mulsf3; +const impl = @import("mulf3.zig"); +const mul_f16 = impl.mul_f16; +const mul_f32 = impl.mul_f32; +const mul_f64 = impl.mul_f64; +const mul_f80 = impl.mul_f80; +const mul_f128 = impl.mul_f128; // return true if equal // use two 64-bit integers instead of one 128-bit integer @@ -34,8 +36,8 @@ fn compareResultLD(result: f128, expectedHi: u64, expectedLo: u64) bool { return false; } -fn test__multf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { - const x = __multf3(a, b); +fn test_mul_f128(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void { + const x = mul_f128(a, b); if (compareResultLD(x, expected_hi, expected_lo)) return; @@ -49,68 +51,68 @@ fn makeNaN128(rand: u64) f128 { } test "multf3" { // qNaN * any = qNaN - try test__multf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + try test_mul_f128(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); // NaN * any = NaN const a = makeNaN128(0x800030000000); - try test__multf3(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + try test_mul_f128(a, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); // inf * any = inf - try test__multf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); + try test_mul_f128(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); // any * any - try test__multf3( + try test_mul_f128( @as(f128, @bitCast(@as(u128, 0x40042eab345678439abcdefea5678234))), @as(f128, @bitCast(@as(u128, 0x3ffeedcb34a235253948765432134675))), 0x400423e7f9e3c9fc, 0xd906c2c2a85777c4, ); - try test__multf3( + try test_mul_f128( @as(f128, @bitCast(@as(u128, 0x3fcd353e45674d89abacc3a2ebf3ff50))), @as(f128, @bitCast(@as(u128, 0x3ff6ed8764648369535adf4be3214568))), 0x3fc52a163c6223fc, 0xc94c4bf0430768b4, ); - try test__multf3( + try test_mul_f128( 0x1.234425696abcad34a35eeffefdcbap+456, 0x451.ed98d76e5d46e5f24323dff21ffp+600, 0x44293a91de5e0e94, 0xe8ed17cc2cdf64ac, ); - try test__multf3( + try test_mul_f128( @as(f128, @bitCast(@as(u128, 0x3f154356473c82a9fabf2d22ace345df))), @as(f128, @bitCast(@as(u128, 0x3e38eda98765476743ab21da23d45679))), 0x3d4f37c1a3137cae, 0xfc6807048bc2836a, ); - try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); + try test_mul_f128(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); // Denormal operands. - try test__multf3( + try test_mul_f128( 0x0.0000000000000000000000000001p-16382, 0x1p16383, 0x3f90000000000000, 0x0, ); - try test__multf3( + try test_mul_f128( 0x1p16383, 0x0.0000000000000000000000000001p-16382, 0x3f90000000000000, 0x0, ); - try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0001p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0002); - try test__multf3(0x1.0000_0000_0000_0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0003); - try test__multf3(2.0, math.floatTrueMin(f128), 0x0000_0000_0000_0000, 0x0000_0000_0000_0002); + try test_mul_f128(0x1.0000_0000_0000_0000_0000_0000_0001p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0002); + try test_mul_f128(0x1.0000_0000_0000_0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_8000_0000_0000, 0x0000_0000_0000_0003); + try test_mul_f128(2.0, math.floatTrueMin(f128), 0x0000_0000_0000_0000, 0x0000_0000_0000_0002); } const qnan80: f80 = @bitCast(@as(u80, @bitCast(math.nan(f80))) | (1 << (math.floatFractionalBits(f80) - 1))); -fn test__mulxf3(a: f80, b: f80, expected: u80) !void { - const x = __mulxf3(a, b); +fn test_mul_f80(a: f80, b: f80, expected: u80) !void { + const x = mul_f80(a, b); const rep: u80 = @bitCast(x); if (rep == expected) @@ -124,47 +126,47 @@ fn test__mulxf3(a: f80, b: f80, expected: u80) !void { test "mulxf3" { // NaN * any = NaN - try test__mulxf3(qnan80, 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80))); - try test__mulxf3(@as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80))); + try test_mul_f80(qnan80, 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80))); + try test_mul_f80(@as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80))); // any * NaN = NaN - try test__mulxf3(0x1.23456789abcdefp+5, qnan80, @as(u80, @bitCast(qnan80))); - try test__mulxf3(0x1.23456789abcdefp+5, @as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), @as(u80, @bitCast(qnan80))); + try test_mul_f80(0x1.23456789abcdefp+5, qnan80, @as(u80, @bitCast(qnan80))); + try test_mul_f80(0x1.23456789abcdefp+5, @as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), @as(u80, @bitCast(qnan80))); // NaN * inf = NaN - try test__mulxf3(qnan80, math.inf(f80), @as(u80, @bitCast(qnan80))); + try test_mul_f80(qnan80, math.inf(f80), @as(u80, @bitCast(qnan80))); // inf * NaN = NaN - try test__mulxf3(math.inf(f80), qnan80, @as(u80, @bitCast(qnan80))); + try test_mul_f80(math.inf(f80), qnan80, @as(u80, @bitCast(qnan80))); // inf * inf = inf - try test__mulxf3(math.inf(f80), math.inf(f80), @as(u80, @bitCast(math.inf(f80)))); + try test_mul_f80(math.inf(f80), math.inf(f80), @as(u80, @bitCast(math.inf(f80)))); // inf * -inf = -inf - try test__mulxf3(math.inf(f80), -math.inf(f80), @as(u80, @bitCast(-math.inf(f80)))); + try test_mul_f80(math.inf(f80), -math.inf(f80), @as(u80, @bitCast(-math.inf(f80)))); // -inf + inf = -inf - try test__mulxf3(-math.inf(f80), math.inf(f80), @as(u80, @bitCast(-math.inf(f80)))); + try test_mul_f80(-math.inf(f80), math.inf(f80), @as(u80, @bitCast(-math.inf(f80)))); // inf * any = inf - try test__mulxf3(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @as(u80, @bitCast(math.inf(f80)))); + try test_mul_f80(math.inf(f80), 0x1.2335653452436234723489432abcdefp+5, @as(u80, @bitCast(math.inf(f80)))); // any * inf = inf - try test__mulxf3(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @as(u80, @bitCast(math.inf(f80)))); + try test_mul_f80(0x1.2335653452436234723489432abcdefp+5, math.inf(f80), @as(u80, @bitCast(math.inf(f80)))); // any * any - try test__mulxf3(0x1.0p+0, 0x1.dcba987654321p+5, 0x4004_ee5d_4c3b_2a19_0800); - try test__mulxf3(0x1.0000_0000_0000_0004p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0003); // exact + try test_mul_f80(0x1.0p+0, 0x1.dcba987654321p+5, 0x4004_ee5d_4c3b_2a19_0800); + try test_mul_f80(0x1.0000_0000_0000_0004p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0003); // exact - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+5, 0x4004_8000_0000_0000_0001); // exact - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.7ffep+5, 0x4004_BFFF_0000_0000_0001); // round down - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0002); // round up to even - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.8002p+5, 0x4004_C001_0000_0000_0002); // round up - try test__mulxf3(0x1.0000_0000_0000_0002p+0, 0x1.0p+6, 0x4005_8000_0000_0000_0001); // exact + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.0p+5, 0x4004_8000_0000_0000_0001); // exact + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.7ffep+5, 0x4004_BFFF_0000_0000_0001); // round down + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.8p+5, 0x4004_C000_0000_0000_0002); // round up to even + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.8002p+5, 0x4004_C001_0000_0000_0002); // round up + try test_mul_f80(0x1.0000_0000_0000_0002p+0, 0x1.0p+6, 0x4005_8000_0000_0000_0001); // exact - try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001p+0, 0x3FFF_8000_0001_0000_0000); // round down to even - try test__mulxf3(0x1.0000_0001p+0, 0x1.0000_0001_0002p+0, 0x3FFF_8000_0001_0001_0001); // round up - try test__mulxf3(0x0.8000_0000_0000_0000p-16382, 2.0, 0x0001_8000_0000_0000_0000); // denormal -> normal - try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x2.0000_0000_0000_0008p0, 0x0001_8000_0000_0000_0000); // denormal -> normal - try test__mulxf3(0x0.7fff_ffff_ffff_fffep-16382, 0x1.0000_0000_0000_0000p0, 0x0000_3FFF_FFFF_FFFF_FFFF); // denormal -> denormal + try test_mul_f80(0x1.0000_0001p+0, 0x1.0000_0001p+0, 0x3FFF_8000_0001_0000_0000); // round down to even + try test_mul_f80(0x1.0000_0001p+0, 0x1.0000_0001_0002p+0, 0x3FFF_8000_0001_0001_0001); // round up + try test_mul_f80(0x0.8000_0000_0000_0000p-16382, 2.0, 0x0001_8000_0000_0000_0000); // denormal -> normal + try test_mul_f80(0x0.7fff_ffff_ffff_fffep-16382, 0x2.0000_0000_0000_0008p0, 0x0001_8000_0000_0000_0000); // denormal -> normal + try test_mul_f80(0x0.7fff_ffff_ffff_fffep-16382, 0x1.0000_0000_0000_0000p0, 0x0000_3FFF_FFFF_FFFF_FFFF); // denormal -> denormal } diff --git a/lib/compiler_rt/mulhc3.zig b/lib/compiler_rt/mulhc3.zig deleted file mode 100644 index 4e0d3f875389ddf2f02bb7ddb3f75106e6d48513..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulhc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulc3 = @import("./mulc3.zig"); - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__mulhc3, "__mulhc3"); - } -} - -pub fn __mulhc3(a: f16, b: f16, c: f16, d: f16) callconv(.c) mulc3.Complex(f16) { - return mulc3.mulc3(f16, a, b, c, d); -} diff --git a/lib/compiler_rt/mulhf3.zig b/lib/compiler_rt/mulhf3.zig deleted file mode 100644 index 46ce7a6b999005704db84280e3e83c7be05985b6..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulhf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - symbol(&__mulhf3, "__mulhf3"); -} - -pub fn __mulhf3(a: f16, b: f16) callconv(.c) f16 { - return mulf3(f16, a, b); -} diff --git a/lib/compiler_rt/mulsc3.zig b/lib/compiler_rt/mulsc3.zig deleted file mode 100644 index e735e65eade6a77f908abe8b4b25e8fc30af7f9f..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulsc3.zig +++ /dev/null @@ -1,12 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const mulc3 = @import("./mulc3.zig"); - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__mulsc3, "__mulsc3"); - } -} - -pub fn __mulsc3(a: f32, b: f32, c: f32, d: f32) callconv(.c) mulc3.Complex(f32) { - return mulc3.mulc3(f32, a, b, c, d); -} diff --git a/lib/compiler_rt/mulsf3.zig b/lib/compiler_rt/mulsf3.zig deleted file mode 100644 index 81f9eafae213d8cba10579b86f109bdfd361ba41..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulsf3.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fmul, "__aeabi_fmul"); - } else { - symbol(&__mulsf3, "__mulsf3"); - } -} - -pub fn __mulsf3(a: f32, b: f32) callconv(.c) f32 { - return mulf3(f32, a, b); -} - -fn __aeabi_fmul(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { - return mulf3(f32, a, b); -} diff --git a/lib/compiler_rt/multc3.zig b/lib/compiler_rt/multc3.zig deleted file mode 100644 index 4914735b10f63ec38d3487738e461769db6f8669..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/multc3.zig +++ /dev/null @@ -1,15 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const mulc3 = @import("./mulc3.zig"); - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - if (compiler_rt.want_ppc_abi) - symbol(&__multc3, "__mulkc3"); - symbol(&__multc3, "__multc3"); - } -} - -pub fn __multc3(a: f128, b: f128, c: f128, d: f128) callconv(.c) mulc3.Complex(f128) { - return mulc3.mulc3(f128, a, b, c, d); -} diff --git a/lib/compiler_rt/multf3.zig b/lib/compiler_rt/multf3.zig deleted file mode 100644 index 7d10c70777176e7a8580eb3b909546e42535785e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/multf3.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__multf3, "__mulkf3"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_mul, "_Qp_mul"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__multf3, "_Q_mul"); - } - symbol(&__multf3, "__multf3"); -} - -pub fn __multf3(a: f128, b: f128) callconv(.c) f128 { - return mulf3(f128, a, b); -} - -fn _Qp_mul(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { - c.* = mulf3(f128, a.*, b.*); -} diff --git a/lib/compiler_rt/mulvsi3.zig b/lib/compiler_rt/mulvsi3.zig index 0935ea497afa52a46f515c83c40c2d8cc5bc02db..f2456fa7cb825a36a359d667d26e5f06eb2c95e4 100644 --- a/lib/compiler_rt/mulvsi3.zig +++ b/lib/compiler_rt/mulvsi3.zig @@ -1,7 +1,8 @@ const testing = @import("std").testing; const mulv = @import("mulo.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__mulvsi3, "__mulvsi3"); @@ -10,7 +11,7 @@ comptime { pub fn __mulvsi3(a: i32, b: i32) callconv(.c) i32 { var overflow: c_int = 0; const sum = mulv.__mulosi4(a, b, &overflow); - if (overflow != 0) @panic("compiler-rt: integer overflow"); + if (overflow != 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/mulxc3.zig b/lib/compiler_rt/mulxc3.zig deleted file mode 100644 index ac0e189f63ba4d4ce2f0a753c4f7409e0b551d23..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulxc3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulc3 = @import("./mulc3.zig"); - -comptime { - if (@import("builtin").zig_backend != .stage2_c) { - symbol(&__mulxc3, "__mulxc3"); - } -} - -pub fn __mulxc3(a: f80, b: f80, c: f80, d: f80) callconv(.c) mulc3.Complex(f80) { - return mulc3.mulc3(f80, a, b, c, d); -} diff --git a/lib/compiler_rt/mulxf3.zig b/lib/compiler_rt/mulxf3.zig deleted file mode 100644 index dcf783a4a6bc434275416e9da0079f65b3354277..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/mulxf3.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const mulf3 = @import("./mulf3.zig").mulf3; - -comptime { - symbol(&__mulxf3, "__mulxf3"); -} - -pub fn __mulxf3(a: f80, b: f80) callconv(.c) f80 { - return mulf3(f80, a, b); -} diff --git a/lib/compiler_rt/negv.zig b/lib/compiler_rt/negv.zig index 7c67a51c34ab72f9c3f0038024e45ca79413d955..c6d61611f1b24d3697dcdc4201f5ff2d8c1cf40c 100644 --- a/lib/compiler_rt/negv.zig +++ b/lib/compiler_rt/negv.zig @@ -33,8 +33,7 @@ inline fn negvXi(comptime ST: type, a: ST) ST { }; const N: UT = @bitSizeOf(ST); const min: ST = @as(ST, @bitCast((@as(UT, 1) << (N - 1)))); - if (a == min) - @panic("compiler_rt negv: overflow"); + if (a == min) @panic("integer overflow"); return -a; } diff --git a/lib/compiler_rt/os_version_check.zig b/lib/compiler_rt/os_version_check.zig index e575fef9ce553fee90cc9f7cc900689c5804cb20..96724a14e8092aae7693e4ab869ab3282a9ea762 100644 --- a/lib/compiler_rt/os_version_check.zig +++ b/lib/compiler_rt/os_version_check.zig @@ -3,7 +3,6 @@ const testing = std.testing; const builtin = @import("builtin"); const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; -const panic = @import("../compiler_rt.zig").panic; const have_availability_version_check = builtin.os.tag.isDarwin() and builtin.os.version_range.semver.min.order(.{ .major = 10, .minor = 15, .patch = 0 }).compare(.gte); diff --git a/lib/compiler_rt/parity.zig b/lib/compiler_rt/parity.zig index e3881699042fafc3fc0da7415e6fb2bb6d1aedde..9540cf49f629556b73f77067ddcf90944afdf21b 100644 --- a/lib/compiler_rt/parity.zig +++ b/lib/compiler_rt/parity.zig @@ -1,6 +1,7 @@ //! parity - if number of bits set is even => 0, else => 1 //! - pariytXi2_generic for big and little endian -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__paritysi2, "__paritysi2"); diff --git a/lib/compiler_rt/popcount.zig b/lib/compiler_rt/popcount.zig index b1ef500ea117514d08b598e4209770bd4b879b1f..3b9d867548f62d9ab7da321786cb737effa2646d 100644 --- a/lib/compiler_rt/popcount.zig +++ b/lib/compiler_rt/popcount.zig @@ -6,7 +6,8 @@ //! TAOCP: Combinational Algorithms, Bitwise Tricks And Techniques, //! subsubsection "Working with the rightmost bits" and "Sideways addition". -const symbol = @import("../compiler_rt.zig").symbol; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__popcountsi2, "__popcountsi2"); diff --git a/lib/compiler_rt/powiXf2.zig b/lib/compiler_rt/powiXf2.zig index b2a1e3e6989ba85538243483d14fd92ad0e3158d..dd8b477f152144ce7206f4ce54caa77c1a4ead36 100644 --- a/lib/compiler_rt/powiXf2.zig +++ b/lib/compiler_rt/powiXf2.zig @@ -4,16 +4,18 @@ //! error propagation and this method is optimized for performance, not accuracy. const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { symbol(&__powihf2, "__powihf2"); symbol(&__powisf2, "__powisf2"); symbol(&__powidf2, "__powidf2"); - if (compiler_rt.want_ppc_abi) - symbol(&__powitf2, "__powikf2"); - symbol(&__powitf2, "__powitf2"); symbol(&__powixf2, "__powixf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__powitf2, "__powikf2"); + } else { + symbol(&__powitf2, "__powitf2"); + } } inline fn powiXf2(comptime FT: type, a: FT, b: i32) FT { @@ -32,26 +34,41 @@ inline fn powiXf2(comptime FT: type, a: FT, b: i32) FT { return if (is_recip) 1 / r else r; } -pub fn __powihf2(a: f16, b: i32) callconv(.c) f16 { +fn __powihf2(a: compiler_rt.f16.Abi, b: i32) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(powi_f16(compiler_rt.f16.fromAbi(a), b)); +} +pub fn powi_f16(a: f16, b: i32) f16 { return powiXf2(f16, a, b); } -pub fn __powisf2(a: f32, b: i32) callconv(.c) f32 { +fn __powisf2(a: compiler_rt.f32.Abi, b: i32) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(powi_f32(compiler_rt.f32.fromAbi(a), b)); +} +pub fn powi_f32(a: f32, b: i32) f32 { return powiXf2(f32, a, b); } -pub fn __powidf2(a: f64, b: i32) callconv(.c) f64 { +fn __powidf2(a: compiler_rt.f64.Abi, b: i32) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(powi_f64(compiler_rt.f64.fromAbi(a), b)); +} +pub fn powi_f64(a: f64, b: i32) f64 { return powiXf2(f64, a, b); } -pub fn __powitf2(a: f128, b: i32) callconv(.c) f128 { - return powiXf2(f128, a, b); +fn __powixf2(a: compiler_rt.f80.Abi, b: i32) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(powi_f80(compiler_rt.f80.fromAbi(a), b)); } - -pub fn __powixf2(a: f80, b: i32) callconv(.c) f80 { +pub fn powi_f80(a: f80, b: i32) f80 { return powiXf2(f80, a, b); } +fn __powitf2(a: compiler_rt.f128.Abi, b: i32) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(powi_f128(compiler_rt.f128.fromAbi(a), b)); +} +pub fn powi_f128(a: f128, b: i32) f128 { + return powiXf2(f128, a, b); +} + test { _ = @import("powiXf2_test.zig"); } diff --git a/lib/compiler_rt/powiXf2_test.zig b/lib/compiler_rt/powiXf2_test.zig index 7bd43c73c3d2d1a379a6ef66977c55dff1fc8a00..1388a4e7250e7b418fee08cde6d165d2bce80adf 100644 --- a/lib/compiler_rt/powiXf2_test.zig +++ b/lib/compiler_rt/powiXf2_test.zig @@ -2,562 +2,568 @@ // powisf2_test.c, powidf2_test.c, powitf2_test.c, powixf2_test.c // powihf2 adapted from powisf2 tests -const powiXf2 = @import("powiXf2.zig"); const std = @import("std"); -const builtin = @import("builtin"); const testing = std.testing; const math = std.math; -fn test__powihf2(a: f16, b: i32, expected: f16) !void { - const result = powiXf2.__powihf2(a, b); +const impl = @import("powiXf2.zig"); + +const powi_f16 = impl.powi_f16; +const powi_f32 = impl.powi_f32; +const powi_f64 = impl.powi_f64; +const powi_f80 = impl.powi_f80; +const powi_f128 = impl.powi_f128; + +fn test_powi_f16(a: f16, b: i32, expected: f16) !void { + const result = powi_f16(a, b); try testing.expectEqual(expected, result); } -fn test__powisf2(a: f32, b: i32, expected: f32) !void { - const result = powiXf2.__powisf2(a, b); +fn test_powi_f32(a: f32, b: i32, expected: f32) !void { + const result = powi_f32(a, b); try testing.expectEqual(expected, result); } -fn test__powidf2(a: f64, b: i32, expected: f64) !void { - const result = powiXf2.__powidf2(a, b); +fn test_powi_f64(a: f64, b: i32, expected: f64) !void { + const result = powi_f64(a, b); try testing.expectEqual(expected, result); } -fn test__powitf2(a: f128, b: i32, expected: f128) !void { - const result = powiXf2.__powitf2(a, b); +fn test_powi_f80(a: f80, b: i32, expected: f80) !void { + const result = powi_f80(a, b); try testing.expectEqual(expected, result); } -fn test__powixf2(a: f80, b: i32, expected: f80) !void { - const result = powiXf2.__powixf2(a, b); +fn test_powi_f128(a: f128, b: i32, expected: f128) !void { + const result = powi_f128(a, b); try testing.expectEqual(expected, result); } -test "powihf2" { +test powi_f16 { const inf_f16 = math.inf(f16); - try test__powisf2(0, 0, 1); - try test__powihf2(1, 0, 1); - try test__powihf2(1.5, 0, 1); - try test__powihf2(2, 0, 1); - try test__powihf2(inf_f16, 0, 1); + try test_powi_f16(0, 0, 1); + try test_powi_f16(1, 0, 1); + try test_powi_f16(1.5, 0, 1); + try test_powi_f16(2, 0, 1); + try test_powi_f16(inf_f16, 0, 1); - try test__powihf2(-0.0, 0, 1); - try test__powihf2(-1, 0, 1); - try test__powihf2(-1.5, 0, 1); - try test__powihf2(-2, 0, 1); - try test__powihf2(-inf_f16, 0, 1); + try test_powi_f16(-0.0, 0, 1); + try test_powi_f16(-1, 0, 1); + try test_powi_f16(-1.5, 0, 1); + try test_powi_f16(-2, 0, 1); + try test_powi_f16(-inf_f16, 0, 1); - try test__powihf2(0, 1, 0); - try test__powihf2(0, 2, 0); - try test__powihf2(0, 3, 0); - try test__powihf2(0, 4, 0); - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); + try test_powi_f16(0, 1, 0); + try test_powi_f16(0, 2, 0); + try test_powi_f16(0, 3, 0); + try test_powi_f16(0, 4, 0); + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); - try test__powihf2(-0.0, 1, -0.0); - try test__powihf2(-0.0, 2, 0); - try test__powihf2(-0.0, 3, -0.0); - try test__powihf2(-0.0, 4, 0); - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + try test_powi_f16(-0.0, 1, -0.0); + try test_powi_f16(-0.0, 2, 0); + try test_powi_f16(-0.0, 3, -0.0); + try test_powi_f16(-0.0, 4, 0); + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - try test__powihf2(1, 1, 1); - try test__powihf2(1, 2, 1); - try test__powihf2(1, 3, 1); - try test__powihf2(1, 4, 1); - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + try test_powi_f16(1, 1, 1); + try test_powi_f16(1, 2, 1); + try test_powi_f16(1, 3, 1); + try test_powi_f16(1, 4, 1); + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - try test__powihf2(inf_f16, 1, inf_f16); - try test__powihf2(inf_f16, 2, inf_f16); - try test__powihf2(inf_f16, 3, inf_f16); - try test__powihf2(inf_f16, 4, inf_f16); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f16); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f16); + try test_powi_f16(inf_f16, 1, inf_f16); + try test_powi_f16(inf_f16, 2, inf_f16); + try test_powi_f16(inf_f16, 3, inf_f16); + try test_powi_f16(inf_f16, 4, inf_f16); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f16); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f16); - try test__powihf2(-inf_f16, 1, -inf_f16); - try test__powihf2(-inf_f16, 2, inf_f16); - try test__powihf2(-inf_f16, 3, -inf_f16); - try test__powihf2(-inf_f16, 4, inf_f16); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f16); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f16); + try test_powi_f16(-inf_f16, 1, -inf_f16); + try test_powi_f16(-inf_f16, 2, inf_f16); + try test_powi_f16(-inf_f16, 3, -inf_f16); + try test_powi_f16(-inf_f16, 4, inf_f16); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f16); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f16); // - try test__powihf2(0, -1, inf_f16); - try test__powihf2(0, -2, inf_f16); - try test__powihf2(0, -3, inf_f16); - try test__powihf2(0, -4, inf_f16); - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f16); // 0 ^ anything = +inf - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f16); - try test__powihf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f16); + try test_powi_f16(0, -1, inf_f16); + try test_powi_f16(0, -2, inf_f16); + try test_powi_f16(0, -3, inf_f16); + try test_powi_f16(0, -4, inf_f16); + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f16); // 0 ^ anything = +inf + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f16); + try test_powi_f16(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f16); - try test__powihf2(-0.0, -1, -inf_f16); - try test__powihf2(-0.0, -2, inf_f16); - try test__powihf2(-0.0, -3, -inf_f16); - try test__powihf2(-0.0, -4, inf_f16); - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f16); // -0 ^ anything even = +inf - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f16); // -0 ^ anything odd = -inf - try test__powihf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f16); + try test_powi_f16(-0.0, -1, -inf_f16); + try test_powi_f16(-0.0, -2, inf_f16); + try test_powi_f16(-0.0, -3, -inf_f16); + try test_powi_f16(-0.0, -4, inf_f16); + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f16); // -0 ^ anything even = +inf + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f16); // -0 ^ anything odd = -inf + try test_powi_f16(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f16); - try test__powihf2(1, -1, 1); - try test__powihf2(1, -2, 1); - try test__powihf2(1, -3, 1); - try test__powihf2(1, -4, 1); - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); // 1.0 ^ anything = 1 - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powihf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + try test_powi_f16(1, -1, 1); + try test_powi_f16(1, -2, 1); + try test_powi_f16(1, -3, 1); + try test_powi_f16(1, -4, 1); + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); // 1.0 ^ anything = 1 + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f16(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - try test__powihf2(inf_f16, -1, 0); - try test__powihf2(inf_f16, -2, 0); - try test__powihf2(inf_f16, -3, 0); - try test__powihf2(inf_f16, -4, 0); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powihf2(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + try test_powi_f16(inf_f16, -1, 0); + try test_powi_f16(inf_f16, -2, 0); + try test_powi_f16(inf_f16, -3, 0); + try test_powi_f16(inf_f16, -4, 0); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f16(inf_f16, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); // - try test__powihf2(-inf_f16, -1, -0.0); - try test__powihf2(-inf_f16, -2, 0); - try test__powihf2(-inf_f16, -3, -0.0); - try test__powihf2(-inf_f16, -4, 0); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powihf2(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + try test_powi_f16(-inf_f16, -1, -0.0); + try test_powi_f16(-inf_f16, -2, 0); + try test_powi_f16(-inf_f16, -3, -0.0); + try test_powi_f16(-inf_f16, -4, 0); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f16(-inf_f16, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - try test__powihf2(2, 10, 1024.0); - try test__powihf2(-2, 10, 1024.0); - try test__powihf2(2, -10, 1.0 / 1024.0); - try test__powihf2(-2, -10, 1.0 / 1024.0); + try test_powi_f16(2, 10, 1024.0); + try test_powi_f16(-2, 10, 1024.0); + try test_powi_f16(2, -10, 1.0 / 1024.0); + try test_powi_f16(-2, -10, 1.0 / 1024.0); - try test__powihf2(2, 14, 16384.0); - try test__powihf2(-2, 14, 16384.0); - try test__powihf2(2, 15, 32768.0); - try test__powihf2(-2, 15, -32768.0); - try test__powihf2(2, 16, inf_f16); - try test__powihf2(-2, 16, inf_f16); + try test_powi_f16(2, 14, 16384.0); + try test_powi_f16(-2, 14, 16384.0); + try test_powi_f16(2, 15, 32768.0); + try test_powi_f16(-2, 15, -32768.0); + try test_powi_f16(2, 16, inf_f16); + try test_powi_f16(-2, 16, inf_f16); - try test__powihf2(2, -13, 1.0 / 8192.0); - try test__powihf2(-2, -13, -1.0 / 8192.0); - try test__powihf2(2, -15, 1.0 / 32768.0); - try test__powihf2(-2, -15, -1.0 / 32768.0); - try test__powihf2(2, -16, 0.0); // expected = 0.0 = 1/(-2**16) - try test__powihf2(-2, -16, 0.0); // expected = 0.0 = 1/(2**16) + try test_powi_f16(2, -13, 1.0 / 8192.0); + try test_powi_f16(-2, -13, -1.0 / 8192.0); + try test_powi_f16(2, -15, 1.0 / 32768.0); + try test_powi_f16(-2, -15, -1.0 / 32768.0); + try test_powi_f16(2, -16, 0.0); // expected = 0.0 = 1/(-2**16) + try test_powi_f16(-2, -16, 0.0); // expected = 0.0 = 1/(2**16) } -test "powisf2" { +test powi_f32 { const inf_f32 = math.inf(f32); - try test__powisf2(0, 0, 1); - try test__powisf2(1, 0, 1); - try test__powisf2(1.5, 0, 1); - try test__powisf2(2, 0, 1); - try test__powisf2(inf_f32, 0, 1); + try test_powi_f32(0, 0, 1); + try test_powi_f32(1, 0, 1); + try test_powi_f32(1.5, 0, 1); + try test_powi_f32(2, 0, 1); + try test_powi_f32(inf_f32, 0, 1); - try test__powisf2(-0.0, 0, 1); - try test__powisf2(-1, 0, 1); - try test__powisf2(-1.5, 0, 1); - try test__powisf2(-2, 0, 1); - try test__powisf2(-inf_f32, 0, 1); + try test_powi_f32(-0.0, 0, 1); + try test_powi_f32(-1, 0, 1); + try test_powi_f32(-1.5, 0, 1); + try test_powi_f32(-2, 0, 1); + try test_powi_f32(-inf_f32, 0, 1); - try test__powisf2(0, 1, 0); - try test__powisf2(0, 2, 0); - try test__powisf2(0, 3, 0); - try test__powisf2(0, 4, 0); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); + try test_powi_f32(0, 1, 0); + try test_powi_f32(0, 2, 0); + try test_powi_f32(0, 3, 0); + try test_powi_f32(0, 4, 0); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); - try test__powisf2(-0.0, 1, -0.0); - try test__powisf2(-0.0, 2, 0); - try test__powisf2(-0.0, 3, -0.0); - try test__powisf2(-0.0, 4, 0); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + try test_powi_f32(-0.0, 1, -0.0); + try test_powi_f32(-0.0, 2, 0); + try test_powi_f32(-0.0, 3, -0.0); + try test_powi_f32(-0.0, 4, 0); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - try test__powisf2(1, 1, 1); - try test__powisf2(1, 2, 1); - try test__powisf2(1, 3, 1); - try test__powisf2(1, 4, 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + try test_powi_f32(1, 1, 1); + try test_powi_f32(1, 2, 1); + try test_powi_f32(1, 3, 1); + try test_powi_f32(1, 4, 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - try test__powisf2(inf_f32, 1, inf_f32); - try test__powisf2(inf_f32, 2, inf_f32); - try test__powisf2(inf_f32, 3, inf_f32); - try test__powisf2(inf_f32, 4, inf_f32); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f32); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f32); + try test_powi_f32(inf_f32, 1, inf_f32); + try test_powi_f32(inf_f32, 2, inf_f32); + try test_powi_f32(inf_f32, 3, inf_f32); + try test_powi_f32(inf_f32, 4, inf_f32); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f32); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f32); - try test__powisf2(-inf_f32, 1, -inf_f32); - try test__powisf2(-inf_f32, 2, inf_f32); - try test__powisf2(-inf_f32, 3, -inf_f32); - try test__powisf2(-inf_f32, 4, inf_f32); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f32); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f32); + try test_powi_f32(-inf_f32, 1, -inf_f32); + try test_powi_f32(-inf_f32, 2, inf_f32); + try test_powi_f32(-inf_f32, 3, -inf_f32); + try test_powi_f32(-inf_f32, 4, inf_f32); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f32); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f32); - try test__powisf2(0, -1, inf_f32); - try test__powisf2(0, -2, inf_f32); - try test__powisf2(0, -3, inf_f32); - try test__powisf2(0, -4, inf_f32); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f32); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f32); - try test__powisf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f32); + try test_powi_f32(0, -1, inf_f32); + try test_powi_f32(0, -2, inf_f32); + try test_powi_f32(0, -3, inf_f32); + try test_powi_f32(0, -4, inf_f32); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f32); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f32); + try test_powi_f32(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f32); - try test__powisf2(-0.0, -1, -inf_f32); - try test__powisf2(-0.0, -2, inf_f32); - try test__powisf2(-0.0, -3, -inf_f32); - try test__powisf2(-0.0, -4, inf_f32); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f32); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f32); - try test__powisf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f32); + try test_powi_f32(-0.0, -1, -inf_f32); + try test_powi_f32(-0.0, -2, inf_f32); + try test_powi_f32(-0.0, -3, -inf_f32); + try test_powi_f32(-0.0, -4, inf_f32); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f32); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f32); + try test_powi_f32(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f32); - try test__powisf2(1, -1, 1); - try test__powisf2(1, -2, 1); - try test__powisf2(1, -3, 1); - try test__powisf2(1, -4, 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powisf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + try test_powi_f32(1, -1, 1); + try test_powi_f32(1, -2, 1); + try test_powi_f32(1, -3, 1); + try test_powi_f32(1, -4, 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f32(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - try test__powisf2(inf_f32, -1, 0); - try test__powisf2(inf_f32, -2, 0); - try test__powisf2(inf_f32, -3, 0); - try test__powisf2(inf_f32, -4, 0); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powisf2(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + try test_powi_f32(inf_f32, -1, 0); + try test_powi_f32(inf_f32, -2, 0); + try test_powi_f32(inf_f32, -3, 0); + try test_powi_f32(inf_f32, -4, 0); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f32(inf_f32, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - try test__powisf2(-inf_f32, -1, -0.0); - try test__powisf2(-inf_f32, -2, 0); - try test__powisf2(-inf_f32, -3, -0.0); - try test__powisf2(-inf_f32, -4, 0); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powisf2(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + try test_powi_f32(-inf_f32, -1, -0.0); + try test_powi_f32(-inf_f32, -2, 0); + try test_powi_f32(-inf_f32, -3, -0.0); + try test_powi_f32(-inf_f32, -4, 0); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f32(-inf_f32, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - try test__powisf2(2.0, 10, 1024.0); - try test__powisf2(-2, 10, 1024.0); - try test__powisf2(2, -10, 1.0 / 1024.0); - try test__powisf2(-2, -10, 1.0 / 1024.0); + try test_powi_f32(2.0, 10, 1024.0); + try test_powi_f32(-2, 10, 1024.0); + try test_powi_f32(2, -10, 1.0 / 1024.0); + try test_powi_f32(-2, -10, 1.0 / 1024.0); // - try test__powisf2(2, 19, 524288.0); - try test__powisf2(-2, 19, -524288.0); - try test__powisf2(2, -19, 1.0 / 524288.0); - try test__powisf2(-2, -19, -1.0 / 524288.0); + try test_powi_f32(2, 19, 524288.0); + try test_powi_f32(-2, 19, -524288.0); + try test_powi_f32(2, -19, 1.0 / 524288.0); + try test_powi_f32(-2, -19, -1.0 / 524288.0); - try test__powisf2(2, 31, 2147483648.0); - try test__powisf2(-2, 31, -2147483648.0); - try test__powisf2(2, -31, 1.0 / 2147483648.0); - try test__powisf2(-2, -31, -1.0 / 2147483648.0); + try test_powi_f32(2, 31, 2147483648.0); + try test_powi_f32(-2, 31, -2147483648.0); + try test_powi_f32(2, -31, 1.0 / 2147483648.0); + try test_powi_f32(-2, -31, -1.0 / 2147483648.0); } -test "powidf2" { +test powi_f64 { const inf_f64 = math.inf(f64); - try test__powidf2(0, 0, 1); - try test__powidf2(1, 0, 1); - try test__powidf2(1.5, 0, 1); - try test__powidf2(2, 0, 1); - try test__powidf2(inf_f64, 0, 1); - - try test__powidf2(-0.0, 0, 1); - try test__powidf2(-1, 0, 1); - try test__powidf2(-1.5, 0, 1); - try test__powidf2(-2, 0, 1); - try test__powidf2(-inf_f64, 0, 1); - - try test__powidf2(0, 1, 0); - try test__powidf2(0, 2, 0); - try test__powidf2(0, 3, 0); - try test__powidf2(0, 4, 0); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); - - try test__powidf2(-0.0, 1, -0.0); - try test__powidf2(-0.0, 2, 0); - try test__powidf2(-0.0, 3, -0.0); - try test__powidf2(-0.0, 4, 0); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - - try test__powidf2(1, 1, 1); - try test__powidf2(1, 2, 1); - try test__powidf2(1, 3, 1); - try test__powidf2(1, 4, 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - - try test__powidf2(inf_f64, 1, inf_f64); - try test__powidf2(inf_f64, 2, inf_f64); - try test__powidf2(inf_f64, 3, inf_f64); - try test__powidf2(inf_f64, 4, inf_f64); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f64); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f64); - - try test__powidf2(-inf_f64, 1, -inf_f64); - try test__powidf2(-inf_f64, 2, inf_f64); - try test__powidf2(-inf_f64, 3, -inf_f64); - try test__powidf2(-inf_f64, 4, inf_f64); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f64); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f64); - - try test__powidf2(0, -1, inf_f64); - try test__powidf2(0, -2, inf_f64); - try test__powidf2(0, -3, inf_f64); - try test__powidf2(0, -4, inf_f64); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f64); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f64); - try test__powidf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f64); - - try test__powidf2(-0.0, -1, -inf_f64); - try test__powidf2(-0.0, -2, inf_f64); - try test__powidf2(-0.0, -3, -inf_f64); - try test__powidf2(-0.0, -4, inf_f64); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f64); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f64); - try test__powidf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f64); - - try test__powidf2(1, -1, 1); - try test__powidf2(1, -2, 1); - try test__powidf2(1, -3, 1); - try test__powidf2(1, -4, 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powidf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - - try test__powidf2(inf_f64, -1, 0); - try test__powidf2(inf_f64, -2, 0); - try test__powidf2(inf_f64, -3, 0); - try test__powidf2(inf_f64, -4, 0); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powidf2(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powidf2(-inf_f64, -1, -0.0); - try test__powidf2(-inf_f64, -2, 0); - try test__powidf2(-inf_f64, -3, -0.0); - try test__powidf2(-inf_f64, -4, 0); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powidf2(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powidf2(2, 10, 1024.0); - try test__powidf2(-2, 10, 1024.0); - try test__powidf2(2, -10, 1.0 / 1024.0); - try test__powidf2(-2, -10, 1.0 / 1024.0); - - try test__powidf2(2, 19, 524288.0); - try test__powidf2(-2, 19, -524288.0); - try test__powidf2(2, -19, 1.0 / 524288.0); - try test__powidf2(-2, -19, -1.0 / 524288.0); - - try test__powidf2(2, 31, 2147483648.0); - try test__powidf2(-2, 31, -2147483648.0); - try test__powidf2(2, -31, 1.0 / 2147483648.0); - try test__powidf2(-2, -31, -1.0 / 2147483648.0); -} - -test "powitf2" { - const inf_f128 = math.inf(f128); - try test__powitf2(0, 0, 1); - try test__powitf2(1, 0, 1); - try test__powitf2(1.5, 0, 1); - try test__powitf2(2, 0, 1); - try test__powitf2(inf_f128, 0, 1); - - try test__powitf2(-0.0, 0, 1); - try test__powitf2(-1, 0, 1); - try test__powitf2(-1.5, 0, 1); - try test__powitf2(-2, 0, 1); - try test__powitf2(-inf_f128, 0, 1); - - try test__powitf2(0, 1, 0); - try test__powitf2(0, 2, 0); - try test__powitf2(0, 3, 0); - try test__powitf2(0, 4, 0); - try test__powitf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powitf2(0, 0x7FFFFFFF, 0); - - try test__powitf2(-0.0, 1, -0.0); - try test__powitf2(-0.0, 2, 0); - try test__powitf2(-0.0, 3, -0.0); - try test__powitf2(-0.0, 4, 0); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - - try test__powitf2(1, 1, 1); - try test__powitf2(1, 2, 1); - try test__powitf2(1, 3, 1); - try test__powitf2(1, 4, 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - - try test__powitf2(inf_f128, 1, inf_f128); - try test__powitf2(inf_f128, 2, inf_f128); - try test__powitf2(inf_f128, 3, inf_f128); - try test__powitf2(inf_f128, 4, inf_f128); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f128); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f128); - - try test__powitf2(-inf_f128, 1, -inf_f128); - try test__powitf2(-inf_f128, 2, inf_f128); - try test__powitf2(-inf_f128, 3, -inf_f128); - try test__powitf2(-inf_f128, 4, inf_f128); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f128); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f128); - - try test__powitf2(0, -1, inf_f128); - try test__powitf2(0, -2, inf_f128); - try test__powitf2(0, -3, inf_f128); - try test__powitf2(0, -4, inf_f128); - try test__powitf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f128); - try test__powitf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f128); - try test__powitf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f128); - - try test__powitf2(-0.0, -1, -inf_f128); - try test__powitf2(-0.0, -2, inf_f128); - try test__powitf2(-0.0, -3, -inf_f128); - try test__powitf2(-0.0, -4, inf_f128); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f128); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f128); - try test__powitf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f128); - - try test__powitf2(1, -1, 1); - try test__powitf2(1, -2, 1); - try test__powitf2(1, -3, 1); - try test__powitf2(1, -4, 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powitf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - - try test__powitf2(inf_f128, -1, 0); - try test__powitf2(inf_f128, -2, 0); - try test__powitf2(inf_f128, -3, 0); - try test__powitf2(inf_f128, -4, 0); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powitf2(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powitf2(-inf_f128, -1, -0.0); - try test__powitf2(-inf_f128, -2, 0); - try test__powitf2(-inf_f128, -3, -0.0); - try test__powitf2(-inf_f128, -4, 0); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powitf2(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powitf2(2, 10, 1024.0); - try test__powitf2(-2, 10, 1024.0); - try test__powitf2(2, -10, 1.0 / 1024.0); - try test__powitf2(-2, -10, 1.0 / 1024.0); - - try test__powitf2(2, 19, 524288.0); - try test__powitf2(-2, 19, -524288.0); - try test__powitf2(2, -19, 1.0 / 524288.0); - try test__powitf2(-2, -19, -1.0 / 524288.0); - - try test__powitf2(2, 31, 2147483648.0); - try test__powitf2(-2, 31, -2147483648.0); - try test__powitf2(2, -31, 1.0 / 2147483648.0); - try test__powitf2(-2, -31, -1.0 / 2147483648.0); + try test_powi_f64(0, 0, 1); + try test_powi_f64(1, 0, 1); + try test_powi_f64(1.5, 0, 1); + try test_powi_f64(2, 0, 1); + try test_powi_f64(inf_f64, 0, 1); + + try test_powi_f64(-0.0, 0, 1); + try test_powi_f64(-1, 0, 1); + try test_powi_f64(-1.5, 0, 1); + try test_powi_f64(-2, 0, 1); + try test_powi_f64(-inf_f64, 0, 1); + + try test_powi_f64(0, 1, 0); + try test_powi_f64(0, 2, 0); + try test_powi_f64(0, 3, 0); + try test_powi_f64(0, 4, 0); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); + + try test_powi_f64(-0.0, 1, -0.0); + try test_powi_f64(-0.0, 2, 0); + try test_powi_f64(-0.0, 3, -0.0); + try test_powi_f64(-0.0, 4, 0); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + + try test_powi_f64(1, 1, 1); + try test_powi_f64(1, 2, 1); + try test_powi_f64(1, 3, 1); + try test_powi_f64(1, 4, 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + + try test_powi_f64(inf_f64, 1, inf_f64); + try test_powi_f64(inf_f64, 2, inf_f64); + try test_powi_f64(inf_f64, 3, inf_f64); + try test_powi_f64(inf_f64, 4, inf_f64); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f64); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f64); + + try test_powi_f64(-inf_f64, 1, -inf_f64); + try test_powi_f64(-inf_f64, 2, inf_f64); + try test_powi_f64(-inf_f64, 3, -inf_f64); + try test_powi_f64(-inf_f64, 4, inf_f64); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f64); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f64); + + try test_powi_f64(0, -1, inf_f64); + try test_powi_f64(0, -2, inf_f64); + try test_powi_f64(0, -3, inf_f64); + try test_powi_f64(0, -4, inf_f64); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f64); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f64); + try test_powi_f64(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f64); + + try test_powi_f64(-0.0, -1, -inf_f64); + try test_powi_f64(-0.0, -2, inf_f64); + try test_powi_f64(-0.0, -3, -inf_f64); + try test_powi_f64(-0.0, -4, inf_f64); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f64); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f64); + try test_powi_f64(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f64); + + try test_powi_f64(1, -1, 1); + try test_powi_f64(1, -2, 1); + try test_powi_f64(1, -3, 1); + try test_powi_f64(1, -4, 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f64(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + + try test_powi_f64(inf_f64, -1, 0); + try test_powi_f64(inf_f64, -2, 0); + try test_powi_f64(inf_f64, -3, 0); + try test_powi_f64(inf_f64, -4, 0); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f64(inf_f64, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f64(-inf_f64, -1, -0.0); + try test_powi_f64(-inf_f64, -2, 0); + try test_powi_f64(-inf_f64, -3, -0.0); + try test_powi_f64(-inf_f64, -4, 0); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f64(-inf_f64, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f64(2, 10, 1024.0); + try test_powi_f64(-2, 10, 1024.0); + try test_powi_f64(2, -10, 1.0 / 1024.0); + try test_powi_f64(-2, -10, 1.0 / 1024.0); + + try test_powi_f64(2, 19, 524288.0); + try test_powi_f64(-2, 19, -524288.0); + try test_powi_f64(2, -19, 1.0 / 524288.0); + try test_powi_f64(-2, -19, -1.0 / 524288.0); + + try test_powi_f64(2, 31, 2147483648.0); + try test_powi_f64(-2, 31, -2147483648.0); + try test_powi_f64(2, -31, 1.0 / 2147483648.0); + try test_powi_f64(-2, -31, -1.0 / 2147483648.0); } -test "powixf2" { +test powi_f80 { const inf_f80 = math.inf(f80); - try test__powixf2(0, 0, 1); - try test__powixf2(1, 0, 1); - try test__powixf2(1.5, 0, 1); - try test__powixf2(2, 0, 1); - try test__powixf2(inf_f80, 0, 1); - - try test__powixf2(-0.0, 0, 1); - try test__powixf2(-1, 0, 1); - try test__powixf2(-1.5, 0, 1); - try test__powixf2(-2, 0, 1); - try test__powixf2(-inf_f80, 0, 1); - - try test__powixf2(0, 1, 0); - try test__powixf2(0, 2, 0); - try test__powixf2(0, 3, 0); - try test__powixf2(0, 4, 0); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); - - try test__powixf2(-0.0, 1, -0.0); - try test__powixf2(-0.0, 2, 0); - try test__powixf2(-0.0, 3, -0.0); - try test__powixf2(-0.0, 4, 0); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); - - try test__powixf2(1, 1, 1); - try test__powixf2(1, 2, 1); - try test__powixf2(1, 3, 1); - try test__powixf2(1, 4, 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); - - try test__powixf2(inf_f80, 1, inf_f80); - try test__powixf2(inf_f80, 2, inf_f80); - try test__powixf2(inf_f80, 3, inf_f80); - try test__powixf2(inf_f80, 4, inf_f80); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f80); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f80); - - try test__powixf2(-inf_f80, 1, -inf_f80); - try test__powixf2(-inf_f80, 2, inf_f80); - try test__powixf2(-inf_f80, 3, -inf_f80); - try test__powixf2(-inf_f80, 4, inf_f80); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f80); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f80); - - try test__powixf2(0, -1, inf_f80); - try test__powixf2(0, -2, inf_f80); - try test__powixf2(0, -3, inf_f80); - try test__powixf2(0, -4, inf_f80); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f80); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f80); - try test__powixf2(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f80); - - try test__powixf2(-0.0, -1, -inf_f80); - try test__powixf2(-0.0, -2, inf_f80); - try test__powixf2(-0.0, -3, -inf_f80); - try test__powixf2(-0.0, -4, inf_f80); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f80); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f80); - try test__powixf2(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f80); - - try test__powixf2(1, -1, 1); - try test__powixf2(1, -2, 1); - try test__powixf2(1, -3, 1); - try test__powixf2(1, -4, 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); - try test__powixf2(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); - - try test__powixf2(inf_f80, -1, 0); - try test__powixf2(inf_f80, -2, 0); - try test__powixf2(inf_f80, -3, 0); - try test__powixf2(inf_f80, -4, 0); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); - try test__powixf2(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powixf2(-inf_f80, -1, -0.0); - try test__powixf2(-inf_f80, -2, 0); - try test__powixf2(-inf_f80, -3, -0.0); - try test__powixf2(-inf_f80, -4, 0); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); - try test__powixf2(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); - - try test__powixf2(2, 10, 1024.0); - try test__powixf2(-2, 10, 1024.0); - try test__powixf2(2, -10, 1.0 / 1024.0); - try test__powixf2(-2, -10, 1.0 / 1024.0); - - try test__powixf2(2, 19, 524288.0); - try test__powixf2(-2, 19, -524288.0); - try test__powixf2(2, -19, 1.0 / 524288.0); - try test__powixf2(-2, -19, -1.0 / 524288.0); - - try test__powixf2(2, 31, 2147483648.0); - try test__powixf2(-2, 31, -2147483648.0); - try test__powixf2(2, -31, 1.0 / 2147483648.0); - try test__powixf2(-2, -31, -1.0 / 2147483648.0); + try test_powi_f80(0, 0, 1); + try test_powi_f80(1, 0, 1); + try test_powi_f80(1.5, 0, 1); + try test_powi_f80(2, 0, 1); + try test_powi_f80(inf_f80, 0, 1); + + try test_powi_f80(-0.0, 0, 1); + try test_powi_f80(-1, 0, 1); + try test_powi_f80(-1.5, 0, 1); + try test_powi_f80(-2, 0, 1); + try test_powi_f80(-inf_f80, 0, 1); + + try test_powi_f80(0, 1, 0); + try test_powi_f80(0, 2, 0); + try test_powi_f80(0, 3, 0); + try test_powi_f80(0, 4, 0); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 0); + + try test_powi_f80(-0.0, 1, -0.0); + try test_powi_f80(-0.0, 2, 0); + try test_powi_f80(-0.0, 3, -0.0); + try test_powi_f80(-0.0, 4, 0); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + + try test_powi_f80(1, 1, 1); + try test_powi_f80(1, 2, 1); + try test_powi_f80(1, 3, 1); + try test_powi_f80(1, 4, 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + + try test_powi_f80(inf_f80, 1, inf_f80); + try test_powi_f80(inf_f80, 2, inf_f80); + try test_powi_f80(inf_f80, 3, inf_f80); + try test_powi_f80(inf_f80, 4, inf_f80); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f80); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f80); + + try test_powi_f80(-inf_f80, 1, -inf_f80); + try test_powi_f80(-inf_f80, 2, inf_f80); + try test_powi_f80(-inf_f80, 3, -inf_f80); + try test_powi_f80(-inf_f80, 4, inf_f80); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f80); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f80); + + try test_powi_f80(0, -1, inf_f80); + try test_powi_f80(0, -2, inf_f80); + try test_powi_f80(0, -3, inf_f80); + try test_powi_f80(0, -4, inf_f80); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f80); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f80); + try test_powi_f80(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f80); + + try test_powi_f80(-0.0, -1, -inf_f80); + try test_powi_f80(-0.0, -2, inf_f80); + try test_powi_f80(-0.0, -3, -inf_f80); + try test_powi_f80(-0.0, -4, inf_f80); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f80); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f80); + try test_powi_f80(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f80); + + try test_powi_f80(1, -1, 1); + try test_powi_f80(1, -2, 1); + try test_powi_f80(1, -3, 1); + try test_powi_f80(1, -4, 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f80(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + + try test_powi_f80(inf_f80, -1, 0); + try test_powi_f80(inf_f80, -2, 0); + try test_powi_f80(inf_f80, -3, 0); + try test_powi_f80(inf_f80, -4, 0); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f80(inf_f80, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f80(-inf_f80, -1, -0.0); + try test_powi_f80(-inf_f80, -2, 0); + try test_powi_f80(-inf_f80, -3, -0.0); + try test_powi_f80(-inf_f80, -4, 0); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f80(-inf_f80, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f80(2, 10, 1024.0); + try test_powi_f80(-2, 10, 1024.0); + try test_powi_f80(2, -10, 1.0 / 1024.0); + try test_powi_f80(-2, -10, 1.0 / 1024.0); + + try test_powi_f80(2, 19, 524288.0); + try test_powi_f80(-2, 19, -524288.0); + try test_powi_f80(2, -19, 1.0 / 524288.0); + try test_powi_f80(-2, -19, -1.0 / 524288.0); + + try test_powi_f80(2, 31, 2147483648.0); + try test_powi_f80(-2, 31, -2147483648.0); + try test_powi_f80(2, -31, 1.0 / 2147483648.0); + try test_powi_f80(-2, -31, -1.0 / 2147483648.0); +} + +test powi_f128 { + const inf_f128 = math.inf(f128); + try test_powi_f128(0, 0, 1); + try test_powi_f128(1, 0, 1); + try test_powi_f128(1.5, 0, 1); + try test_powi_f128(2, 0, 1); + try test_powi_f128(inf_f128, 0, 1); + + try test_powi_f128(-0.0, 0, 1); + try test_powi_f128(-1, 0, 1); + try test_powi_f128(-1.5, 0, 1); + try test_powi_f128(-2, 0, 1); + try test_powi_f128(-inf_f128, 0, 1); + + try test_powi_f128(0, 1, 0); + try test_powi_f128(0, 2, 0); + try test_powi_f128(0, 3, 0); + try test_powi_f128(0, 4, 0); + try test_powi_f128(0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f128(0, 0x7FFFFFFF, 0); + + try test_powi_f128(-0.0, 1, -0.0); + try test_powi_f128(-0.0, 2, 0); + try test_powi_f128(-0.0, 3, -0.0); + try test_powi_f128(-0.0, 4, 0); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 0); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -0.0); + + try test_powi_f128(1, 1, 1); + try test_powi_f128(1, 2, 1); + try test_powi_f128(1, 3, 1); + try test_powi_f128(1, 4, 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), 1); + + try test_powi_f128(inf_f128, 1, inf_f128); + try test_powi_f128(inf_f128, 2, inf_f128); + try test_powi_f128(inf_f128, 3, inf_f128); + try test_powi_f128(inf_f128, 4, inf_f128); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f128); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), inf_f128); + + try test_powi_f128(-inf_f128, 1, -inf_f128); + try test_powi_f128(-inf_f128, 2, inf_f128); + try test_powi_f128(-inf_f128, 3, -inf_f128); + try test_powi_f128(-inf_f128, 4, inf_f128); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFE))), inf_f128); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x7FFFFFFF))), -inf_f128); + + try test_powi_f128(0, -1, inf_f128); + try test_powi_f128(0, -2, inf_f128); + try test_powi_f128(0, -3, inf_f128); + try test_powi_f128(0, -4, inf_f128); + try test_powi_f128(0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f128); + try test_powi_f128(0, @as(i32, @bitCast(@as(u32, 0x80000001))), inf_f128); + try test_powi_f128(0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f128); + + try test_powi_f128(-0.0, -1, -inf_f128); + try test_powi_f128(-0.0, -2, inf_f128); + try test_powi_f128(-0.0, -3, -inf_f128); + try test_powi_f128(-0.0, -4, inf_f128); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x80000002))), inf_f128); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x80000001))), -inf_f128); + try test_powi_f128(-0.0, @as(i32, @bitCast(@as(u32, 0x80000000))), inf_f128); + + try test_powi_f128(1, -1, 1); + try test_powi_f128(1, -2, 1); + try test_powi_f128(1, -3, 1); + try test_powi_f128(1, -4, 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x80000002))), 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x80000001))), 1); + try test_powi_f128(1, @as(i32, @bitCast(@as(u32, 0x80000000))), 1); + + try test_powi_f128(inf_f128, -1, 0); + try test_powi_f128(inf_f128, -2, 0); + try test_powi_f128(inf_f128, -3, 0); + try test_powi_f128(inf_f128, -4, 0); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000001))), 0); + try test_powi_f128(inf_f128, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f128(-inf_f128, -1, -0.0); + try test_powi_f128(-inf_f128, -2, 0); + try test_powi_f128(-inf_f128, -3, -0.0); + try test_powi_f128(-inf_f128, -4, 0); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000002))), 0); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000001))), -0.0); + try test_powi_f128(-inf_f128, @as(i32, @bitCast(@as(u32, 0x80000000))), 0); + + try test_powi_f128(2, 10, 1024.0); + try test_powi_f128(-2, 10, 1024.0); + try test_powi_f128(2, -10, 1.0 / 1024.0); + try test_powi_f128(-2, -10, 1.0 / 1024.0); + + try test_powi_f128(2, 19, 524288.0); + try test_powi_f128(-2, 19, -524288.0); + try test_powi_f128(2, -19, 1.0 / 524288.0); + try test_powi_f128(-2, -19, -1.0 / 524288.0); + + try test_powi_f128(2, 31, 2147483648.0); + try test_powi_f128(-2, 31, -2147483648.0); + try test_powi_f128(2, -31, 1.0 / 2147483648.0); + try test_powi_f128(-2, -31, -1.0 / 2147483648.0); } diff --git a/lib/compiler_rt/round.zig b/lib/compiler_rt/round.zig index 590b957922efdbf33ac4fea2728390daad82ee38..ffcaed60774e70e5067ff107380a8af5a057d718 100644 --- a/lib/compiler_rt/round.zig +++ b/lib/compiler_rt/round.zig @@ -18,19 +18,22 @@ comptime { symbol(&roundf, "roundf"); symbol(&round, "round"); symbol(&__roundx, "__roundx"); - if (compiler_rt.want_ppc_abi) { - symbol(&roundq, "roundf128"); - } - symbol(&roundq, "roundq"); + symbol(&roundq, "roundf128"); symbol(&roundl, "roundl"); } -pub fn __roundh(x: f16) callconv(.c) f16 { +fn __roundh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(round_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn round_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(roundf(x)); + return @floatCast(round_f32(x)); } -pub fn roundf(x_: f32) callconv(.c) f32 { +fn roundf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(round_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn round_f32(x_: f32) f32 { const f32_toint = 1.0 / math.floatEps(f32); var x = x_; @@ -65,7 +68,10 @@ pub fn roundf(x_: f32) callconv(.c) f32 { } } -pub fn round(x_: f64) callconv(.c) f64 { +fn round(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(round_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn round_f64(x_: f64) f64 { const f64_toint = 1.0 / math.floatEps(f64); var x = x_; @@ -100,12 +106,18 @@ pub fn round(x_: f64) callconv(.c) f64 { } } -pub fn __roundx(x: f80) callconv(.c) f80 { +fn __roundx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(round_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn round_f80(x: f80) f80 { // TODO: more efficient implementation - return @floatCast(roundq(x)); + return @floatCast(round_f128(x)); } -pub fn roundq(x_: f128) callconv(.c) f128 { +fn roundq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(round_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn round_f128(x_: f128) f128 { const f128_toint = 1.0 / math.floatEps(f128); var x = x_; @@ -142,54 +154,79 @@ pub fn roundq(x_: f128) callconv(.c) f128 { pub fn roundl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return round(x), - 80 => return __roundx(x), - 128 => return roundq(x), - else => @compileError("unreachable"), + 64 => return round_f64(x), + 80 => return round_f80(x), + 128 => return round_f128(x), + else => comptime unreachable, } } -test "round32" { - try expect(roundf(1.3) == 1.0); - try expect(roundf(-1.3) == -1.0); - try expect(roundf(0.2) == 0.0); - try expect(roundf(1.8) == 2.0); +test round_f16 { + try expect(round_f16(1.3) == 1.0); + try expect(round_f16(-1.3) == -1.0); + try expect(round_f16(1.8) == 2.0); + try expect(round_f16(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f16(0.2))); + try expect(math.isNegativeZero(round_f16(-0.2))); + try expect(math.isPositiveZero(round_f16(0.0))); + try expect(math.isNegativeZero(round_f16(-0.0))); + try expect(math.isPositiveInf(round_f16(math.inf(f32)))); + try expect(math.isNegativeInf(round_f16(-math.inf(f32)))); + try expect(math.isNan(round_f16(math.nan(f32)))); } -test "round64" { - try expect(round(1.3) == 1.0); - try expect(round(-1.3) == -1.0); - try expect(round(0.2) == 0.0); - try expect(round(1.8) == 2.0); +test round_f32 { + try expect(round_f32(1.3) == 1.0); + try expect(round_f32(-1.3) == -1.0); + try expect(round_f32(1.8) == 2.0); + try expect(round_f32(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f32(0.2))); + try expect(math.isNegativeZero(round_f32(-0.2))); + try expect(math.isPositiveZero(round_f32(0.0))); + try expect(math.isNegativeZero(round_f32(-0.0))); + try expect(math.isPositiveInf(round_f32(math.inf(f32)))); + try expect(math.isNegativeInf(round_f32(-math.inf(f32)))); + try expect(math.isNan(round_f32(math.nan(f32)))); } -test "round128" { - try expect(roundq(1.3) == 1.0); - try expect(roundq(-1.3) == -1.0); - try expect(roundq(0.2) == 0.0); - try expect(roundq(1.8) == 2.0); +test round_f64 { + try expect(round_f64(1.3) == 1.0); + try expect(round_f64(-1.3) == -1.0); + try expect(round_f64(1.8) == 2.0); + try expect(round_f64(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f64(0.2))); + try expect(math.isNegativeZero(round_f64(-0.2))); + try expect(math.isPositiveZero(round_f64(0.0))); + try expect(math.isNegativeZero(round_f64(-0.0))); + try expect(math.isPositiveInf(round_f64(math.inf(f64)))); + try expect(math.isNegativeInf(round_f64(-math.inf(f64)))); + try expect(math.isNan(round_f64(math.nan(f64)))); } -test "round32.special" { - try expect(roundf(0.0) == 0.0); - try expect(roundf(-0.0) == -0.0); - try expect(math.isPositiveInf(roundf(math.inf(f32)))); - try expect(math.isNegativeInf(roundf(-math.inf(f32)))); - try expect(math.isNan(roundf(math.nan(f32)))); +test round_f80 { + try expect(round_f80(1.3) == 1.0); + try expect(round_f80(-1.3) == -1.0); + try expect(round_f80(1.8) == 2.0); + try expect(round_f80(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f80(0.2))); + try expect(math.isNegativeZero(round_f80(-0.2))); + try expect(math.isPositiveZero(round_f80(0.0))); + try expect(math.isNegativeZero(round_f80(-0.0))); + try expect(math.isPositiveInf(round_f80(math.inf(f64)))); + try expect(math.isNegativeInf(round_f80(-math.inf(f64)))); + try expect(math.isNan(round_f80(math.nan(f64)))); } -test "round64.special" { - try expect(round(0.0) == 0.0); - try expect(round(-0.0) == -0.0); - try expect(math.isPositiveInf(round(math.inf(f64)))); - try expect(math.isNegativeInf(round(-math.inf(f64)))); - try expect(math.isNan(round(math.nan(f64)))); -} - -test "round128.special" { - try expect(roundq(0.0) == 0.0); - try expect(roundq(-0.0) == -0.0); - try expect(math.isPositiveInf(roundq(math.inf(f128)))); - try expect(math.isNegativeInf(roundq(-math.inf(f128)))); - try expect(math.isNan(roundq(math.nan(f128)))); +test round_f128 { + try expect(round_f128(1.3) == 1.0); + try expect(round_f128(-1.3) == -1.0); + try expect(round_f128(1.8) == 2.0); + try expect(round_f128(-1.8) == -2.0); + try expect(math.isPositiveZero(round_f128(0.2))); + try expect(math.isNegativeZero(round_f128(-0.2))); + try expect(math.isPositiveZero(round_f128(0.0))); + try expect(math.isNegativeZero(round_f128(-0.0))); + try expect(math.isPositiveInf(round_f128(math.inf(f128)))); + try expect(math.isNegativeInf(round_f128(-math.inf(f128)))); + try expect(math.isNan(round_f128(math.nan(f128)))); } diff --git a/lib/compiler_rt/sin.zig b/lib/compiler_rt/sin.zig index 040cba8cd3ef34e59f6bfd181a3c09036963fb4c..3e0b8f0cbd823b0e57fe0172217c7726955c7fd1 100644 --- a/lib/compiler_rt/sin.zig +++ b/lib/compiler_rt/sin.zig @@ -13,31 +13,34 @@ const expect = std.testing.expect; const expectApproxEqAbs = std.testing.expectApproxEqAbs; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const trig = @import("trig.zig"); const rem_pio2 = @import("rem_pio2.zig").rem_pio2; const rem_pio2f = @import("rem_pio2f.zig").rem_pio2f; const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l; comptime { - symbol(&sinh, "__sinh"); - symbol(&sinl, "__sinl"); + symbol(&__sinh, "__sinh"); symbol(&sinf, "sinf"); symbol(&sin, "sin"); - symbol(&sinx, "__sinx"); - if (compiler_rt.want_ppc_abi) { - symbol(&sinq, "sinf128"); - } - symbol(&sinq, "sinq"); + symbol(&__sinx, "__sinx"); + symbol(&sinq, "sinf128"); symbol(&sinl, "sinl"); + symbol(&sinl, "__sinl"); // required by musl } -pub fn sinh(x: f16) callconv(.c) f16 { +fn __sinh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(sin_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn sin_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(sinf(x)); + return @floatCast(sin_f32(x)); } -pub fn sinf(x: f32) callconv(.c) f32 { +fn sinf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(sin_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn sin_f32(x: f32) f32 { // Small multiples of pi/2 rounded to double precision. const s1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 const s2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 @@ -98,7 +101,10 @@ pub fn sinf(x: f32) callconv(.c) f32 { }; } -pub fn sin(x: f64) callconv(.c) f64 { +fn sin(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(sin_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn sin_f64(x: f64) f64 { var ix = @as(u64, @bitCast(x)) >> 32; ix &= 0x7fffffff; @@ -133,7 +139,10 @@ pub fn sin(x: f64) callconv(.c) f64 { }; } -fn sinx(x: f80) callconv(.c) f80 { +fn __sinx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(sin_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn sin_f80(x: f80) f80 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -160,7 +169,10 @@ fn sinx(x: f80) callconv(.c) f80 { }; } -pub fn sinq(x: f128) callconv(.c) f128 { +fn sinq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(sin_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn sin_f128(x: f128) f128 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -189,20 +201,21 @@ pub fn sinq(x: f128) callconv(.c) f128 { pub fn sinl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return sin(x), - 80 => return sinx(x), - 128 => return sinq(x), - else => @compileError("unreachable"), + 64 => return sin_f64(x), + 80 => return sin_f80(x), + 128 => return sin_f128(x), + else => comptime unreachable, } } fn testSinSpecial(comptime T: type) !void { const f = switch (T) { - f32 => sinf, - f64 => sin, - f80 => sinx, - f128 => sinq, - else => @compileError("unimplemented"), + f16 => sin_f16, + f32 => sin_f32, + f64 => sin_f64, + f80 => sin_f80, + f128 => sin_f128, + else => comptime unreachable, }; try expect(math.isPositiveZero(f(0.0))); @@ -214,13 +227,13 @@ fn testSinSpecial(comptime T: type) !void { test "sin32.normal" { const epsilon = math.floatEps(f32); - try expectApproxEqAbs(@as(f32, 0.0), sinf(0.0), epsilon); - try expectApproxEqAbs(@as(f32, 0.19866933), sinf(0.2), epsilon); - try expectApproxEqAbs(@as(f32, 0.77851737), sinf(0.8923), epsilon); - try expectApproxEqAbs(@as(f32, 0.997495), sinf(1.5), epsilon); - try expectApproxEqAbs(@as(f32, -0.997495), sinf(-1.5), epsilon); - try expectApproxEqAbs(@as(f32, -0.24654257), sinf(37.45), epsilon); - try expectApproxEqAbs(@as(f32, 0.9161657), sinf(89.123), epsilon); + try expectApproxEqAbs(@as(f32, 0.0), sin_f32(0.0), epsilon); + try expectApproxEqAbs(@as(f32, 0.19866933), sin_f32(0.2), epsilon); + try expectApproxEqAbs(@as(f32, 0.77851737), sin_f32(0.8923), epsilon); + try expectApproxEqAbs(@as(f32, 0.997495), sin_f32(1.5), epsilon); + try expectApproxEqAbs(@as(f32, -0.997495), sin_f32(-1.5), epsilon); + try expectApproxEqAbs(@as(f32, -0.24654257), sin_f32(37.45), epsilon); + try expectApproxEqAbs(@as(f32, 0.9161657), sin_f32(89.123), epsilon); } test "sin32.special" { @@ -229,13 +242,13 @@ test "sin32.special" { test "sin64.normal" { const epsilon = math.floatEps(f64); - try expectApproxEqAbs(@as(f64, 0.0), sin(0.0), epsilon); - try expectApproxEqAbs(@as(f64, 0.19866933079506122), sin(0.2), epsilon); - try expectApproxEqAbs(@as(f64, 0.7785173385577349), sin(0.8923), epsilon); - try expectApproxEqAbs(@as(f64, 0.9974949866040544), sin(1.5), epsilon); - try expectApproxEqAbs(@as(f64, -0.9974949866040544), sin(-1.5), epsilon); - try expectApproxEqAbs(@as(f64, -0.24654331551411082), sin(37.45), epsilon); - try expectApproxEqAbs(@as(f64, 0.9161652766622714), sin(89.123), epsilon); + try expectApproxEqAbs(@as(f64, 0.0), sin_f64(0.0), epsilon); + try expectApproxEqAbs(@as(f64, 0.19866933079506122), sin_f64(0.2), epsilon); + try expectApproxEqAbs(@as(f64, 0.7785173385577349), sin_f64(0.8923), epsilon); + try expectApproxEqAbs(@as(f64, 0.9974949866040544), sin_f64(1.5), epsilon); + try expectApproxEqAbs(@as(f64, -0.9974949866040544), sin_f64(-1.5), epsilon); + try expectApproxEqAbs(@as(f64, -0.24654331551411082), sin_f64(37.45), epsilon); + try expectApproxEqAbs(@as(f64, 0.9161652766622714), sin_f64(89.123), epsilon); } test "sin64.special" { @@ -244,13 +257,13 @@ test "sin64.special" { test "sin80.normal" { const epsilon = math.floatEps(f80); - try expectApproxEqAbs(@as(f80, 0.0), sinx(0.0), epsilon); - try expectApproxEqAbs(@as(f80, 0.19866933079506121545941262711838975), sinx(0.2), epsilon); - try expectApproxEqAbs(@as(f80, 0.77851733855773487830689285621486050), sinx(0.8923), epsilon); - try expectApproxEqAbs(@as(f80, 0.99749498660405443094172337114148732), sinx(1.5), epsilon); - try expectApproxEqAbs(@as(f80, -0.99749498660405443094172337114148732), sinx(-1.5), epsilon); - try expectApproxEqAbs(@as(f80, -0.24654331551411356504), sinx(37.45), epsilon); - try expectApproxEqAbs(@as(f80, 0.91616527666226951006), sinx(89.123), epsilon); + try expectApproxEqAbs(@as(f80, 0.0), sin_f80(0.0), epsilon); + try expectApproxEqAbs(@as(f80, 0.19866933079506121545941262711838975), sin_f80(0.2), epsilon); + try expectApproxEqAbs(@as(f80, 0.77851733855773487830689285621486050), sin_f80(0.8923), epsilon); + try expectApproxEqAbs(@as(f80, 0.99749498660405443094172337114148732), sin_f80(1.5), epsilon); + try expectApproxEqAbs(@as(f80, -0.99749498660405443094172337114148732), sin_f80(-1.5), epsilon); + try expectApproxEqAbs(@as(f80, -0.24654331551411356504), sin_f80(37.45), epsilon); + try expectApproxEqAbs(@as(f80, 0.91616527666226951006), sin_f80(89.123), epsilon); } test "sin80.special" { @@ -259,13 +272,13 @@ test "sin80.special" { test "sin128.normal" { const epsilon = math.floatEps(f128); - try expectApproxEqAbs(@as(f128, 0.0), sinq(0.0), epsilon); - try expectApproxEqAbs(@as(f128, 0.19866933079506121545941262711838975), sinq(0.2), epsilon); - try expectApproxEqAbs(@as(f128, 0.77851733855773487830689285621486050), sinq(0.8923), epsilon); - try expectApproxEqAbs(@as(f128, 0.99749498660405443094172337114148732), sinq(1.5), epsilon); - try expectApproxEqAbs(@as(f128, -0.99749498660405443094172337114148732), sinq(-1.5), epsilon); - try expectApproxEqAbs(@as(f128, -0.24654331551411356571238581321661085), sinq(37.45), epsilon); - try expectApproxEqAbs(@as(f128, 0.91616527666226951075019849560482170), sinq(89.123), epsilon); + try expectApproxEqAbs(@as(f128, 0.0), sin_f128(0.0), epsilon); + try expectApproxEqAbs(@as(f128, 0.19866933079506121545941262711838975), sin_f128(0.2), epsilon); + try expectApproxEqAbs(@as(f128, 0.77851733855773487830689285621486050), sin_f128(0.8923), epsilon); + try expectApproxEqAbs(@as(f128, 0.99749498660405443094172337114148732), sin_f128(1.5), epsilon); + try expectApproxEqAbs(@as(f128, -0.99749498660405443094172337114148732), sin_f128(-1.5), epsilon); + try expectApproxEqAbs(@as(f128, -0.24654331551411356571238581321661085), sin_f128(37.45), epsilon); + try expectApproxEqAbs(@as(f128, 0.91616527666226951075019849560482170), sin_f128(89.123), epsilon); } test "sin128.special" { @@ -274,10 +287,10 @@ test "sin128.special" { test "sin32 #9901" { const float: f32 = @bitCast(@as(u32, 0b11100011111111110000000000000000)); - _ = sinf(float); + _ = sin_f32(float); } test "sin64 #9901" { const float: f64 = @bitCast(@as(u64, 0b1111111101000001000000001111110111111111100000000000000000000001)); - _ = sin(float); + _ = sin_f64(float); } diff --git a/lib/compiler_rt/sincos.zig b/lib/compiler_rt/sincos.zig index 24bb751e76e7e93d32b05a4a801dec6d5d474709..d43f55b623954f602edf850b75d409931b1aaee6 100644 --- a/lib/compiler_rt/sincos.zig +++ b/lib/compiler_rt/sincos.zig @@ -18,23 +18,27 @@ comptime { symbol(&sincosf, "sincosf"); symbol(&sincos, "sincos"); symbol(&sincosx, "__sincosx"); - if (compiler_rt.want_ppc_abi) { - symbol(&sincosq, "sincosf128"); - } - symbol(&sincosq, "sincosq"); + symbol(&sincosq, "sincosf128"); symbol(&sincosl, "sincosl"); } -pub fn sincosh(x: f16, r_sin: *f16, r_cos: *f16) callconv(.c) void { +fn sincosh(x: compiler_rt.f16.Abi, r_sin: *compiler_rt.f16.Abi, r_cos: *compiler_rt.f16.Abi) callconv(.c) void { + const s, const c = sincos_f16(compiler_rt.f16.fromAbi(x)); + r_sin.* = compiler_rt.f16.toAbi(s); + r_cos.* = compiler_rt.f16.toAbi(c); +} +pub fn sincos_f16(x: f16) struct { f16, f16 } { // TODO: more efficient implementation - var big_sin: f32 = undefined; - var big_cos: f32 = undefined; - sincosf(x, &big_sin, &big_cos); - r_sin.* = @as(f16, @floatCast(big_sin)); - r_cos.* = @as(f16, @floatCast(big_cos)); + const s, const c = sincos_f32(x); + return .{ @floatCast(s), @floatCast(c) }; } -pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { +fn sincosf(x: compiler_rt.f32.Abi, r_sin: *compiler_rt.f32.Abi, r_cos: *compiler_rt.f32.Abi) callconv(.c) void { + const s, const c = sincos_f32(compiler_rt.f32.fromAbi(x)); + r_sin.* = compiler_rt.f32.toAbi(s); + r_cos.* = compiler_rt.f32.toAbi(c); +} +pub fn sincos_f32(x: f32) struct { f32, f32 } { const sc1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 const sc2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 const sc3pio2: f64 = 3.0 * math.pi / 2.0; // 0x4012D97C, 0x7F3321D2 @@ -56,13 +60,9 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { mem.doNotOptimizeAway(x + 0x1p120); } } - r_sin.* = x; - r_cos.* = 1.0; - return; + return .{ x, 1.0 }; } - r_sin.* = trig.sindf(x); - r_cos.* = trig.cosdf(x); - return; + return .{ trig.sindf(x), trig.cosdf(x) }; } // |x| ~<= 5*pi/4 @@ -70,18 +70,16 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { // |x| ~<= 3pi/4 if (ix <= 0x4016cbe3) { if (sign) { - r_sin.* = -trig.cosdf(x + sc1pio2); - r_cos.* = trig.sindf(x + sc1pio2); + return .{ -trig.cosdf(x + sc1pio2), trig.sindf(x + sc1pio2) }; } else { - r_sin.* = trig.cosdf(sc1pio2 - x); - r_cos.* = trig.sindf(sc1pio2 - x); + return .{ trig.cosdf(sc1pio2 - x), trig.sindf(sc1pio2 - x) }; } - return; } // -sin(x+c) is not correct if x+c could be 0: -0 vs +0 - r_sin.* = -trig.sindf(if (sign) x + sc2pio2 else x - sc2pio2); - r_cos.* = -trig.cosdf(if (sign) x + sc2pio2 else x - sc2pio2); - return; + return .{ + -trig.sindf(if (sign) x + sc2pio2 else x - sc2pio2), + -trig.cosdf(if (sign) x + sc2pio2 else x - sc2pio2), + }; } // |x| ~<= 9*pi/4 @@ -89,25 +87,21 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { // |x| ~<= 7*pi/4 if (ix <= 0x40afeddf) { if (sign) { - r_sin.* = trig.cosdf(x + sc3pio2); - r_cos.* = -trig.sindf(x + sc3pio2); + return .{ trig.cosdf(x + sc3pio2), -trig.sindf(x + sc3pio2) }; } else { - r_sin.* = -trig.cosdf(x - sc3pio2); - r_cos.* = trig.sindf(x - sc3pio2); + return .{ -trig.cosdf(x - sc3pio2), trig.sindf(x - sc3pio2) }; } - return; } - r_sin.* = trig.sindf(if (sign) x + sc4pio2 else x - sc4pio2); - r_cos.* = trig.cosdf(if (sign) x + sc4pio2 else x - sc4pio2); - return; + return .{ + trig.sindf(if (sign) x + sc4pio2 else x - sc4pio2), + trig.cosdf(if (sign) x + sc4pio2 else x - sc4pio2), + }; } // sin(Inf or NaN) is NaN if (ix >= 0x7f800000) { const result = x - x; - r_sin.* = result; - r_cos.* = result; - return; + return .{ result, result }; } // general argument reduction needed @@ -115,27 +109,20 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { const n = rem_pio2f(x, &y); const s = trig.sindf(y); const c = trig.cosdf(y); - switch (n & 3) { - 0 => { - r_sin.* = s; - r_cos.* = c; - }, - 1 => { - r_sin.* = c; - r_cos.* = -s; - }, - 2 => { - r_sin.* = -s; - r_cos.* = -c; - }, - else => { - r_sin.* = -c; - r_cos.* = s; - }, - } + return switch (@as(u2, @truncate(@as(u32, @bitCast(n))))) { + 0 => .{ s, c }, + 1 => .{ c, -s }, + 2 => .{ -s, -c }, + 3 => .{ -c, s }, + }; } -pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void { +fn sincos(x: compiler_rt.f64.Abi, r_sin: *compiler_rt.f64.Abi, r_cos: *compiler_rt.f64.Abi) callconv(.c) void { + const s, const c = sincos_f64(compiler_rt.f64.fromAbi(x)); + r_sin.* = compiler_rt.f64.toAbi(s); + r_cos.* = compiler_rt.f64.toAbi(c); +} +pub fn sincos_f64(x: f64) struct { f64, f64 } { const ix = @as(u32, @truncate(@as(u64, @bitCast(x)) >> 32)) & 0x7fffffff; // |x| ~< pi/4 @@ -150,21 +137,15 @@ pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void { mem.doNotOptimizeAway(x + 0x1p120); } } - r_sin.* = x; - r_cos.* = 1.0; - return; + return .{ x, 1.0 }; } - r_sin.* = trig.sin(x, 0.0, 0); - r_cos.* = trig.cos(x, 0.0); - return; + return .{ trig.sin(x, 0.0, 0), trig.cos(x, 0.0) }; } // sincos(Inf or NaN) is NaN if (ix >= 0x7ff00000) { const result = x - x; - r_sin.* = result; - r_cos.* = result; - return; + return .{ result, result }; } // argument reduction needed @@ -172,33 +153,24 @@ pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void { const n = rem_pio2(x, &y); const s = trig.sin(y[0], y[1], 1); const c = trig.cos(y[0], y[1]); - switch (n & 3) { - 0 => { - r_sin.* = s; - r_cos.* = c; - }, - 1 => { - r_sin.* = c; - r_cos.* = -s; - }, - 2 => { - r_sin.* = -s; - r_cos.* = -c; - }, - else => { - r_sin.* = -c; - r_cos.* = s; - }, - } + return switch (@as(u2, @truncate(@as(u32, @bitCast(n))))) { + 0 => .{ s, c }, + 1 => .{ c, -s }, + 2 => .{ -s, -c }, + 3 => .{ -c, s }, + }; } -pub fn sincosx(x: f80, r_sin: *f80, r_cos: *f80) callconv(.c) void { +fn sincosx(x: compiler_rt.f80.Abi, r_sin: *compiler_rt.f80.Abi, r_cos: *compiler_rt.f80.Abi) callconv(.c) void { + const s, const c = sincos_f80(compiler_rt.f80.fromAbi(x)); + r_sin.* = compiler_rt.f80.toAbi(s); + r_cos.* = compiler_rt.f80.toAbi(c); +} +pub fn sincos_f80(x: f80) struct { f80, f80 } { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { const result = x - x; - r_sin.* = result; - r_cos.* = result; - return; + return .{ result, result }; } if (@abs(x) < trig.pi_4) { @@ -207,47 +179,34 @@ pub fn sincosx(x: f80, r_sin: *f80, r_cos: *f80) callconv(.c) void { if (compiler_rt.want_float_exceptions and se == 0) { mem.doNotOptimizeAway(x * 0x1p-120); } - r_sin.* = x; // raise inexact if x!=0 - r_cos.* = 1.0 + x; - return; + return .{ x, 1.0 + x }; } - r_sin.* = trig.sinx(x, 0.0, 0); - r_cos.* = trig.cosx(x, 0.0); - return; + return .{ trig.sinx(x, 0.0, 0), trig.cosx(x, 0.0) }; } var y: [2]f80 = undefined; const n = rem_pio2l(f80, x, &y); const s = trig.sinx(y[0], y[1], 1); const c = trig.cosx(y[0], y[1]); - switch (n & 3) { - 0 => { - r_sin.* = s; - r_cos.* = c; - }, - 1 => { - r_sin.* = c; - r_cos.* = -s; - }, - 2 => { - r_sin.* = -s; - r_cos.* = -c; - }, - else => { - r_sin.* = -c; - r_cos.* = s; - }, - } + return switch (@as(u2, @truncate(@as(u32, @bitCast(n))))) { + 0 => .{ s, c }, + 1 => .{ c, -s }, + 2 => .{ -s, -c }, + 3 => .{ -c, s }, + }; } -pub fn sincosq(x: f128, r_sin: *f128, r_cos: *f128) callconv(.c) void { +fn sincosq(x: compiler_rt.f128.Abi, r_sin: *compiler_rt.f128.Abi, r_cos: *compiler_rt.f128.Abi) callconv(.c) void { + const s, const c = sincos_f128(compiler_rt.f128.fromAbi(x)); + r_sin.* = compiler_rt.f128.toAbi(s); + r_cos.* = compiler_rt.f128.toAbi(c); +} +pub fn sincos_f128(x: f128) struct { f128, f128 } { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { const result = x - x; - r_sin.* = result; - r_cos.* = result; - return; + return .{ result, result }; } if (@abs(x) < trig.pi_4) { @@ -256,78 +215,63 @@ pub fn sincosq(x: f128, r_sin: *f128, r_cos: *f128) callconv(.c) void { if (compiler_rt.want_float_exceptions and se == 0) { mem.doNotOptimizeAway(x * 0x1p-120); } - r_sin.* = x; // raise inexact if x!=0 - r_cos.* = 1.0 + x; - return; + return .{ x, 1.0 + x }; } - r_sin.* = trig.sinq(x, 0.0, 0); - r_cos.* = trig.cosq(x, 0.0); - return; + return .{ trig.sinq(x, 0.0, 0), trig.cosq(x, 0.0) }; } var y: [2]f128 = undefined; const n = rem_pio2l(f128, x, &y); const s = trig.sinq(y[0], y[1], 1); const c = trig.cosq(y[0], y[1]); - switch (n & 3) { - 0 => { - r_sin.* = s; - r_cos.* = c; - }, - 1 => { - r_sin.* = c; - r_cos.* = -s; - }, - 2 => { - r_sin.* = -s; - r_cos.* = -c; - }, - else => { - r_sin.* = -c; - r_cos.* = s; - }, - } + return switch (@as(u2, @truncate(@as(u32, @bitCast(n))))) { + 0 => .{ s, c }, + 1 => .{ c, -s }, + 2 => .{ -s, -c }, + 3 => .{ -c, s }, + }; } pub fn sincosl(x: c_longdouble, r_sin: *c_longdouble, r_cos: *c_longdouble) callconv(.c) void { - switch (@typeInfo(c_longdouble).float.bits) { - 64 => return sincos(x, r_sin, r_cos), - 80 => return sincosx(x, r_sin, r_cos), - 128 => return sincosq(x, r_sin, r_cos), - else => @compileError("unreachable"), - } + r_sin.*, r_cos.* = switch (@typeInfo(c_longdouble).float.bits) { + 64 => sincos_f64(x), + 80 => sincos_f80(x), + 128 => sincos_f128(x), + else => comptime unreachable, + }; } fn testSincosSpecial(comptime T: type) !void { const f = switch (T) { - f32 => sincosf, - f64 => sincos, - f80 => sincosx, - f128 => sincosq, + f16 => sincos_f16, + f32 => sincos_f32, + f64 => sincos_f64, + f80 => sincos_f80, + f128 => sincos_f128, else => @compileError("unimplemented"), }; var s: T = undefined; var c: T = undefined; - f(0.0, &s, &c); + s, c = f(0.0); try expect(math.isPositiveZero(s)); try expect(c == 1.0); - f(-0.0, &s, &c); + s, c = f(-0.0); try expect(math.isNegativeZero(s)); try expect(c == 1.0); - f(math.inf(T), &s, &c); + s, c = f(math.inf(T)); try expect(math.isNan(s)); try expect(math.isNan(c)); - f(-math.inf(T), &s, &c); + s, c = f(-math.inf(T)); try expect(math.isNan(s)); try expect(math.isNan(c)); - f(math.nan(T), &s, &c); + s, c = f(math.nan(T)); try expect(math.isNan(s)); try expect(math.isNan(c)); } @@ -337,31 +281,31 @@ test "sincos32.normal" { var s: f32 = undefined; var c: f32 = undefined; - sincosf(0.0, &s, &c); + s, c = sincos_f32(0.0); try expectApproxEqAbs(@as(f32, 0.0), s, epsilon); try expectApproxEqAbs(@as(f32, 1.0), c, epsilon); - sincosf(0.2, &s, &c); + s, c = sincos_f32(0.2); try expectApproxEqAbs(@as(f32, 0.19866933), s, epsilon); try expectApproxEqAbs(@as(f32, 0.9800666), c, epsilon); - sincosf(0.8923, &s, &c); + s, c = sincos_f32(0.8923); try expectApproxEqAbs(@as(f32, 0.77851737), s, epsilon); try expectApproxEqAbs(@as(f32, 0.6276231), c, epsilon); - sincosf(1.5, &s, &c); + s, c = sincos_f32(1.5); try expectApproxEqAbs(@as(f32, 0.997495), s, epsilon); try expectApproxEqAbs(@as(f32, 0.0707372), c, epsilon); - sincosf(-1.5, &s, &c); + s, c = sincos_f32(-1.5); try expectApproxEqAbs(@as(f32, -0.997495), s, epsilon); try expectApproxEqAbs(@as(f32, 0.0707372), c, epsilon); - sincosf(37.45, &s, &c); + s, c = sincos_f32(37.45); try expectApproxEqAbs(@as(f32, -0.24654257), s, epsilon); try expectApproxEqAbs(@as(f32, 0.96913195), c, epsilon); - sincosf(89.123, &s, &c); + s, c = sincos_f32(89.123); try expectApproxEqAbs(@as(f32, 0.9161657), s, epsilon); try expectApproxEqAbs(@as(f32, 0.40079966), c, epsilon); } @@ -375,31 +319,31 @@ test "sincos64.normal" { var s: f64 = undefined; var c: f64 = undefined; - sincos(0.0, &s, &c); + s, c = sincos_f64(0.0); try expectApproxEqAbs(@as(f64, 0.0), s, epsilon); try expectApproxEqAbs(@as(f64, 1.0), c, epsilon); - sincos(0.2, &s, &c); + s, c = sincos_f64(0.2); try expectApproxEqAbs(@as(f64, 0.19866933079506122), s, epsilon); try expectApproxEqAbs(@as(f64, 0.9800665778412416), c, epsilon); - sincos(0.8923, &s, &c); + s, c = sincos_f64(0.8923); try expectApproxEqAbs(@as(f64, 0.7785173385577349), s, epsilon); try expectApproxEqAbs(@as(f64, 0.6276230983360804), c, epsilon); - sincos(1.5, &s, &c); + s, c = sincos_f64(1.5); try expectApproxEqAbs(@as(f64, 0.9974949866040544), s, epsilon); try expectApproxEqAbs(@as(f64, 0.0707372016677029), c, epsilon); - sincos(-1.5, &s, &c); + s, c = sincos_f64(-1.5); try expectApproxEqAbs(@as(f64, -0.9974949866040544), s, epsilon); try expectApproxEqAbs(@as(f64, 0.0707372016677029), c, epsilon); - sincos(37.45, &s, &c); + s, c = sincos_f64(37.45); try expectApproxEqAbs(@as(f64, -0.24654331551411082), s, epsilon); try expectApproxEqAbs(@as(f64, 0.9691317730707778), c, epsilon); - sincos(89.123, &s, &c); + s, c = sincos_f64(89.123); try expectApproxEqAbs(@as(f64, 0.9161652766622714), s, epsilon); try expectApproxEqAbs(@as(f64, 0.4008006809354791), c, epsilon); } @@ -413,31 +357,31 @@ test "sincos80.normal" { var s: f80 = undefined; var c: f80 = undefined; - sincosx(0.0, &s, &c); + s, c = sincos_f80(0.0); try expectApproxEqAbs(@as(f80, 0.0), s, epsilon); try expectApproxEqAbs(@as(f80, 1.0), c, epsilon); - sincosx(0.2, &s, &c); + s, c = sincos_f80(0.2); try expectApproxEqAbs(@as(f80, 0.19866933079506121545941262711838975), s, epsilon); try expectApproxEqAbs(@as(f80, 0.98006657784124163112419651674816888), c, epsilon); - sincosx(0.8923, &s, &c); + s, c = sincos_f80(0.8923); try expectApproxEqAbs(@as(f80, 0.77851733855773487830689285621486050), s, epsilon); try expectApproxEqAbs(@as(f80, 0.62762309833608037003563995939286067), c, epsilon); - sincosx(1.5, &s, &c); + s, c = sincos_f80(1.5); try expectApproxEqAbs(@as(f80, 0.99749498660405443094172337114148732), s, epsilon); try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), c, epsilon); - sincosx(-1.5, &s, &c); + s, c = sincos_f80(-1.5); try expectApproxEqAbs(@as(f80, -0.99749498660405443094172337114148732), s, epsilon); try expectApproxEqAbs(@as(f80, 0.070737201667702910088189851434268747), c, epsilon); - sincosx(37.45, &s, &c); + s, c = sincos_f80(37.45); try expectApproxEqAbs(@as(f80, -0.24654331551411356504), s, epsilon); try expectApproxEqAbs(@as(f80, 0.9691317730707771246), c, epsilon); - sincosx(89.123, &s, &c); + s, c = sincos_f80(89.123); try expectApproxEqAbs(@as(f80, 0.91616527666226951006), s, epsilon); try expectApproxEqAbs(@as(f80, 0.4008006809354834001), c, epsilon); } @@ -451,31 +395,31 @@ test "sincos128.normal" { var s: f128 = undefined; var c: f128 = undefined; - sincosq(0.0, &s, &c); + s, c = sincos_f128(0.0); try expectApproxEqAbs(@as(f128, 0.0), s, epsilon); try expectApproxEqAbs(@as(f128, 1.0), c, epsilon); - sincosq(0.2, &s, &c); + s, c = sincos_f128(0.2); try expectApproxEqAbs(@as(f128, 0.19866933079506121545941262711838975), s, epsilon); try expectApproxEqAbs(@as(f128, 0.98006657784124163112419651674816888), c, epsilon); - sincosq(0.8923, &s, &c); + s, c = sincos_f128(0.8923); try expectApproxEqAbs(@as(f128, 0.77851733855773487830689285621486050), s, epsilon); try expectApproxEqAbs(@as(f128, 0.62762309833608037003563995939286067), c, epsilon); - sincosq(1.5, &s, &c); + s, c = sincos_f128(1.5); try expectApproxEqAbs(@as(f128, 0.99749498660405443094172337114148732), s, epsilon); try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), c, epsilon); - sincosq(-1.5, &s, &c); + s, c = sincos_f128(-1.5); try expectApproxEqAbs(@as(f128, -0.99749498660405443094172337114148732), s, epsilon); try expectApproxEqAbs(@as(f128, 0.070737201667702910088189851434268747), c, epsilon); - sincosq(37.45, &s, &c); + s, c = sincos_f128(37.45); try expectApproxEqAbs(@as(f128, -0.24654331551411356571238581321661085), s, epsilon); try expectApproxEqAbs(@as(f128, 0.96913177307077712443149563847233230), c, epsilon); - sincosq(89.123, &s, &c); + s, c = sincos_f128(89.123); try expectApproxEqAbs(@as(f128, 0.91616527666226951075019849560482170), s, epsilon); try expectApproxEqAbs(@as(f128, 0.40080068093548339848199454493704702), c, epsilon); } diff --git a/lib/compiler_rt/sqrt.zig b/lib/compiler_rt/sqrt.zig index 739285af0eaa66af2cf6ed31a3dcc142a708b590..a37fe429c1458153dded08805982d118dedb8ebb 100644 --- a/lib/compiler_rt/sqrt.zig +++ b/lib/compiler_rt/sqrt.zig @@ -17,18 +17,19 @@ comptime { symbol(&sqrtf, "sqrtf"); symbol(&sqrt, "sqrt"); symbol(&__sqrtx, "__sqrtx"); - if (compiler_rt.want_ppc_abi) { - symbol(&sqrtq, "sqrtf128"); - } else if (compiler_rt.want_sparc64_abi) { + symbol(&sqrtq, "sqrtf128"); + if (compiler_rt.want_sparc64_abi) { symbol(&_Qp_sqrt, "_Qp_sqrt"); } else if (compiler_rt.want_sparc32_abi) { symbol(&sqrtq, "_Q_sqrt"); } - symbol(&sqrtq, "sqrtq"); symbol(&sqrtl, "sqrtl"); } -pub fn __sqrth(x: f16) callconv(.c) f16 { +fn __sqrth(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(sqrt_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn sqrt_f16(x: f16) f16 { var ix: u16 = @bitCast(x); var top = ix >> 10; @@ -93,7 +94,10 @@ pub fn __sqrth(x: f16) callconv(.c) f16 { return y; } -pub fn sqrtf(x: f32) callconv(.c) f32 { +fn sqrtf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(sqrt_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn sqrt_f32(x: f32) f32 { var ix: u32 = @bitCast(x); if (ix < @as(u32, @bitCast(@as(f32, 0x1p-126))) or @as(u32, @bitCast(std.math.inf(f32))) <= ix) { @@ -147,7 +151,10 @@ pub fn sqrtf(x: f32) callconv(.c) f32 { return y + t; } -pub fn sqrt(x: f64) callconv(.c) f64 { +fn sqrt(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(sqrt_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn sqrt_f64(x: f64) f64 { var ix: u64 = @bitCast(x); var top = ix >> 52; @@ -284,7 +291,10 @@ pub fn sqrt(x: f64) callconv(.c) f64 { return y; } -pub fn __sqrtx(x: f80) callconv(.c) f80 { +fn __sqrtx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(sqrt_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn sqrt_f80(x: f80) f80 { var ix: u80 = @bitCast(x); var top = ix >> 64; @@ -381,7 +391,10 @@ pub fn __sqrtx(x: f80) callconv(.c) f80 { return y; } -pub fn sqrtq(x: f128) callconv(.c) f128 { +fn sqrtq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(sqrt_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn sqrt_f128(x: f128) f128 { var ix: u128 = @bitCast(x); var top = ix >> 112; @@ -483,10 +496,10 @@ fn _Qp_sqrt(c: *f128, a: *f128) callconv(.c) void { pub fn sqrtl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return sqrt(x), - 80 => return __sqrtx(x), - 128 => return sqrtq(x), - else => @compileError("unreachable"), + 64 => return sqrt_f64(x), + 80 => return sqrt_f80(x), + 128 => return sqrt_f128(x), + else => comptime unreachable, } } @@ -545,187 +558,187 @@ inline fn mul80_tail(a: u80, b: u80) u80 { return alo * blo +% ((ahi * blo) << 40) +% ((alo * bhi) << 40); } -test "__sqrth" { +test "sqrt_f16" { // sqrt(±0) is ±0 - try std.testing.expectEqual(__sqrth(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(__sqrth(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f16(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f16(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(__sqrth(0x1.FFCp15), 0x1.FFCp7); + try std.testing.expectEqual(sqrt_f16(0x1.FFCp15), 0x1.FFCp7); // sqrt(4)=2 - try std.testing.expectEqual(__sqrth(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f16(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(__sqrth(0x1p0), 0x1p0); - try std.testing.expectEqual(__sqrth(0x1.004p0), 0x1p0); - try std.testing.expectEqual(__sqrth(0x1.FF8p-1), 0x1.FFCp-1); + try std.testing.expectEqual(sqrt_f16(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f16(0x1.004p0), 0x1p0); + try std.testing.expectEqual(sqrt_f16(0x1.FF8p-1), 0x1.FFCp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(__sqrth(0x1p-14), 0x1p-7); + try std.testing.expectEqual(sqrt_f16(0x1p-14), 0x1p-7); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(__sqrth(0x0.004p-14), 0x1p-12); + try std.testing.expectEqual(sqrt_f16(0x0.004p-14), 0x1p-12); // sqrt(inf) is inf - try std.testing.expect(math.isInf(__sqrth(math.inf(f16)))); + try std.testing.expect(math.isInf(sqrt_f16(math.inf(f16)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(__sqrth(math.nan(f16)))); + try std.testing.expect(math.isNan(sqrt_f16(math.nan(f16)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(__sqrth(-0x1p-14))); - try std.testing.expect(math.isNan(__sqrth(-0x1p+0))); - try std.testing.expect(math.isNan(__sqrth(-math.inf(f16)))); + try std.testing.expect(math.isNan(sqrt_f16(-0x1p-14))); + try std.testing.expect(math.isNan(sqrt_f16(-0x1p+0))); + try std.testing.expect(math.isNan(sqrt_f16(-math.inf(f16)))); // random arguments - try std.testing.expectEqual(__sqrth(0x1.1p14), 0x1.08p7); - try std.testing.expectEqual(__sqrth(0x1.C9p-12), 0x1.56p-6); - try std.testing.expectEqual(__sqrth(0x1.CE8p-7), 0x1.E68p-4); - try std.testing.expectEqual(__sqrth(0x1.134p-7), 0x1.778p-4); - try std.testing.expectEqual(__sqrth(0x1.E9Cp-10), 0x1.62p-5); - try std.testing.expectEqual(__sqrth(0x1.3Dp9), 0x1.92Cp4); - try std.testing.expectEqual(__sqrth(0x1.AA4p8), 0x1.4A4p4); - try std.testing.expectEqual(__sqrth(0x1.8A8p4), 0x1.3DCp2); - try std.testing.expectEqual(__sqrth(0x1.8Fp-7), 0x1.C4p-4); - try std.testing.expectEqual(__sqrth(0x1.584p-11), 0x1.A3Cp-6); + try std.testing.expectEqual(sqrt_f16(0x1.1p14), 0x1.08p7); + try std.testing.expectEqual(sqrt_f16(0x1.C9p-12), 0x1.56p-6); + try std.testing.expectEqual(sqrt_f16(0x1.CE8p-7), 0x1.E68p-4); + try std.testing.expectEqual(sqrt_f16(0x1.134p-7), 0x1.778p-4); + try std.testing.expectEqual(sqrt_f16(0x1.E9Cp-10), 0x1.62p-5); + try std.testing.expectEqual(sqrt_f16(0x1.3Dp9), 0x1.92Cp4); + try std.testing.expectEqual(sqrt_f16(0x1.AA4p8), 0x1.4A4p4); + try std.testing.expectEqual(sqrt_f16(0x1.8A8p4), 0x1.3DCp2); + try std.testing.expectEqual(sqrt_f16(0x1.8Fp-7), 0x1.C4p-4); + try std.testing.expectEqual(sqrt_f16(0x1.584p-11), 0x1.A3Cp-6); } -test "sqrtf" { +test "sqrt_f32" { // sqrt(±0) is ±0 - try std.testing.expectEqual(sqrtf(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(sqrtf(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f32(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f32(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(sqrtf(0x1.FFFFFEp127), 0x1.FFFFFEp63); + try std.testing.expectEqual(sqrt_f32(0x1.FFFFFEp127), 0x1.FFFFFEp63); // sqrt(4)=2 - try std.testing.expectEqual(sqrtf(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f32(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(sqrtf(0x1p0), 0x1p0); - try std.testing.expectEqual(sqrtf(0x1.000002p0), 0x1p0); - try std.testing.expectEqual(sqrtf(0x1.FFFFFEp-1), 0x1.FFFFFEp-1); + try std.testing.expectEqual(sqrt_f32(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f32(0x1.000002p0), 0x1p0); + try std.testing.expectEqual(sqrt_f32(0x1.FFFFFEp-1), 0x1.FFFFFEp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(sqrtf(0x1p-126), 0x1p-63); + try std.testing.expectEqual(sqrt_f32(0x1p-126), 0x1p-63); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(sqrtf(0x0.000002p-126), 0x1.6a09e6p-75); + try std.testing.expectEqual(sqrt_f32(0x0.000002p-126), 0x1.6a09e6p-75); // sqrt(inf) is inf - try std.testing.expect(math.isInf(sqrtf(math.inf(f32)))); + try std.testing.expect(math.isInf(sqrt_f32(math.inf(f32)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(sqrtf(math.nan(f32)))); + try std.testing.expect(math.isNan(sqrt_f32(math.nan(f32)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(sqrtf(-0x1p-149))); - try std.testing.expect(math.isNan(sqrtf(-0x1p0))); - try std.testing.expect(math.isNan(sqrtf(-math.inf(f32)))); + try std.testing.expect(math.isNan(sqrt_f32(-0x1p-149))); + try std.testing.expect(math.isNan(sqrt_f32(-0x1p0))); + try std.testing.expect(math.isNan(sqrt_f32(-math.inf(f32)))); // random arguments - try std.testing.expectEqual(sqrtf(0x1.4DD57Ep77), 0x1.9D6DA8p38); - try std.testing.expectEqual(sqrtf(0x1.871848p102), 0x1.3C6AFAp51); - try std.testing.expectEqual(sqrtf(0x1.A1D748p-112), 0x1.470EFCp-56); - try std.testing.expectEqual(sqrtf(0x1.E626C2p18), 0x1.60C80Ep9); - try std.testing.expectEqual(sqrtf(0x1.E80E66p-29), 0x1.F3E282p-15); - try std.testing.expectEqual(sqrtf(0x1.B47204p89), 0x1.D8B732p44); - try std.testing.expectEqual(sqrtf(0x1.77F45p15), 0x1.B6BC3Ap7); - try std.testing.expectEqual(sqrtf(0x1.AD5F5p-48), 0x1.4B8A72p-24); - try std.testing.expectEqual(sqrtf(0x1.91A39p-76), 0x1.40A7A8p-38); - try std.testing.expectEqual(sqrtf(0x1.DAE088p79), 0x1.ED16DCp39); + try std.testing.expectEqual(sqrt_f32(0x1.4DD57Ep77), 0x1.9D6DA8p38); + try std.testing.expectEqual(sqrt_f32(0x1.871848p102), 0x1.3C6AFAp51); + try std.testing.expectEqual(sqrt_f32(0x1.A1D748p-112), 0x1.470EFCp-56); + try std.testing.expectEqual(sqrt_f32(0x1.E626C2p18), 0x1.60C80Ep9); + try std.testing.expectEqual(sqrt_f32(0x1.E80E66p-29), 0x1.F3E282p-15); + try std.testing.expectEqual(sqrt_f32(0x1.B47204p89), 0x1.D8B732p44); + try std.testing.expectEqual(sqrt_f32(0x1.77F45p15), 0x1.B6BC3Ap7); + try std.testing.expectEqual(sqrt_f32(0x1.AD5F5p-48), 0x1.4B8A72p-24); + try std.testing.expectEqual(sqrt_f32(0x1.91A39p-76), 0x1.40A7A8p-38); + try std.testing.expectEqual(sqrt_f32(0x1.DAE088p79), 0x1.ED16DCp39); } -test "sqrt" { +test "sqrt_f64" { // sqrt(±0) is ±0 - try std.testing.expectEqual(sqrt(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(sqrt(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f64(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f64(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(sqrt(math.floatMax(f64)), 0x1.FFFFFFFFFFFFFp511); + try std.testing.expectEqual(sqrt_f64(math.floatMax(f64)), 0x1.FFFFFFFFFFFFFp511); // sqrt(4)=2 - try std.testing.expectEqual(sqrt(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f64(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(sqrt(0x1p0), 0x1p0); - try std.testing.expectEqual(sqrt(0x1p0 + math.floatEps(f64)), 0x1p0); - try std.testing.expectEqual(sqrt(0x1p0 - math.floatEps(f64)), 0x1.FFFFFFFFFFFFFp-1); + try std.testing.expectEqual(sqrt_f64(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f64(0x1p0 + math.floatEps(f64)), 0x1p0); + try std.testing.expectEqual(sqrt_f64(0x1p0 - math.floatEps(f64)), 0x1.FFFFFFFFFFFFFp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(sqrt(math.floatMin(f64)), 0x1p-511); + try std.testing.expectEqual(sqrt_f64(math.floatMin(f64)), 0x1p-511); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(sqrt(math.floatTrueMin(f64)), 0x1p-537); + try std.testing.expectEqual(sqrt_f64(math.floatTrueMin(f64)), 0x1p-537); // sqrt(inf) is inf - try std.testing.expect(math.isInf(sqrt(math.inf(f64)))); + try std.testing.expect(math.isInf(sqrt_f64(math.inf(f64)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(sqrt(math.nan(f64)))); + try std.testing.expect(math.isNan(sqrt_f64(math.nan(f64)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(sqrt(-0x1p-1074))); - try std.testing.expect(math.isNan(sqrt(-0x1p0))); - try std.testing.expect(math.isNan(sqrt(-math.inf(f64)))); + try std.testing.expect(math.isNan(sqrt_f64(-0x1p-1074))); + try std.testing.expect(math.isNan(sqrt_f64(-0x1p0))); + try std.testing.expect(math.isNan(sqrt_f64(-math.inf(f64)))); // random arguments - try std.testing.expectEqual(sqrt(0x1.27D3510D4789Bp471), 0x1.852E97E58CFB7p235); - try std.testing.expectEqual(sqrt(0x1.8C4FCD5A07846p791), 0x1.C27504E56D938p395); - try std.testing.expectEqual(sqrt(0x1.B1B69324F96E7p-137), 0x1.D73BD0414D8BFp-69); - try std.testing.expectEqual(sqrt(0x1.1CBD179A811FEp278), 0x1.0DFCB9A114A61p139); - try std.testing.expectEqual(sqrt(0x1.1D0C7EFB04A56p917), 0x1.7E0708A25DDCDp458); - try std.testing.expectEqual(sqrt(0x1.21B355DA8C94Bp-249), 0x1.8121CBE2608E3p-125); - try std.testing.expectEqual(sqrt(0x1.63024D4C5E987p487), 0x1.AA56AEA589DCDp243); - try std.testing.expectEqual(sqrt(0x1.45AC3BE941F6Ep339), 0x1.9857F3F453E2Dp169); - try std.testing.expectEqual(sqrt(0x1.3B719C733AA24p267), 0x1.91E12E3AC8F71p133); - try std.testing.expectEqual(sqrt(0x1.0B150433A2275p357), 0x1.71CAB87F8277Cp178); + try std.testing.expectEqual(sqrt_f64(0x1.27D3510D4789Bp471), 0x1.852E97E58CFB7p235); + try std.testing.expectEqual(sqrt_f64(0x1.8C4FCD5A07846p791), 0x1.C27504E56D938p395); + try std.testing.expectEqual(sqrt_f64(0x1.B1B69324F96E7p-137), 0x1.D73BD0414D8BFp-69); + try std.testing.expectEqual(sqrt_f64(0x1.1CBD179A811FEp278), 0x1.0DFCB9A114A61p139); + try std.testing.expectEqual(sqrt_f64(0x1.1D0C7EFB04A56p917), 0x1.7E0708A25DDCDp458); + try std.testing.expectEqual(sqrt_f64(0x1.21B355DA8C94Bp-249), 0x1.8121CBE2608E3p-125); + try std.testing.expectEqual(sqrt_f64(0x1.63024D4C5E987p487), 0x1.AA56AEA589DCDp243); + try std.testing.expectEqual(sqrt_f64(0x1.45AC3BE941F6Ep339), 0x1.9857F3F453E2Dp169); + try std.testing.expectEqual(sqrt_f64(0x1.3B719C733AA24p267), 0x1.91E12E3AC8F71p133); + try std.testing.expectEqual(sqrt_f64(0x1.0B150433A2275p357), 0x1.71CAB87F8277Cp178); } test "__sqrtx" { // sqrt(±0) is ±0 - try std.testing.expectEqual(__sqrtx(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(__sqrtx(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f80(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f80(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(__sqrtx(math.floatMax(f80)), 0x1.FFFFFFFFFFFFFFFEp8191); + try std.testing.expectEqual(sqrt_f80(math.floatMax(f80)), 0x1.FFFFFFFFFFFFFFFEp8191); // sqrt(4)=2 - try std.testing.expectEqual(__sqrtx(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f80(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(__sqrtx(0x1p0), 0x1p0); - try std.testing.expectEqual(__sqrtx(0x1p0 + math.floatEps(f80)), 0x1p0); - try std.testing.expectEqual(__sqrtx(0x1p0 - math.floatEps(f80)), 0x1.FFFFFFFFFFFFFFFEp-1); + try std.testing.expectEqual(sqrt_f80(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f80(0x1p0 + math.floatEps(f80)), 0x1p0); + try std.testing.expectEqual(sqrt_f80(0x1p0 - math.floatEps(f80)), 0x1.FFFFFFFFFFFFFFFEp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(__sqrtx(math.floatMin(f80)), 0x1p-8191); + try std.testing.expectEqual(sqrt_f80(math.floatMin(f80)), 0x1p-8191); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(__sqrtx(math.floatTrueMin(f80)), 0x1.6A09E667F3BCC908p-8223); + try std.testing.expectEqual(sqrt_f80(math.floatTrueMin(f80)), 0x1.6A09E667F3BCC908p-8223); // sqrt(inf) is inf - try std.testing.expect(math.isInf(__sqrtx(math.inf(f80)))); + try std.testing.expect(math.isInf(sqrt_f80(math.inf(f80)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(__sqrtx(math.nan(f80)))); + try std.testing.expect(math.isNan(sqrt_f80(math.nan(f80)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(__sqrtx(-0x1p-16442))); - try std.testing.expect(math.isNan(__sqrtx(-0x1p0))); - try std.testing.expect(math.isNan(__sqrtx(-math.inf(f80)))); + try std.testing.expect(math.isNan(sqrt_f80(-0x1p-16442))); + try std.testing.expect(math.isNan(sqrt_f80(-0x1p0))); + try std.testing.expect(math.isNan(sqrt_f80(-math.inf(f80)))); // random arguments - try std.testing.expectEqual(__sqrtx(0x1.087F3953486918A4p15482), 0x1.0436BBE03D02F32p7741); - try std.testing.expectEqual(__sqrtx(0x1.530CF9E2AE84D8Fp-6330), 0x1.269CFEF51933BE58p-3165); - try std.testing.expectEqual(__sqrtx(0x1.3F971515EADD574Ap5713), 0x1.9483232AB780B006p2856); - try std.testing.expectEqual(__sqrtx(0x1.4CC0DC7379222954p864), 0x1.23DD4D0A4758C2Cp432); - try std.testing.expectEqual(__sqrtx(0x1.920E5649559A839Ep-3181), 0x1.C5B5BC0F98DD83D2p-1591); - try std.testing.expectEqual(__sqrtx(0x1.2E59726F87CD1746p-629), 0x1.8973327E95CB350Cp-315); - try std.testing.expectEqual(__sqrtx(0x1.D3A16391F57B4D64p-9034), 0x1.59FF08B7DEEF5DB2p-4517); - try std.testing.expectEqual(__sqrtx(0x1.E7053D8DAA49BCEEp-11411), 0x1.F35AA3EA5E18E344p-5706); - try std.testing.expectEqual(__sqrtx(0x1.797ED0B05DD4A984p7521), 0x1.B7A22E40C6A7867Ap3760); - try std.testing.expectEqual(__sqrtx(0x1.FC50806445C7226Ap15371), 0x1.FE2766142653F5BEp7685); + try std.testing.expectEqual(sqrt_f80(0x1.087F3953486918A4p15482), 0x1.0436BBE03D02F32p7741); + try std.testing.expectEqual(sqrt_f80(0x1.530CF9E2AE84D8Fp-6330), 0x1.269CFEF51933BE58p-3165); + try std.testing.expectEqual(sqrt_f80(0x1.3F971515EADD574Ap5713), 0x1.9483232AB780B006p2856); + try std.testing.expectEqual(sqrt_f80(0x1.4CC0DC7379222954p864), 0x1.23DD4D0A4758C2Cp432); + try std.testing.expectEqual(sqrt_f80(0x1.920E5649559A839Ep-3181), 0x1.C5B5BC0F98DD83D2p-1591); + try std.testing.expectEqual(sqrt_f80(0x1.2E59726F87CD1746p-629), 0x1.8973327E95CB350Cp-315); + try std.testing.expectEqual(sqrt_f80(0x1.D3A16391F57B4D64p-9034), 0x1.59FF08B7DEEF5DB2p-4517); + try std.testing.expectEqual(sqrt_f80(0x1.E7053D8DAA49BCEEp-11411), 0x1.F35AA3EA5E18E344p-5706); + try std.testing.expectEqual(sqrt_f80(0x1.797ED0B05DD4A984p7521), 0x1.B7A22E40C6A7867Ap3760); + try std.testing.expectEqual(sqrt_f80(0x1.FC50806445C7226Ap15371), 0x1.FE2766142653F5BEp7685); } -test "sqrtq" { +test "sqrt_f128" { // sqrt(±0) is ±0 - try std.testing.expectEqual(sqrtq(0x0.0p0), 0x0.0p0); - try std.testing.expectEqual(sqrtq(-0x0.0p0), -0x0.0p0); + try std.testing.expectEqual(sqrt_f128(0x0.0p0), 0x0.0p0); + try std.testing.expectEqual(sqrt_f128(-0x0.0p0), -0x0.0p0); // sqrt(+max) is finite - try std.testing.expectEqual(sqrtq(math.floatMax(f128)), 0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp8191); + try std.testing.expectEqual(sqrt_f128(math.floatMax(f128)), 0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp8191); // sqrt(4)=2 - try std.testing.expectEqual(sqrtq(0x1p2), 0x1p1); + try std.testing.expectEqual(sqrt_f128(0x1p2), 0x1p1); // sqrt(x) for x=1, 1±ulp - try std.testing.expectEqual(sqrtq(0x1p0), 0x1p0); - try std.testing.expectEqual(sqrtq(0x1p0 + math.floatEps(f128)), 0x1p0); - try std.testing.expectEqual(sqrtq(0x1p0 - math.floatEps(f128)), 0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp-1); + try std.testing.expectEqual(sqrt_f128(0x1p0), 0x1p0); + try std.testing.expectEqual(sqrt_f128(0x1p0 + math.floatEps(f128)), 0x1p0); + try std.testing.expectEqual(sqrt_f128(0x1p0 - math.floatEps(f128)), 0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp-1); // sqrt(+min) is non-zero - try std.testing.expectEqual(sqrtq(math.floatMin(f128)), 0x1p-8191); + try std.testing.expectEqual(sqrt_f128(math.floatMin(f128)), 0x1p-8191); // sqrt(min subnormal) is non-zero - try std.testing.expectEqual(sqrtq(math.floatTrueMin(f128)), 0x1p-8247); + try std.testing.expectEqual(sqrt_f128(math.floatTrueMin(f128)), 0x1p-8247); // sqrt(inf) is inf - try std.testing.expect(math.isInf(sqrtq(math.inf(f128)))); + try std.testing.expect(math.isInf(sqrt_f128(math.inf(f128)))); // sqrt(nan) is nan - try std.testing.expect(math.isNan(sqrtq(math.nan(f128)))); + try std.testing.expect(math.isNan(sqrt_f128(math.nan(f128)))); // sqrt(-ve) is nan - try std.testing.expect(math.isNan(sqrtq(-0x1p-16442))); - try std.testing.expect(math.isNan(sqrtq(-0x1p0))); - try std.testing.expect(math.isNan(sqrtq(-math.inf(f128)))); + try std.testing.expect(math.isNan(sqrt_f128(-0x1p-16442))); + try std.testing.expect(math.isNan(sqrt_f128(-0x1p0))); + try std.testing.expect(math.isNan(sqrt_f128(-math.inf(f128)))); // random arguments - try std.testing.expectEqual(sqrtq(0x1.B6942D29A331751600C9F3AF7E5Fp3363), 0x1.D9DE9AFEF0F2D25586A50CA39D4Dp1681); - try std.testing.expectEqual(sqrtq(0x1.5E65C405F84D471A8070ADD7A42Dp11765), 0x1.A78F7F9452B4D9EC2403C81D9D42p5882); - try std.testing.expectEqual(sqrtq(0x1.B42334D68F8016D8AE6F5E22B044p-5624), 0x1.4E247A7F2FF2A325E9377BB09C8p-2812); - try std.testing.expectEqual(sqrtq(0x1.E61715047F80F2E0B9382B38E06Bp10062), 0x1.60C25D9DFDC0116B78EF5AFDE0E9p5031); - try std.testing.expectEqual(sqrtq(0x1.2ED0B53B494CB55A7B04E653D40Ep-1026), 0x1.166CE78D658D2453D700B04C5748p-513); - try std.testing.expectEqual(sqrtq(0x1.1BA756B9790E78A4E6F0B083AA89p1835), 0x1.7D1767EA3303DB7A46940033988p917); - try std.testing.expectEqual(sqrtq(0x1.5B6C574319C1120335C8E1609704p4512), 0x1.2A3A8A415BB1648C548FBA2A4182p2256); - try std.testing.expectEqual(sqrtq(0x1.FF91E8CDEE1552A2B74E77B602Ep14953), 0x1.FFC8F171267D4FE75CBE7AB4D851p7476); - try std.testing.expectEqual(sqrtq(0x1.9B1837CFC629A1B6B1BB97099E7Dp2892), 0x1.4468511B909EAF8641BD59105A6Bp1446); - try std.testing.expectEqual(sqrtq(0x1.0E2115475E64A92340914E7F7B37p-13951), 0x1.73E536F82F414134012F55BA5368p-6976); + try std.testing.expectEqual(sqrt_f128(0x1.B6942D29A331751600C9F3AF7E5Fp3363), 0x1.D9DE9AFEF0F2D25586A50CA39D4Dp1681); + try std.testing.expectEqual(sqrt_f128(0x1.5E65C405F84D471A8070ADD7A42Dp11765), 0x1.A78F7F9452B4D9EC2403C81D9D42p5882); + try std.testing.expectEqual(sqrt_f128(0x1.B42334D68F8016D8AE6F5E22B044p-5624), 0x1.4E247A7F2FF2A325E9377BB09C8p-2812); + try std.testing.expectEqual(sqrt_f128(0x1.E61715047F80F2E0B9382B38E06Bp10062), 0x1.60C25D9DFDC0116B78EF5AFDE0E9p5031); + try std.testing.expectEqual(sqrt_f128(0x1.2ED0B53B494CB55A7B04E653D40Ep-1026), 0x1.166CE78D658D2453D700B04C5748p-513); + try std.testing.expectEqual(sqrt_f128(0x1.1BA756B9790E78A4E6F0B083AA89p1835), 0x1.7D1767EA3303DB7A46940033988p917); + try std.testing.expectEqual(sqrt_f128(0x1.5B6C574319C1120335C8E1609704p4512), 0x1.2A3A8A415BB1648C548FBA2A4182p2256); + try std.testing.expectEqual(sqrt_f128(0x1.FF91E8CDEE1552A2B74E77B602Ep14953), 0x1.FFC8F171267D4FE75CBE7AB4D851p7476); + try std.testing.expectEqual(sqrt_f128(0x1.9B1837CFC629A1B6B1BB97099E7Dp2892), 0x1.4468511B909EAF8641BD59105A6Bp1446); + try std.testing.expectEqual(sqrt_f128(0x1.0E2115475E64A92340914E7F7B37p-13951), 0x1.73E536F82F414134012F55BA5368p-6976); } diff --git a/lib/compiler_rt/ssp.zig b/lib/compiler_rt/ssp.zig index 42d088eeb8ab714b4b3d9ac79e579634ffff11a3..20468b0c0de8eb23cc9dff83c3e1bcbf46417f57 100644 --- a/lib/compiler_rt/ssp.zig +++ b/lib/compiler_rt/ssp.zig @@ -17,7 +17,7 @@ const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; const builtin = @import("builtin"); -extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.c) ?[*]u8; +extern fn memset(dest: ?[*]u8, c: c_int, n: usize) callconv(.c) ?[*]u8; extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8; extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.c) ?[*]u8; @@ -138,7 +138,7 @@ fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callc return memmove(dest, src, n); } -fn __memset_chk(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.c) ?[*]u8 { +fn __memset_chk(dest: ?[*]u8, c: c_int, n: usize, dest_n: usize) callconv(.c) ?[*]u8 { if (dest_n < n) __chk_fail(); return memset(dest, c, n); } diff --git a/lib/compiler_rt/subdf3.zig b/lib/compiler_rt/subdf3.zig deleted file mode 100644 index 4d00a7f03ae71c4f9bf2ffecbcd1123216dff6b6..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subdf3.zig +++ /dev/null @@ -1,24 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const addf3 = @import("./addf3.zig").addf3; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dsub, "__aeabi_dsub"); - } else { - symbol(&__subdf3, "__subdf3"); - } -} - -fn __subdf3(a: f64, b: f64) callconv(.c) f64 { - return sub(a, b); -} - -fn __aeabi_dsub(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) f64 { - return sub(a, b); -} - -inline fn sub(a: f64, b: f64) f64 { - const neg_b = @as(f64, @bitCast(@as(u64, @bitCast(b)) ^ (@as(u64, 1) << 63))); - return addf3(f64, a, neg_b); -} diff --git a/lib/compiler_rt/subhf3.zig b/lib/compiler_rt/subhf3.zig deleted file mode 100644 index 258401d2957a6d3aafcd0aa02c6de63ca0211952..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subhf3.zig +++ /dev/null @@ -1,12 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - symbol(&__subhf3, "__subhf3"); -} - -fn __subhf3(a: f16, b: f16) callconv(.c) f16 { - const neg_b = @as(f16, @bitCast(@as(u16, @bitCast(b)) ^ (@as(u16, 1) << 15))); - return addf3(f16, a, neg_b); -} diff --git a/lib/compiler_rt/subsf3.zig b/lib/compiler_rt/subsf3.zig deleted file mode 100644 index 94d47220166aff38656455d3f50fa2b061df3f61..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subsf3.zig +++ /dev/null @@ -1,24 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_fsub, "__aeabi_fsub"); - } else { - symbol(&__subsf3, "__subsf3"); - } -} - -fn __subsf3(a: f32, b: f32) callconv(.c) f32 { - return sub(a, b); -} - -fn __aeabi_fsub(a: f32, b: f32) callconv(.{ .arm_aapcs = .{} }) f32 { - return sub(a, b); -} - -inline fn sub(a: f32, b: f32) f32 { - const neg_b = @as(f32, @bitCast(@as(u32, @bitCast(b)) ^ (@as(u32, 1) << 31))); - return addf3(f32, a, neg_b); -} diff --git a/lib/compiler_rt/subtf3.zig b/lib/compiler_rt/subtf3.zig deleted file mode 100644 index 46580f1728d70b85c83259dce39cb860e46ac10e..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subtf3.zig +++ /dev/null @@ -1,27 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const addf3 = @import("./addf3.zig").addf3; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__subtf3, "__subkf3"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_sub, "_Qp_sub"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__subtf3, "_Q_sub"); - } - symbol(&__subtf3, "__subtf3"); -} - -pub fn __subtf3(a: f128, b: f128) callconv(.c) f128 { - return sub(a, b); -} - -fn _Qp_sub(c: *f128, a: *const f128, b: *const f128) callconv(.c) void { - c.* = sub(a.*, b.*); -} - -inline fn sub(a: f128, b: f128) f128 { - const neg_b = @as(f128, @bitCast(@as(u128, @bitCast(b)) ^ (@as(u128, 1) << 127))); - return addf3(f128, a, neg_b); -} diff --git a/lib/compiler_rt/subvdi3.zig b/lib/compiler_rt/subvdi3.zig index 62bb1b406835c1a72588cd9c1d08705f6663bbd2..2fedc77ee2c07fe42ded5f5da11191a41fc17a0f 100644 --- a/lib/compiler_rt/subvdi3.zig +++ b/lib/compiler_rt/subvdi3.zig @@ -1,5 +1,6 @@ -const symbol = @import("../compiler_rt.zig").symbol; const testing = @import("std").testing; +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; comptime { symbol(&__subvdi3, "__subvdi3"); @@ -9,7 +10,7 @@ pub fn __subvdi3(a: i64, b: i64) callconv(.c) i64 { const sum = a -% b; // Overflow occurred iff the operands have opposite signs, and the sign of the // sum is the opposite of the lhs sign. - if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); + if (((a ^ b) & (sum ^ a)) < 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/subvsi3.zig b/lib/compiler_rt/subvsi3.zig index 0744585770237d034f35947a927155efe23eaef9..0d2a47e7cbfa8beb25cbeedc1809e549481db97e 100644 --- a/lib/compiler_rt/subvsi3.zig +++ b/lib/compiler_rt/subvsi3.zig @@ -10,7 +10,7 @@ pub fn __subvsi3(a: i32, b: i32) callconv(.c) i32 { const sum = a -% b; // Overflow occurred iff the operands have opposite signs, and the sign of the // sum is the opposite of the lhs sign. - if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); + if (((a ^ b) & (sum ^ a)) < 0) @panic("integer overflow"); return sum; } diff --git a/lib/compiler_rt/subxf3.zig b/lib/compiler_rt/subxf3.zig deleted file mode 100644 index 1c2dcd65429596c975937432aae6eaefb89c2f72..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/subxf3.zig +++ /dev/null @@ -1,13 +0,0 @@ -const std = @import("std"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__subxf3, "__subxf3"); -} - -fn __subxf3(a: f80, b: f80) callconv(.c) f80 { - var b_rep = std.math.F80.fromFloat(b); - b_rep.exp ^= 0x8000; - const neg_b = b_rep.toFloat(); - return a + neg_b; -} diff --git a/lib/compiler_rt/tan.zig b/lib/compiler_rt/tan.zig index 6cbc3cb098acd1f6a719451d103574b935a8bb2c..4ee4440dd6c5cd7417842de27084cab36ae85907 100644 --- a/lib/compiler_rt/tan.zig +++ b/lib/compiler_rt/tan.zig @@ -21,26 +21,29 @@ const rem_pio2l = @import("rem_pio2l.zig").rem_pio2l; const arch = builtin.cpu.arch; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; comptime { - symbol(&tanh, "__tanh"); + symbol(&__tanh, "__tanh"); symbol(&tanf, "tanf"); symbol(&tan, "tan"); - symbol(&tanx, "__tanx"); - if (compiler_rt.want_ppc_abi) { - symbol(&tanq, "tanf128"); - } - symbol(&tanq, "tanq"); + symbol(&__tanx, "__tanx"); + symbol(&tanq, "tanf128"); symbol(&tanl, "tanl"); } -pub fn tanh(x: f16) callconv(.c) f16 { +fn __tanh(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(tan_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn tan_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(tanf(x)); + return @floatCast(tan_f32(x)); } -pub fn tanf(x: f32) callconv(.c) f32 { +fn tanf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(tan_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn tan_f32(x: f32) f32 { // Small multiples of pi/2 rounded to double precision. const t1pio2: f64 = 1.0 * math.pi / 2.0; // 0x3FF921FB, 0x54442D18 const t2pio2: f64 = 2.0 * math.pi / 2.0; // 0x400921FB, 0x54442D18 @@ -90,7 +93,10 @@ pub fn tanf(x: f32) callconv(.c) f32 { return kernel.tandf(y, n & 1 != 0); } -pub fn tan(x: f64) callconv(.c) f64 { +fn tan(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(tan_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn tan_f64(x: f64) f64 { var ix = @as(u64, @bitCast(x)) >> 32; ix &= 0x7fffffff; @@ -120,7 +126,10 @@ pub fn tan(x: f64) callconv(.c) f64 { return kernel.tan(y[0], y[1], n & 1 != 0); } -pub fn tanx(x: f80) callconv(.c) f80 { +fn __tanx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(tan_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn tan_f80(x: f80) f80 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -141,7 +150,10 @@ pub fn tanx(x: f80) callconv(.c) f80 { return kernel.tanx(y[0], y[1], n & 1); } -pub fn tanq(x: f128) callconv(.c) f128 { +fn tanq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(tan_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn tan_f128(x: f128) f128 { const se = ld.signExponent(x) & 0x7fff; if (se == 0x7fff) { return x - x; @@ -164,18 +176,21 @@ pub fn tanq(x: f128) callconv(.c) f128 { pub fn tanl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return tan(x), - 80 => return tanx(x), - 128 => return tanq(x), - else => @compileError("unreachable"), + 64 => return tan_f64(x), + 80 => return tan_f80(x), + 128 => return tan_f128(x), + else => comptime unreachable, } } fn testTanNormal(comptime T: type) !void { const f = switch (T) { - f32 => tanf, - f64 => tan, - else => @compileError("unimplemented"), + f16 => tan_f16, + f32 => tan_f32, + f64 => tan_f64, + f80 => tan_f80, + f128 => tan_f128, + else => comptime unreachable, }; const epsilon = 0.00001; @@ -189,11 +204,12 @@ fn testTanNormal(comptime T: type) !void { fn testTanSpecial(comptime T: type) !void { const f = switch (T) { - f32 => tanf, - f64 => tan, - f80 => tanx, - f128 => tanq, - else => @compileError("unimplemented"), + f16 => tan_f16, + f32 => tan_f32, + f64 => tan_f64, + f80 => tan_f80, + f128 => tan_f128, + else => comptime unreachable, }; try expect(math.isPositiveZero(f(0.0))); @@ -214,23 +230,23 @@ test "tan64.normal" { test "tan80.normal" { const epsilon = math.floatEps(f80); - try expectApproxEqAbs(@as(f80, 0.0), tanx(0.0), epsilon); - try expectApproxEqAbs(@as(f80, 0.2027100355086724833213582716475345), tanx(0.2), epsilon); - try expectApproxEqAbs(@as(f80, 1.2404217445497097995561220131857544), tanx(0.8923), epsilon); - try expectApproxEqAbs(@as(f80, 14.10141994717171938764), tanx(1.5), epsilon); - try expectApproxEqAbs(@as(f80, -0.25439607116885656232), tanx(37.45), epsilon); - try expectApproxEqAbs(@as(f80, 2.2858376251355320963), tanx(89.123), epsilon); + try expectApproxEqAbs(@as(f80, 0.0), tan_f80(0.0), epsilon); + try expectApproxEqAbs(@as(f80, 0.2027100355086724833213582716475345), tan_f80(0.2), epsilon); + try expectApproxEqAbs(@as(f80, 1.2404217445497097995561220131857544), tan_f80(0.8923), epsilon); + try expectApproxEqAbs(@as(f80, 14.10141994717171938764), tan_f80(1.5), epsilon); + try expectApproxEqAbs(@as(f80, -0.25439607116885656232), tan_f80(37.45), epsilon); + try expectApproxEqAbs(@as(f80, 2.2858376251355320963), tan_f80(89.123), epsilon); } test "tan128.normal" { const epsilon = math.floatEps(f128); - try expectApproxEqAbs(@as(f128, 0.0), tanq(0.0), epsilon); - try expectApproxEqAbs(@as(f128, 0.2027100355086724833213582716475345), tanq(0.2), epsilon); - try expectApproxEqAbs(@as(f128, 1.2404217445497097995561220131857544), tanq(0.8923), epsilon); - try expectApproxEqAbs(@as(f128, 14.101419947171719387646083651987755), tanq(1.5), epsilon); - try expectApproxEqAbs(@as(f128, -0.2543960711688565630469573224504774), tanq(37.45), epsilon); - try expectApproxEqAbs(@as(f128, 2.2858376251355321074066028114094292), tanq(89.123), epsilon); + try expectApproxEqAbs(@as(f128, 0.0), tan_f128(0.0), epsilon); + try expectApproxEqAbs(@as(f128, 0.2027100355086724833213582716475345), tan_f128(0.2), epsilon); + try expectApproxEqAbs(@as(f128, 1.2404217445497097995561220131857544), tan_f128(0.8923), epsilon); + try expectApproxEqAbs(@as(f128, 14.101419947171719387646083651987755), tan_f128(1.5), epsilon); + try expectApproxEqAbs(@as(f128, -0.2543960711688565630469573224504774), tan_f128(37.45), epsilon); + try expectApproxEqAbs(@as(f128, 2.2858376251355321074066028114094292), tan_f128(89.123), epsilon); } test "tan32.special" { diff --git a/lib/compiler_rt/trunc.zig b/lib/compiler_rt/trunc.zig index aa2eb560dfd8035f14aa07c8e51c5c117daad042..0dbacf0e9d822385a8dc558a29bf0401f6d97e21 100644 --- a/lib/compiler_rt/trunc.zig +++ b/lib/compiler_rt/trunc.zig @@ -17,19 +17,22 @@ comptime { symbol(&truncf, "truncf"); symbol(&trunc, "trunc"); symbol(&__truncx, "__truncx"); - if (compiler_rt.want_ppc_abi) { - symbol(&truncq, "truncf128"); - } - symbol(&truncq, "truncq"); + symbol(&truncq, "truncf128"); symbol(&truncl, "truncl"); } -pub fn __trunch(x: f16) callconv(.c) f16 { +fn __trunch(x: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { + return compiler_rt.f16.toAbi(trunc_f16(compiler_rt.f16.fromAbi(x))); +} +pub fn trunc_f16(x: f16) f16 { // TODO: more efficient implementation - return @floatCast(truncf(x)); + return @floatCast(trunc_f32(x)); } -pub fn truncf(x: f32) callconv(.c) f32 { +fn truncf(x: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(trunc_f32(compiler_rt.f32.fromAbi(x))); +} +pub fn trunc_f32(x: f32) f32 { const u: u32 = @bitCast(x); var e = @as(i32, @intCast(((u >> 23) & 0xFF))) - 0x7F + 9; var m: u32 = undefined; @@ -50,7 +53,10 @@ pub fn truncf(x: f32) callconv(.c) f32 { } } -pub fn trunc(x: f64) callconv(.c) f64 { +fn trunc(x: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(trunc_f64(compiler_rt.f64.fromAbi(x))); +} +pub fn trunc_f64(x: f64) f64 { const u: u64 = @bitCast(x); var e = @as(i32, @intCast(((u >> 52) & 0x7FF))) - 0x3FF + 12; var m: u64 = undefined; @@ -71,12 +77,18 @@ pub fn trunc(x: f64) callconv(.c) f64 { } } -pub fn __truncx(x: f80) callconv(.c) f80 { +fn __truncx(x: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(trunc_f80(compiler_rt.f80.fromAbi(x))); +} +pub fn trunc_f80(x: f80) f80 { // TODO: more efficient implementation - return @floatCast(truncq(x)); + return @floatCast(trunc_f128(x)); } -pub fn truncq(x: f128) callconv(.c) f128 { +fn truncq(x: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { + return compiler_rt.f128.toAbi(trunc_f128(compiler_rt.f128.fromAbi(x))); +} +pub fn trunc_f128(x: f128) f128 { const u: u128 = @bitCast(x); var e = @as(i32, @intCast(((u >> 112) & 0x7FFF))) - 0x3FFF + 16; var m: u128 = undefined; @@ -99,51 +111,69 @@ pub fn truncq(x: f128) callconv(.c) f128 { pub fn truncl(x: c_longdouble) callconv(.c) c_longdouble { switch (@typeInfo(c_longdouble).float.bits) { - 64 => return trunc(x), - 80 => return __truncx(x), - 128 => return truncq(x), - else => @compileError("unreachable"), + 64 => return trunc_f64(x), + 80 => return trunc_f80(x), + 128 => return trunc_f128(x), + else => comptime unreachable, } } -test "trunc32" { - try expect(truncf(1.3) == 1.0); - try expect(truncf(-1.3) == -1.0); - try expect(truncf(0.2) == 0.0); +test trunc_f16 { + try expect(trunc_f16(1.3) == 1.0); + try expect(trunc_f16(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f16(0.2))); + try expect(math.isNegativeZero(trunc_f16(-0.2))); + try expect(math.isPositiveZero(trunc_f16(0.0))); + try expect(math.isNegativeZero(trunc_f16(-0.0))); + try expect(math.isPositiveInf(trunc_f16(math.inf(f32)))); + try expect(math.isNegativeInf(trunc_f16(-math.inf(f32)))); + try expect(math.isNan(trunc_f16(math.nan(f32)))); } -test "trunc64" { - try expect(trunc(1.3) == 1.0); - try expect(trunc(-1.3) == -1.0); - try expect(trunc(0.2) == 0.0); +test trunc_f32 { + try expect(trunc_f32(1.3) == 1.0); + try expect(trunc_f32(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f32(0.2))); + try expect(math.isNegativeZero(trunc_f32(-0.2))); + try expect(math.isPositiveZero(trunc_f32(0.0))); + try expect(math.isNegativeZero(trunc_f32(-0.0))); + try expect(math.isPositiveInf(trunc_f32(math.inf(f32)))); + try expect(math.isNegativeInf(trunc_f32(-math.inf(f32)))); + try expect(math.isNan(trunc_f32(math.nan(f32)))); } -test "trunc128" { - try expect(truncq(1.3) == 1.0); - try expect(truncq(-1.3) == -1.0); - try expect(truncq(0.2) == 0.0); +test trunc_f64 { + try expect(trunc_f64(1.3) == 1.0); + try expect(trunc_f64(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f64(0.2))); + try expect(math.isNegativeZero(trunc_f64(-0.2))); + try expect(math.isPositiveZero(trunc_f64(0.0))); + try expect(math.isNegativeZero(trunc_f64(-0.0))); + try expect(math.isPositiveInf(trunc_f64(math.inf(f64)))); + try expect(math.isNegativeInf(trunc_f64(-math.inf(f64)))); + try expect(math.isNan(trunc_f64(math.nan(f64)))); } -test "trunc32.special" { - try expect(truncf(0.0) == 0.0); // 0x3F800000 - try expect(truncf(-0.0) == -0.0); - try expect(math.isPositiveInf(truncf(math.inf(f32)))); - try expect(math.isNegativeInf(truncf(-math.inf(f32)))); - try expect(math.isNan(truncf(math.nan(f32)))); +test trunc_f80 { + try expect(trunc_f80(1.3) == 1.0); + try expect(trunc_f80(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f80(0.2))); + try expect(math.isNegativeZero(trunc_f80(-0.2))); + try expect(math.isPositiveZero(trunc_f80(0.0))); + try expect(math.isNegativeZero(trunc_f80(-0.0))); + try expect(math.isPositiveInf(trunc_f80(math.inf(f64)))); + try expect(math.isNegativeInf(trunc_f80(-math.inf(f64)))); + try expect(math.isNan(trunc_f80(math.nan(f64)))); } -test "trunc64.special" { - try expect(trunc(0.0) == 0.0); - try expect(trunc(-0.0) == -0.0); - try expect(math.isPositiveInf(trunc(math.inf(f64)))); - try expect(math.isNegativeInf(trunc(-math.inf(f64)))); - try expect(math.isNan(trunc(math.nan(f64)))); -} - -test "trunc128.special" { - try expect(truncq(0.0) == 0.0); - try expect(truncq(-0.0) == -0.0); - try expect(math.isPositiveInf(truncq(math.inf(f128)))); - try expect(math.isNegativeInf(truncq(-math.inf(f128)))); - try expect(math.isNan(truncq(math.nan(f128)))); +test trunc_f128 { + try expect(trunc_f128(1.3) == 1.0); + try expect(trunc_f128(-1.3) == -1.0); + try expect(math.isPositiveZero(trunc_f128(0.2))); + try expect(math.isNegativeZero(trunc_f128(-0.2))); + try expect(math.isPositiveZero(trunc_f128(0.0))); + try expect(math.isNegativeZero(trunc_f128(-0.0))); + try expect(math.isPositiveInf(trunc_f128(math.inf(f128)))); + try expect(math.isNegativeInf(trunc_f128(-math.inf(f128)))); + try expect(math.isNan(trunc_f128(math.nan(f128)))); } diff --git a/lib/compiler_rt/truncdfhf2.zig b/lib/compiler_rt/truncdfhf2.zig deleted file mode 100644 index e01e1877633eee7077c64ef42e6cde56a0a17aee..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncdfhf2.zig +++ /dev/null @@ -1,18 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const truncf = @import("./truncf.zig").truncf; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2h, "__aeabi_d2h"); - } - symbol(&__truncdfhf2, "__truncdfhf2"); -} - -pub fn __truncdfhf2(a: f64) callconv(.c) compiler_rt.F16T(f64) { - return @bitCast(truncf(f16, f64, a)); -} - -fn __aeabi_d2h(a: f64) callconv(.{ .arm_aapcs = .{} }) u16 { - return @bitCast(truncf(f16, f64, a)); -} diff --git a/lib/compiler_rt/truncdfsf2.zig b/lib/compiler_rt/truncdfsf2.zig deleted file mode 100644 index f1bada18449130344f213ad0f8272794d38f23bf..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncdfsf2.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const truncf = @import("./truncf.zig").truncf; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_d2f, "__aeabi_d2f"); - } else { - symbol(&__truncdfsf2, "__truncdfsf2"); - } -} - -pub fn __truncdfsf2(a: f64) callconv(.c) f32 { - return truncf(f32, f64, a); -} - -fn __aeabi_d2f(a: f64) callconv(.{ .arm_aapcs = .{} }) f32 { - return truncf(f32, f64, a); -} diff --git a/lib/compiler_rt/truncf.zig b/lib/compiler_rt/truncf.zig index a03f3b67113028ba8a69c4fc72023b9d26f87e23..9a1cb491e27bc214a2c5c7a4a91f8f236efae1ef 100644 --- a/lib/compiler_rt/truncf.zig +++ b/lib/compiler_rt/truncf.zig @@ -1,6 +1,204 @@ const std = @import("std"); -pub inline fn truncf(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + if (compiler_rt.want_aeabi) { + if (compiler_rt.gnu_f16_abi) { + symbol(&__aeabi_f2h, "__gnu_f2h_ieee"); + } else { + symbol(&__aeabi_f2h, "__aeabi_f2h"); + } + symbol(&__aeabi_d2h, "__aeabi_d2h"); + } else if (compiler_rt.gnu_f16_abi) { + symbol(&__truncsfhf2, "__gnu_f2h_ieee"); + } + symbol(&__truncsfhf2, "__truncsfhf2"); + symbol(&__truncdfhf2, "__truncdfhf2"); + symbol(&__truncxfhf2, "__truncxfhf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__trunctfhf2, "__trunckfhf2"); + } else { + symbol(&__trunctfhf2, "__trunctfhf2"); + } + + if (compiler_rt.want_aeabi) { + symbol(&__aeabi_d2f, "__aeabi_d2f"); + } else { + symbol(&__truncdfsf2, "__truncdfsf2"); + } + symbol(&__truncxfsf2, "__truncxfsf2"); + if (compiler_rt.want_ppc_abi) { + symbol(&__trunctfsf2, "__trunckfsf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_qtos, "_Qp_qtos"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__trunctfsf2, "_Q_qtos"); + } else { + symbol(&__trunctfsf2, "__trunctfsf2"); + } + + symbol(&__truncxfdf2, "__truncxfdf2"); + + if (compiler_rt.want_ppc_abi) { + symbol(&__trunctfdf2, "__trunckfdf2"); + } else if (compiler_rt.want_sparc64_abi) { + symbol(&_Qp_qtod, "_Qp_qtod"); + } else if (compiler_rt.want_sparc32_abi) { + symbol(&__trunctfdf2, "_Q_qtod"); + } else { + symbol(&__trunctfdf2, "__trunctfdf2"); + } + + if (compiler_rt.want_ppc_abi) { + symbol(&__trunctfxf2, "__trunckfxf2"); + } else { + symbol(&__trunctfxf2, "__trunctfxf2"); + } +} + +fn __truncsfhf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f16Conv(f32).Abi { + return compiler_rt.f16Conv(f32).toAbi(f16_floatCast_f32(compiler_rt.f32.fromAbi(a))); +} +fn __aeabi_f2h(a: u32) callconv(.{ .arm_aapcs = .{} }) u16 { + return @bitCast(f16_floatCast_f32(@bitCast(a))); +} +pub fn f16_floatCast_f32(a: f32) f16 { + return truncf(f16, f32, a); +} + +fn __truncdfhf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f16Conv(f64).Abi { + return compiler_rt.f16Conv(f64).toAbi(f16_floatCast_f64(compiler_rt.f64.fromAbi(a))); +} +fn __aeabi_d2h(a: u64) callconv(.{ .arm_aapcs = .{} }) u16 { + return @bitCast(f16_floatCast_f64(@bitCast(a))); +} +pub fn f16_floatCast_f64(a: f64) f16 { + return truncf(f16, f64, a); +} + +fn __truncxfhf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f16Conv(f80).Abi { + return compiler_rt.f16Conv(f80).toAbi(f16_floatCast_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn f16_floatCast_f80(a: f80) f16 { + return trunc_f80(f16, a); +} + +fn __trunctfhf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f16Conv(f128).Abi { + return compiler_rt.f16Conv(f128).toAbi(f16_floatCast_f128(compiler_rt.f128.fromAbi(a))); +} +pub fn f16_floatCast_f128(a: f128) f16 { + return truncf(f16, f128, a); +} + +fn __truncdfsf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatCast_f64(compiler_rt.f64.fromAbi(a))); +} +fn __aeabi_d2f(a: f64) callconv(.{ .arm_aapcs = .{} }) f32 { + return f32_floatCast_f64(a); +} +pub fn f32_floatCast_f64(a: f64) f32 { + return truncf(f32, f64, a); +} + +fn __truncxfsf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatCast_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn f32_floatCast_f80(a: f80) f32 { + return trunc_f80(f32, a); +} + +fn __trunctfsf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f32.Abi { + return compiler_rt.f32.toAbi(f32_floatCast_f128(compiler_rt.f128.fromAbi(a))); +} +fn _Qp_qtos(a: *const f128) callconv(.c) f32 { + return f32_floatCast_f128(a.*); +} +pub fn f32_floatCast_f128(a: f128) f32 { + return truncf(f32, f128, a); +} + +fn __truncxfdf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatCast_f80(compiler_rt.f80.fromAbi(a))); +} +pub fn f64_floatCast_f80(a: f80) f64 { + return trunc_f80(f64, a); +} + +fn __trunctfdf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f64.Abi { + return compiler_rt.f64.toAbi(f64_floatCast_f128(compiler_rt.f128.fromAbi(a))); +} +fn _Qp_qtod(a: *const f128) callconv(.c) f64 { + return f64_floatCast_f128(a.*); +} +pub fn f64_floatCast_f128(a: f128) f64 { + return truncf(f64, f128, a); +} + +fn __trunctfxf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f80.Abi { + return compiler_rt.f80.toAbi(f80_floatCast_f128(compiler_rt.f128.fromAbi(a))); +} +pub fn f80_floatCast_f128(a: f128) f80 { + const src_sig_bits = std.math.floatMantissaBits(f128); + const dst_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const src_bits = @typeInfo(f128).float.bits; + const src_exp_bits = src_bits - src_sig_bits - 1; + const src_inf_exp = 0x7FFF; + + const src_inf = src_inf_exp << src_sig_bits; + const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); + const src_abs_mask = src_sign_mask - 1; + const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; + const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); + + // Break a into a sign and representation of the absolute value + const a_rep: u128 = @bitCast(a); + const a_abs = a_rep & src_abs_mask; + const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0; + const integer_bit = 1 << 63; + + var res: std.math.F80 = undefined; + + if (a_abs > src_inf) { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + res.exp = 0x7fff; + res.fraction = 0x8000000000000000; + res.fraction |= @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))); + } else { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding, adding the explicit integer bit, and adjusting the exponent + res.fraction = @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))) | integer_bit; + res.exp = @truncate(a_abs >> src_sig_bits); + + const round_bits = a_abs & round_mask; + if (round_bits > halfway) { + // Round to nearest + const ov = @addWithOverflow(res.fraction, 1); + res.fraction = ov[0]; + res.exp += ov[1]; + res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry + } else if (round_bits == halfway) { + // Ties to even + const ov = @addWithOverflow(res.fraction, res.fraction & 1); + res.fraction = ov[0]; + res.exp += ov[1]; + res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry + } + if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals + } + + res.exp |= sign; + return res.toFloat(); +} + +inline fn truncf(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { const src_rep_t = @Int(.unsigned, @typeInfo(src_t).float.bits); const dst_rep_t = @Int(.unsigned, @typeInfo(dst_t).float.bits); const srcSigBits = std.math.floatMantissaBits(src_t); @@ -99,7 +297,7 @@ pub inline fn truncf(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t return @bitCast(result); } -pub inline fn trunc_f80(comptime dst_t: type, a: f80) dst_t { +inline fn trunc_f80(comptime dst_t: type, a: f80) dst_t { const dst_rep_t = @Int(.unsigned, @typeInfo(dst_t).float.bits); const src_sig_bits = std.math.floatMantissaBits(f80) - 1; // -1 for the integer bit const dst_sig_bits = std.math.floatMantissaBits(dst_t); diff --git a/lib/compiler_rt/truncf_test.zig b/lib/compiler_rt/truncf_test.zig index 8da6fe0a19456e9898f32ea4dec4c7b8ccb221b4..6595c47b52d8f868d019c1728ae3d57735e12323 100644 --- a/lib/compiler_rt/truncf_test.zig +++ b/lib/compiler_rt/truncf_test.zig @@ -1,79 +1,82 @@ const std = @import("std"); const testing = std.testing; -const __truncsfhf2 = @import("truncsfhf2.zig").__truncsfhf2; -const __truncdfhf2 = @import("truncdfhf2.zig").__truncdfhf2; -const __truncdfsf2 = @import("truncdfsf2.zig").__truncdfsf2; -const __trunctfhf2 = @import("trunctfhf2.zig").__trunctfhf2; -const __trunctfsf2 = @import("trunctfsf2.zig").__trunctfsf2; -const __trunctfdf2 = @import("trunctfdf2.zig").__trunctfdf2; -const __trunctfxf2 = @import("trunctfxf2.zig").__trunctfxf2; - -fn test__truncsfhf2(a: u32, expected: u16) !void { - const actual: u16 = @bitCast(__truncsfhf2(@bitCast(a))); - - if (actual == expected) { - return; - } - - return error.TestFailure; +const impl = @import("truncf.zig"); + +const f16_floatCast_f32 = impl.f16_floatCast_f32; +const f16_floatCast_f64 = impl.f16_floatCast_f64; +const f16_floatCast_f80 = impl.f16_floatCast_f80; +const f16_floatCast_f128 = impl.f16_floatCast_f128; + +const f32_floatCast_f64 = impl.f32_floatCast_f64; +const f32_floatCast_f80 = impl.f32_floatCast_f80; +const f32_floatCast_f128 = impl.f32_floatCast_f128; + +const f64_floatCast_f80 = impl.f64_floatCast_f80; +const f64_floatCast_f128 = impl.f64_floatCast_f128; + +const f80_floatCast_f128 = impl.f80_floatCast_f128; + +fn test_f16_floatCast_f32(a: u32, expected: u16) !void { + const actual: u16 = @bitCast(f16_floatCast_f32(@bitCast(a))); + try testing.expect(actual == expected); } -test "truncsfhf2" { - try test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN - try test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN +test f16_floatCast_f32 { + try test_f16_floatCast_f32(0x7fc00000, 0x7e00); // qNaN + try test_f16_floatCast_f32(0x7fe00000, 0x7f00); // sNaN - try test__truncsfhf2(0, 0); // 0 - try test__truncsfhf2(0x80000000, 0x8000); // -0 + try test_f16_floatCast_f32(0, 0); // 0 + try test_f16_floatCast_f32(0x80000000, 0x8000); // -0 - try test__truncsfhf2(0x7f800000, 0x7c00); // inf - try test__truncsfhf2(0xff800000, 0xfc00); // -inf + try test_f16_floatCast_f32(0x7f800000, 0x7c00); // inf + try test_f16_floatCast_f32(0xff800000, 0xfc00); // -inf - try test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf - try test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf + try test_f16_floatCast_f32(0x477ff000, 0x7c00); // 65520 -> inf + try test_f16_floatCast_f32(0xc77ff000, 0xfc00); // -65520 -> -inf - try test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf - try test__truncsfhf2(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf + try test_f16_floatCast_f32(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf + try test_f16_floatCast_f32(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf - try test__truncsfhf2(0x38800000, 0x0400); // normal (min), 2**-14 - try test__truncsfhf2(0xb8800000, 0x8400); // normal (min), -2**-14 + try test_f16_floatCast_f32(0x38800000, 0x0400); // normal (min), 2**-14 + try test_f16_floatCast_f32(0xb8800000, 0x8400); // normal (min), -2**-14 - try test__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504 - try test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504 + try test_f16_floatCast_f32(0x477fe000, 0x7bff); // normal (max), 65504 + try test_f16_floatCast_f32(0xc77fe000, 0xfbff); // normal (max), -65504 - try test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504 - try test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 + try test_f16_floatCast_f32(0x477fe100, 0x7bff); // normal, 65505 -> 65504 + try test_f16_floatCast_f32(0xc77fe100, 0xfbff); // normal, -65505 -> -65504 - try test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504 - try test__truncsfhf2(0xc77fef00, 0xfbff); // normal, -65519 -> -65504 + try test_f16_floatCast_f32(0x477fef00, 0x7bff); // normal, 65519 -> 65504 + try test_f16_floatCast_f32(0xc77fef00, 0xfbff); // normal, -65519 -> -65504 - try test__truncsfhf2(0x3f802000, 0x3c01); // normal, 1 + 2**-10 - try test__truncsfhf2(0xbf802000, 0xbc01); // normal, -1 - 2**-10 + try test_f16_floatCast_f32(0x3f802000, 0x3c01); // normal, 1 + 2**-10 + try test_f16_floatCast_f32(0xbf802000, 0xbc01); // normal, -1 - 2**-10 - try test__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3 - try test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3 + try test_f16_floatCast_f32(0x3eaaa000, 0x3555); // normal, approx. 1/3 + try test_f16_floatCast_f32(0xbeaaa000, 0xb555); // normal, approx. -1/3 - try test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535 - try test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535 + try test_f16_floatCast_f32(0x40490fdb, 0x4248); // normal, 3.1415926535 + try test_f16_floatCast_f32(0xc0490fdb, 0xc248); // normal, -3.1415926535 - try test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 + try test_f16_floatCast_f32(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12 - try test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1 - try test__truncsfhf2(0x38800000, 0x0400); // normal, 0x1.0p-14 + try test_f16_floatCast_f32(0x3f800000, 0x3c00); // normal, 1 + try test_f16_floatCast_f32(0x38800000, 0x0400); // normal, 0x1.0p-14 - try test__truncsfhf2(0x33800000, 0x0001); // denormal (min), 2**-24 - try test__truncsfhf2(0xb3800000, 0x8001); // denormal (min), -2**-24 + try test_f16_floatCast_f32(0x33800000, 0x0001); // denormal (min), 2**-24 + try test_f16_floatCast_f32(0xb3800000, 0x8001); // denormal (min), -2**-24 - try test__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 - try test__truncsfhf2(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24 + try test_f16_floatCast_f32(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24 + try test_f16_floatCast_f32(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24 - try test__truncsfhf2(0x35800000, 0x0010); // denormal, 0x1.0p-20 - try test__truncsfhf2(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24 - try test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero + try test_f16_floatCast_f32(0x35800000, 0x0010); // denormal, 0x1.0p-20 + try test_f16_floatCast_f32(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24 + try test_f16_floatCast_f32(0x33000000, 0x0000); // 0x1.0p-25 -> zero } -fn test__truncdfhf2(a: f64, expected: u16) void { - const rep: u16 = @bitCast(__truncdfhf2(a)); +fn test_f16_floatCast_f64(a: f64, expected: u16) !void { + const rep: u16 = @bitCast(f16_floatCast_f64(a)); if (rep == expected) { return; @@ -84,62 +87,56 @@ fn test__truncdfhf2(a: f64, expected: u16) void { return; } } - - @panic("__truncdfhf2 test failure"); + return error.TestFailure; } -fn test__truncdfhf2_raw(a: u64, expected: u16) void { - const actual: u16 = @bitCast(__truncdfhf2(@bitCast(a))); - - if (actual == expected) { - return; - } - - @panic("__truncdfhf2 test failure"); +fn test_f16_floatCast_f64_raw(a: u64, expected: u16) !void { + const actual: u16 = @bitCast(f16_floatCast_f64(@bitCast(a))); + try testing.expect(actual == expected); } -test "truncdfhf2" { - test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN - test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN +test f16_floatCast_f64 { + try test_f16_floatCast_f64_raw(0x7ff8000000000000, 0x7e00); // qNaN + try test_f16_floatCast_f64_raw(0x7ff0000000008000, 0x7e00); // NaN - test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf - test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf + try test_f16_floatCast_f64_raw(0x7ff0000000000000, 0x7c00); //inf + try test_f16_floatCast_f64_raw(0xfff0000000000000, 0xfc00); // -inf - test__truncdfhf2(0.0, 0x0); // zero - test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero + try test_f16_floatCast_f64(0.0, 0x0); // zero + try test_f16_floatCast_f64_raw(0x80000000 << 32, 0x8000); // -zero - test__truncdfhf2(3.1415926535, 0x4248); - test__truncdfhf2(-3.1415926535, 0xc248); + try test_f16_floatCast_f64(3.1415926535, 0x4248); + try test_f16_floatCast_f64(-3.1415926535, 0xc248); - test__truncdfhf2(0x1.987124876876324p+1000, 0x7c00); - test__truncdfhf2(0x1.987124876876324p+12, 0x6e62); - test__truncdfhf2(0x1.0p+0, 0x3c00); - test__truncdfhf2(0x1.0p-14, 0x0400); + try test_f16_floatCast_f64(0x1.987124876876324p+1000, 0x7c00); + try test_f16_floatCast_f64(0x1.987124876876324p+12, 0x6e62); + try test_f16_floatCast_f64(0x1.0p+0, 0x3c00); + try test_f16_floatCast_f64(0x1.0p-14, 0x0400); // denormal - test__truncdfhf2(0x1.0p-20, 0x0010); - test__truncdfhf2(0x1.0p-24, 0x0001); - test__truncdfhf2(-0x1.0p-24, 0x8001); - test__truncdfhf2(0x1.5p-25, 0x0001); + try test_f16_floatCast_f64(0x1.0p-20, 0x0010); + try test_f16_floatCast_f64(0x1.0p-24, 0x0001); + try test_f16_floatCast_f64(-0x1.0p-24, 0x8001); + try test_f16_floatCast_f64(0x1.5p-25, 0x0001); // and back to zero - test__truncdfhf2(0x1.0p-25, 0x0000); - test__truncdfhf2(-0x1.0p-25, 0x8000); + try test_f16_floatCast_f64(0x1.0p-25, 0x0000); + try test_f16_floatCast_f64(-0x1.0p-25, 0x8000); // max (precise) - test__truncdfhf2(65504.0, 0x7bff); + try test_f16_floatCast_f64(65504.0, 0x7bff); // max (rounded) - test__truncdfhf2(65519.0, 0x7bff); + try test_f16_floatCast_f64(65519.0, 0x7bff); // max (to +inf) - test__truncdfhf2(65520.0, 0x7c00); - test__truncdfhf2(-65520.0, 0xfc00); - test__truncdfhf2(65536.0, 0x7c00); + try test_f16_floatCast_f64(65520.0, 0x7c00); + try test_f16_floatCast_f64(-65520.0, 0xfc00); + try test_f16_floatCast_f64(65536.0, 0x7c00); } -fn test__trunctfsf2(a: f128, expected: u32) void { - const x = __trunctfsf2(a); +fn test_f32_floatCast_f128(a: f128, expected: u32) !void { + const x = f32_floatCast_f128(a); const rep: u32 = @bitCast(x); if (rep == expected) { @@ -151,28 +148,27 @@ fn test__trunctfsf2(a: f128, expected: u32) void { return; } } - - @panic("__trunctfsf2 test failure"); + return error.TestFailure; } -test "trunctfsf2" { +test f32_floatCast_f128 { // qnan - test__trunctfsf2(@bitCast(@as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); + try test_f32_floatCast_f128(@bitCast(@as(u128, 0x7fff800000000000 << 64)), 0x7fc00000); // nan - test__trunctfsf2(@bitCast(@as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); + try test_f32_floatCast_f128(@bitCast(@as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000); // inf - test__trunctfsf2(@bitCast(@as(u128, 0x7fff000000000000 << 64)), 0x7f800000); + try test_f32_floatCast_f128(@bitCast(@as(u128, 0x7fff000000000000 << 64)), 0x7f800000); // zero - test__trunctfsf2(0.0, 0x0); + try test_f32_floatCast_f128(0.0, 0x0); - test__trunctfsf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156); - test__trunctfsf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2); - test__trunctfsf2(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000); - test__trunctfsf2(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0); + try test_f32_floatCast_f128(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156); + try test_f32_floatCast_f128(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2); + try test_f32_floatCast_f128(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000); + try test_f32_floatCast_f128(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0); } -fn test__trunctfdf2(a: f128, expected: u64) void { - const x = __trunctfdf2(a); +fn test_f64_floatCast_f128(a: f128, expected: u64) !void { + const x = f64_floatCast_f128(a); const rep: u64 = @bitCast(x); if (rep == expected) { @@ -184,28 +180,27 @@ fn test__trunctfdf2(a: f128, expected: u64) void { return; } } - - @panic("__trunctfsf2 test failure"); + return error.TestFailure; } -test "trunctfdf2" { +test f64_floatCast_f128 { // qnan - test__trunctfdf2(@bitCast(@as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); + try test_f64_floatCast_f128(@bitCast(@as(u128, 0x7fff800000000000 << 64)), 0x7ff8000000000000); // nan - test__trunctfdf2(@bitCast(@as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); + try test_f64_floatCast_f128(@bitCast(@as(u128, (0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000); // inf - test__trunctfdf2(@bitCast(@as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); + try test_f64_floatCast_f128(@bitCast(@as(u128, 0x7fff000000000000 << 64)), 0x7ff0000000000000); // zero - test__trunctfdf2(0.0, 0x0); + try test_f64_floatCast_f128(0.0, 0x0); - test__trunctfdf2(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb); - test__trunctfdf2(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7); - test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000); - test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab); + try test_f64_floatCast_f128(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb); + try test_f64_floatCast_f128(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7); + try test_f64_floatCast_f128(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000); + try test_f64_floatCast_f128(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab); } -fn test__truncdfsf2(a: f64, expected: u32) void { - const x = __truncdfsf2(a); +fn test_f32_floatCast_f64(a: f64, expected: u32) !void { + const x = f32_floatCast_f64(a); const rep: u32 = @bitCast(x); if (rep == expected) { @@ -217,90 +212,81 @@ fn test__truncdfsf2(a: f64, expected: u32) void { return; } } - - std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); - - @panic("__trunctfsf2 test failure"); + return error.TestFailure; } -test "truncdfsf2" { +test f32_floatCast_f64 { // nan & qnan - test__truncdfsf2(@bitCast(@as(u64, 0x7ff8000000000000)), 0x7fc00000); - test__truncdfsf2(@bitCast(@as(u64, 0x7ff0000000000001)), 0x7fc00000); + try test_f32_floatCast_f64(@bitCast(@as(u64, 0x7ff8000000000000)), 0x7fc00000); + try test_f32_floatCast_f64(@bitCast(@as(u64, 0x7ff0000000000001)), 0x7fc00000); // inf - test__truncdfsf2(@bitCast(@as(u64, 0x7ff0000000000000)), 0x7f800000); - test__truncdfsf2(@bitCast(@as(u64, 0xfff0000000000000)), 0xff800000); + try test_f32_floatCast_f64(@bitCast(@as(u64, 0x7ff0000000000000)), 0x7f800000); + try test_f32_floatCast_f64(@bitCast(@as(u64, 0xfff0000000000000)), 0xff800000); - test__truncdfsf2(0.0, 0x0); - test__truncdfsf2(1.0, 0x3f800000); - test__truncdfsf2(-1.0, 0xbf800000); + try test_f32_floatCast_f64(0.0, 0x0); + try test_f32_floatCast_f64(1.0, 0x3f800000); + try test_f32_floatCast_f64(-1.0, 0xbf800000); // huge number becomes inf - test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); + try test_f32_floatCast_f64(340282366920938463463374607431768211456.0, 0x7f800000); } -fn test__trunctfhf2(a: f128, expected: u16) void { - const x = __trunctfhf2(a); +fn test_f16_floatCast_f128(a: f128, expected: u16) !void { + const x = f16_floatCast_f128(a); const rep: u16 = @bitCast(x); - if (rep == expected) { - return; - } - - std.debug.print("got 0x{x} wanted 0x{x}\n", .{ rep, expected }); - - @panic("__trunctfhf2 test failure"); + try testing.expect(rep == expected); } -test "trunctfhf2" { +test f16_floatCast_f128 { // qNaN - test__trunctfhf2(@bitCast(@as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); + try test_f16_floatCast_f128(@bitCast(@as(u128, 0x7fff8000000000000000000000000000)), 0x7e00); // NaN - test__trunctfhf2(@bitCast(@as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); + try test_f16_floatCast_f128(@bitCast(@as(u128, 0x7fff0000000000000000000000000001)), 0x7e00); // inf - test__trunctfhf2(@bitCast(@as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); - test__trunctfhf2(-@as(f128, @bitCast(@as(u128, 0x7fff0000000000000000000000000000))), 0xfc00); + try test_f16_floatCast_f128(@bitCast(@as(u128, 0x7fff0000000000000000000000000000)), 0x7c00); + try test_f16_floatCast_f128(-@as(f128, @bitCast(@as(u128, 0x7fff0000000000000000000000000000))), 0xfc00); // zero - test__trunctfhf2(0.0, 0x0); - test__trunctfhf2(-0.0, 0x8000); + try test_f16_floatCast_f128(0.0, 0x0); + try test_f16_floatCast_f128(-0.0, 0x8000); - test__trunctfhf2(3.1415926535, 0x4248); - test__trunctfhf2(-3.1415926535, 0xc248); - test__trunctfhf2(0x1.987124876876324p+100, 0x7c00); - test__trunctfhf2(0x1.987124876876324p+12, 0x6e62); - test__trunctfhf2(0x1.0p+0, 0x3c00); - test__trunctfhf2(0x1.0p-14, 0x0400); + try test_f16_floatCast_f128(3.1415926535, 0x4248); + try test_f16_floatCast_f128(-3.1415926535, 0xc248); + try test_f16_floatCast_f128(0x1.987124876876324p+100, 0x7c00); + try test_f16_floatCast_f128(0x1.987124876876324p+12, 0x6e62); + try test_f16_floatCast_f128(0x1.0p+0, 0x3c00); + try test_f16_floatCast_f128(0x1.0p-14, 0x0400); // denormal - test__trunctfhf2(0x1.0p-20, 0x0010); - test__trunctfhf2(0x1.0p-24, 0x0001); - test__trunctfhf2(-0x1.0p-24, 0x8001); - test__trunctfhf2(0x1.5p-25, 0x0001); + try test_f16_floatCast_f128(0x1.0p-20, 0x0010); + try test_f16_floatCast_f128(0x1.0p-24, 0x0001); + try test_f16_floatCast_f128(-0x1.0p-24, 0x8001); + try test_f16_floatCast_f128(0x1.5p-25, 0x0001); // and back to zero - test__trunctfhf2(0x1.0p-25, 0x0000); - test__trunctfhf2(-0x1.0p-25, 0x8000); + try test_f16_floatCast_f128(0x1.0p-25, 0x0000); + try test_f16_floatCast_f128(-0x1.0p-25, 0x8000); // max (precise) - test__trunctfhf2(65504.0, 0x7bff); + try test_f16_floatCast_f128(65504.0, 0x7bff); // max (rounded) - test__trunctfhf2(65519.0, 0x7bff); + try test_f16_floatCast_f128(65519.0, 0x7bff); // max (to +inf) - test__trunctfhf2(65520.0, 0x7c00); - test__trunctfhf2(65536.0, 0x7c00); - test__trunctfhf2(-65520.0, 0xfc00); + try test_f16_floatCast_f128(65520.0, 0x7c00); + try test_f16_floatCast_f128(65536.0, 0x7c00); + try test_f16_floatCast_f128(-65520.0, 0xfc00); - test__trunctfhf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x508f); - test__trunctfhf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x1b8f); - test__trunctfhf2(0x1.234eebb5faa678f4488693abcdefp+453, 0x7c00); - test__trunctfhf2(0x1.edcba9bb8c76a5a43dd21f334634p-43, 0x0); + try test_f16_floatCast_f128(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x508f); + try test_f16_floatCast_f128(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x1b8f); + try test_f16_floatCast_f128(0x1.234eebb5faa678f4488693abcdefp+453, 0x7c00); + try test_f16_floatCast_f128(0x1.edcba9bb8c76a5a43dd21f334634p-43, 0x0); } -test "trunctfxf2" { - try test__trunctfxf2(1.5, 1.5); - try test__trunctfxf2(2.5, 2.5); - try test__trunctfxf2(-2.5, -2.5); - try test__trunctfxf2(0.0, 0.0); -} - -fn test__trunctfxf2(a: f128, expected: f80) !void { - const x = __trunctfxf2(a); +fn test_f80_floatCast_f128(a: f128, expected: f80) !void { + const x = f80_floatCast_f128(a); try testing.expect(x == expected); } + +test f80_floatCast_f128 { + try test_f80_floatCast_f128(1.5, 1.5); + try test_f80_floatCast_f128(2.5, 2.5); + try test_f80_floatCast_f128(-2.5, -2.5); + try test_f80_floatCast_f128(0.0, 0.0); +} diff --git a/lib/compiler_rt/truncsfhf2.zig b/lib/compiler_rt/truncsfhf2.zig deleted file mode 100644 index e0b2b1e4bf2f15400c568f1c1656c8cb70bc03c8..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncsfhf2.zig +++ /dev/null @@ -1,24 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const truncf = @import("./truncf.zig").truncf; - -comptime { - if (compiler_rt.gnu_f16_abi) { - symbol(&__gnu_f2h_ieee, "__gnu_f2h_ieee"); - } else if (compiler_rt.want_aeabi) { - symbol(&__aeabi_f2h, "__aeabi_f2h"); - } - symbol(&__truncsfhf2, "__truncsfhf2"); -} - -pub fn __truncsfhf2(a: f32) callconv(.c) compiler_rt.F16T(f32) { - return @bitCast(truncf(f16, f32, a)); -} - -fn __gnu_f2h_ieee(a: f32) callconv(.c) compiler_rt.F16T(f32) { - return @bitCast(truncf(f16, f32, a)); -} - -fn __aeabi_f2h(a: f32) callconv(.{ .arm_aapcs = .{} }) u16 { - return @bitCast(truncf(f16, f32, a)); -} diff --git a/lib/compiler_rt/trunctfdf2.zig b/lib/compiler_rt/trunctfdf2.zig deleted file mode 100644 index ba909de73bf144b2f023e4f6366dac5a4ad0ea40..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/trunctfdf2.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const truncf = @import("./truncf.zig").truncf; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__trunctfdf2, "__trunckfdf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtod, "_Qp_qtod"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__trunctfdf2, "_Q_qtod"); - } - symbol(&__trunctfdf2, "__trunctfdf2"); -} - -pub fn __trunctfdf2(a: f128) callconv(.c) f64 { - return truncf(f64, f128, a); -} - -fn _Qp_qtod(a: *const f128) callconv(.c) f64 { - return truncf(f64, f128, a.*); -} diff --git a/lib/compiler_rt/trunctfhf2.zig b/lib/compiler_rt/trunctfhf2.zig deleted file mode 100644 index 5af87f9c127180b49a15b8f3906252d7da162d26..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/trunctfhf2.zig +++ /dev/null @@ -1,14 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const truncf = @import("./truncf.zig").truncf; - -comptime { - symbol(&__trunctfhf2, "__trunctfhf2"); - if (compiler_rt.want_ppc_abi) { - symbol(&__trunctfhf2, "__trunckfhf2"); - } -} - -pub fn __trunctfhf2(a: f128) callconv(.c) compiler_rt.F16T(f128) { - return @bitCast(truncf(f16, f128, a)); -} diff --git a/lib/compiler_rt/trunctfsf2.zig b/lib/compiler_rt/trunctfsf2.zig deleted file mode 100644 index 8af51ca82f95b1dd36c7f27df20e6756b8e15396..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/trunctfsf2.zig +++ /dev/null @@ -1,22 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const truncf = @import("./truncf.zig").truncf; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_ppc_abi) { - symbol(&__trunctfsf2, "__trunckfsf2"); - } else if (compiler_rt.want_sparc64_abi) { - symbol(&_Qp_qtos, "_Qp_qtos"); - } else if (compiler_rt.want_sparc32_abi) { - symbol(&__trunctfsf2, "_Q_qtos"); - } - symbol(&__trunctfsf2, "__trunctfsf2"); -} - -pub fn __trunctfsf2(a: f128) callconv(.c) f32 { - return truncf(f32, f128, a); -} - -fn _Qp_qtos(a: *const f128) callconv(.c) f32 { - return truncf(f32, f128, a.*); -} diff --git a/lib/compiler_rt/trunctfxf2.zig b/lib/compiler_rt/trunctfxf2.zig deleted file mode 100644 index dfb9ef80402cda0360a111e436ba1f7c460bbc1f..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/trunctfxf2.zig +++ /dev/null @@ -1,67 +0,0 @@ -const math = @import("std").math; -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = compiler_rt.symbol; -const trunc_f80 = @import("./truncf.zig").trunc_f80; - -comptime { - symbol(&__trunctfxf2, "__trunctfxf2"); -} - -pub fn __trunctfxf2(a: f128) callconv(.c) f80 { - const src_sig_bits = math.floatMantissaBits(f128); - const dst_sig_bits = math.floatMantissaBits(f80) - 1; // -1 for the integer bit - - // Various constants whose values follow from the type parameters. - // Any reasonable optimizer will fold and propagate all of these. - const src_bits = @typeInfo(f128).float.bits; - const src_exp_bits = src_bits - src_sig_bits - 1; - const src_inf_exp = 0x7FFF; - - const src_inf = src_inf_exp << src_sig_bits; - const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); - const src_abs_mask = src_sign_mask - 1; - const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; - const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); - - // Break a into a sign and representation of the absolute value - const a_rep = @as(u128, @bitCast(a)); - const a_abs = a_rep & src_abs_mask; - const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0; - const integer_bit = 1 << 63; - - var res: math.F80 = undefined; - - if (a_abs > src_inf) { - // a is NaN. - // Conjure the result by beginning with infinity, setting the qNaN - // bit and inserting the (truncated) trailing NaN field. - res.exp = 0x7fff; - res.fraction = 0x8000000000000000; - res.fraction |= @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))); - } else { - // The exponent of a is within the range of normal numbers in the - // destination format. We can convert by simply right-shifting with - // rounding, adding the explicit integer bit, and adjusting the exponent - res.fraction = @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))) | integer_bit; - res.exp = @truncate(a_abs >> src_sig_bits); - - const round_bits = a_abs & round_mask; - if (round_bits > halfway) { - // Round to nearest - const ov = @addWithOverflow(res.fraction, 1); - res.fraction = ov[0]; - res.exp += ov[1]; - res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry - } else if (round_bits == halfway) { - // Ties to even - const ov = @addWithOverflow(res.fraction, res.fraction & 1); - res.fraction = ov[0]; - res.exp += ov[1]; - res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry - } - if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals - } - - res.exp |= sign; - return res.toFloat(); -} diff --git a/lib/compiler_rt/truncxfdf2.zig b/lib/compiler_rt/truncxfdf2.zig deleted file mode 100644 index 6140d94181fbe10a5e83e880dff805e87b34fae8..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncxfdf2.zig +++ /dev/null @@ -1,10 +0,0 @@ -const symbol = @import("../compiler_rt.zig").symbol; -const trunc_f80 = @import("./truncf.zig").trunc_f80; - -comptime { - symbol(&__truncxfdf2, "__truncxfdf2"); -} - -fn __truncxfdf2(a: f80) callconv(.c) f64 { - return trunc_f80(f64, a); -} diff --git a/lib/compiler_rt/truncxfhf2.zig b/lib/compiler_rt/truncxfhf2.zig deleted file mode 100644 index 4c3e951bfe9b67ff88818e6a89f210851ddfcfb0..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncxfhf2.zig +++ /dev/null @@ -1,11 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; -const trunc_f80 = @import("./truncf.zig").trunc_f80; - -comptime { - symbol(&__truncxfhf2, "__truncxfhf2"); -} - -fn __truncxfhf2(a: f80) callconv(.c) compiler_rt.F16T(f80) { - return @bitCast(trunc_f80(f16, a)); -} diff --git a/lib/compiler_rt/truncxfsf2.zig b/lib/compiler_rt/truncxfsf2.zig deleted file mode 100644 index 8aaf7e6906a9da938835d2c36e931bfb21d07037..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/truncxfsf2.zig +++ /dev/null @@ -1,10 +0,0 @@ -const trunc_f80 = @import("./truncf.zig").trunc_f80; -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - symbol(&__truncxfsf2, "__truncxfsf2"); -} - -fn __truncxfsf2(a: f80) callconv(.c) f32 { - return trunc_f80(f32, a); -} diff --git a/lib/compiler_rt/udivmodei4.zig b/lib/compiler_rt/udivmodei4.zig index 41ba32cdbef1532de8b77e0f91db4bbf4b39f29a..e7c4f52cd1f0360307c5e0ab2232c8925b0b1792 100644 --- a/lib/compiler_rt/udivmodei4.zig +++ b/lib/compiler_rt/udivmodei4.zig @@ -6,7 +6,7 @@ const shr = std.math.shr; const shl = std.math.shl; const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const max_limbs = @divCeil(65535, 32); // max supported type is u65535 diff --git a/lib/compiler_rt/unorddf2.zig b/lib/compiler_rt/unorddf2.zig deleted file mode 100644 index 90da7451992ab5f8b003e5e2f85f93947f932197..0000000000000000000000000000000000000000 --- a/lib/compiler_rt/unorddf2.zig +++ /dev/null @@ -1,19 +0,0 @@ -const compiler_rt = @import("../compiler_rt.zig"); -const comparef = @import("./comparef.zig"); -const symbol = @import("../compiler_rt.zig").symbol; - -comptime { - if (compiler_rt.want_aeabi) { - symbol(&__aeabi_dcmpun, "__aeabi_dcmpun"); - } else { - symbol(&__unorddf2, "__unorddf2"); - } -} - -pub fn __unorddf2(a: f64, b: f64) callconv(.c) i32 { - return comparef.unordcmp(f64, a, b); -} - -fn __aeabi_dcmpun(a: f64, b: f64) callconv(.{ .arm_aapcs = .{} }) i32 { - return comparef.unordcmp(f64, a, b); -} diff --git a/lib/docs/wasm/html_render.zig b/lib/docs/wasm/html_render.zig index 5bb54f7ad2ba4a7ade1cb71f00b1a6ba037c26ef..cb94a016e44aff8d1b219d2f206a42109f635f17 100644 --- a/lib/docs/wasm/html_render.zig +++ b/lib/docs/wasm/html_render.zig @@ -62,7 +62,7 @@ pub fn fileSourceHtml( var cursor: usize = ast.tokenStart(start_token); var indent: usize = 0; - if (std.mem.lastIndexOf(u8, ast.source[0..cursor], "\n")) |newline_index| { + if (std.mem.findLast(u8, ast.source[0..cursor], "\n")) |newline_index| { for (ast.source[newline_index + 1 .. cursor]) |c| { if (c == ' ') { indent += 1; diff --git a/lib/docs/wasm/main.zig b/lib/docs/wasm/main.zig index 7f8bf047e44235eabdc5350098923ca074e862bd..aba4d2ac4ff5568a9aa072291dc33869af0f1c63 100644 --- a/lib/docs/wasm/main.zig +++ b/lib/docs/wasm/main.zig @@ -153,11 +153,11 @@ fn query_exec_fallible(query: []const u8, ignore_case: bool) !void { continue; } // substring, case insensitive match of full decl path - if (std.mem.indexOf(u8, g.full_path_search_text_lower.items, term) != null) { + if (std.mem.find(u8, g.full_path_search_text_lower.items, term) != null) { points += 2; continue; } - if (std.mem.indexOf(u8, g.doc_search_text.items, term) != null) { + if (std.mem.find(u8, g.doc_search_text.items, term) != null) { points += 1; continue; } @@ -803,7 +803,7 @@ fn unpackInner(tar_bytes: []u8) !void { if (std.mem.endsWith(u8, tar_file.name, ".zig")) { log.debug("found file: '{s}'", .{tar_file.name}); const file_name = try gpa.dupe(u8, tar_file.name); - if (std.mem.indexOfScalar(u8, file_name, '/')) |pkg_name_end| { + if (std.mem.findScalar(u8, file_name, '/')) |pkg_name_end| { const pkg_name = file_name[0..pkg_name_end]; const gop = try Walk.modules.getOrPut(gpa, pkg_name); const file: Walk.File.Index = @fromBackingInt(@intCast(Walk.files.entries.len)); diff --git a/lib/docs/wasm/markdown/Document.zig b/lib/docs/wasm/markdown/Document.zig index 97507506af7a15bb5a800085930709d1446d8a11..7cde78f32b5ca948ab6e940f558a43dcd9d9bacc 100644 --- a/lib/docs/wasm/markdown/Document.zig +++ b/lib/docs/wasm/markdown/Document.zig @@ -108,7 +108,7 @@ pub const Node = struct { // In Debug and ReleaseSafe builds, there may be hidden extra fields // included for safety checks. Without such safety checks enabled, // we always want this union to be 8 bytes. - if (builtin.mode != .Debug and builtin.mode != .ReleaseSafe) { + if (builtin.mode != .debug and builtin.mode != .safe) { assert(@sizeOf(Data) == 8); } } diff --git a/lib/docs/wasm/markdown/Parser.zig b/lib/docs/wasm/markdown/Parser.zig index 0b4695983cc7fc7dd89ffbd4273f809fdfe7bba1..1bded7541327d17d35aef311c231d6b7171df4e5 100644 --- a/lib/docs/wasm/markdown/Parser.zig +++ b/lib/docs/wasm/markdown/Parser.zig @@ -159,7 +159,7 @@ const Block = struct { .heading => null, .code_block => code_block: { const trimmed = mem.trimEnd(u8, unindented, " \t"); - if (mem.indexOfNone(u8, trimmed, "`") != null or trimmed.len != b.data.code_block.fence_len) { + if (mem.findNone(u8, trimmed, "`") != null or trimmed.len != b.data.code_block.fence_len) { const effective_indent = @min(indent, b.data.code_block.indent); break :code_block line[effective_indent..]; } else { @@ -209,7 +209,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void { } else p.pending_blocks.items.len; const in_code_block = p.pending_blocks.items.len > 0 and - p.pending_blocks.getLast().?.tag == .code_block; + p.pending_blocks.last().?.tag == .code_block; const code_block_end = in_code_block and first_unmatched + 1 == p.pending_blocks.items.len; // New blocks cannot be started if we are actively inside a code block or @@ -225,7 +225,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void { if (maybe_block_start == null and !isBlank(rest_line) and p.pending_blocks.items.len > 0 and - p.pending_blocks.getLast().?.tag == .paragraph) + p.pending_blocks.last().?.tag == .paragraph) { try p.addScratchStringLine(mem.trimStart(u8, rest_line, " \t")); return; @@ -236,7 +236,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void { // paragraphs. if (maybe_block_start != null and p.pending_blocks.items.len > 0 and - p.pending_blocks.getLast().?.tag == .paragraph) + p.pending_blocks.last().?.tag == .paragraph) { try p.closeLastBlock(); } @@ -259,7 +259,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void { // Do not append the end of a code block (```) as textual content. if (code_block_end) return; - const can_accept = if (p.pending_blocks.getLast()) |last_pending_block| + const can_accept = if (p.pending_blocks.last()) |last_pending_block| last_pending_block.canAccept() else .blocks; @@ -273,7 +273,7 @@ pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void { // loose, since we might just be looking at a blank line after the // end of the last item in the list. The final determination will be // made when appending the next child of the list or list item. - const maybe_containing_list_index = if (p.pending_blocks.items.len > 0 and p.pending_blocks.getLast().?.tag == .list_item) + const maybe_containing_list_index = if (p.pending_blocks.items.len > 0 and p.pending_blocks.last().?.tag == .list_item) p.pending_blocks.items.len - 2 else null; @@ -368,7 +368,7 @@ const BlockStart = struct { }; fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { - if (p.pending_blocks.getLast()) |last_pending_block| { + if (p.pending_blocks.last()) |last_pending_block| { // Close the last block if it is a list and the new block is not a list item // or not of the same marker type. const should_close_list = last_pending_block.tag == .list and @@ -383,7 +383,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { } } - if (p.pending_blocks.getLast()) |last_pending_block| { + if (p.pending_blocks.last()) |last_pending_block| { // If the last block is a list or list item, check for tightness based // on the last line. const maybe_containing_list = switch (last_pending_block.tag) { @@ -401,7 +401,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { // Start a new list if the new block is a list item and there is no // containing list yet. if (block_start.tag == .list_item and - (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().?.tag != .list)) + (p.pending_blocks.items.len == 0 or p.pending_blocks.last().?.tag != .list)) { try p.pending_blocks.append(p.allocator, .{ .tag = .list, @@ -417,7 +417,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { if (block_start.tag == .table_row) { // Likewise, table rows start a table implicitly. - if (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().?.tag != .table) { + if (p.pending_blocks.items.len == 0 or p.pending_blocks.last().?.tag != .table) { try p.pending_blocks.append(p.allocator, .{ .tag = .table, .data = .{ .table = .{ @@ -429,7 +429,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { }); } - const current_row = p.scratch_extra.items.len - p.pending_blocks.getLast().?.extra_start; + const current_row = p.scratch_extra.items.len - p.pending_blocks.last().?.extra_start; if (current_row <= 1) { var buffer: [max_table_columns]Node.TableCellAlignment = undefined; const table_row = &block_start.data.table_row; @@ -441,7 +441,7 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { // We need to go back and mark the header row and its column // alignments. const datas = p.nodes.items(.data); - const header_data = datas[p.scratch_extra.getLast().?]; + const header_data = datas[p.scratch_extra.last().?]; for (p.extraChildren(header_data.container.children), 0..) |header_cell, i| { const alignment = if (i < alignments.len) alignments[i] else .unset; const cell_data = &datas[@backingInt(header_cell)].table_cell; @@ -594,7 +594,7 @@ fn startListItem(unindented_line: []const u8) ?ListItemStart { }; } - const number_end = mem.indexOfNone(u8, unindented_line, "0123456789") orelse return null; + const number_end = mem.findNone(u8, unindented_line, "0123456789") orelse return null; const after_number = unindented_line[number_end..]; const marker: Block.Data.ListMarker = if (mem.startsWith(u8, after_number, ". ")) .number_dot @@ -639,10 +639,10 @@ fn startTableRow(unindented_line: []const u8) ?TableRowStart { // Ignoring pipes in code spans allows table cells to contain // code using ||, for example. const open_start = i; - i = mem.indexOfNonePos(u8, table_row_content, i, "`") orelse return null; + i = mem.findNonePos(u8, table_row_content, i, "`") orelse return null; const open_len = i - open_start; - while (mem.indexOfScalarPos(u8, table_row_content, i, '`')) |close_start| { - i = mem.indexOfNonePos(u8, table_row_content, close_start, "`") orelse return null; + while (mem.findScalarPos(u8, table_row_content, i, '`')) |close_start| { + i = mem.findNonePos(u8, table_row_content, close_start, "`") orelse return null; const close_len = i - close_start; if (close_len == open_len) break; } else return null; @@ -794,7 +794,7 @@ fn startCodeBlock(p: *Parser, unindented_line: []const u8) !?CodeBlockStart { } else ""; // Code block tags may not contain backticks, since that would create // potential confusion with inline code spans. - if (fence_len < 3 or mem.indexOfScalar(u8, tag_bytes, '`') != null) return null; + if (fence_len < 3 or mem.findScalar(u8, tag_bytes, '`') != null) return null; return .{ .tag = try p.addString(mem.trim(u8, tag_bytes, " ")), .fence_len = fence_len, @@ -1382,12 +1382,12 @@ const InlineParser = struct { /// parsing. fn parseCodeSpan(ip: *InlineParser) !void { const opener_start = ip.pos; - ip.pos = mem.indexOfNonePos(u8, ip.content, ip.pos, "`") orelse ip.content.len; + ip.pos = mem.findNonePos(u8, ip.content, ip.pos, "`") orelse ip.content.len; const opener_len = ip.pos - opener_start; const start = ip.pos; - const end = while (mem.indexOfScalarPos(u8, ip.content, ip.pos, '`')) |closer_start| { - ip.pos = mem.indexOfNonePos(u8, ip.content, closer_start, "`") orelse ip.content.len; + const end = while (mem.findScalarPos(u8, ip.content, ip.pos, '`')) |closer_start| { + ip.pos = mem.findNonePos(u8, ip.content, closer_start, "`") orelse ip.content.len; const closer_len = ip.pos - closer_start; if (closer_len == opener_len) break closer_start; @@ -1627,7 +1627,7 @@ fn addScratchStringLine(p: *Parser, line: []const u8) !void { } fn isBlank(line: []const u8) bool { - return mem.indexOfNone(u8, line, " \t") == null; + return mem.findNone(u8, line, " \t") == null; } fn isPunctuation(c: u8) bool { diff --git a/lib/fuzzer.zig b/lib/fuzzer.zig index 65f677fb4e95b301403ef95f3f7f4034697df856..cf051dca8ec935688551a6da922634ae3e8320df 100644 --- a/lib/fuzzer.zig +++ b/lib/fuzzer.zig @@ -41,8 +41,8 @@ fn logOverride( var safe_allocator: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{}); const gpa = switch (builtin.mode) { - .Debug, .ReleaseSafe => safe_allocator.allocator(), - .ReleaseFast, .ReleaseSmall => std.heap.smp_allocator, + .debug, .safe => safe_allocator.allocator(), + .fast, .small => std.heap.smp_allocator, }; // Seperate from `exec` to allow initialization before `exec` is. @@ -1085,7 +1085,7 @@ const Fuzzer = struct { fn removeBest(f: *Fuzzer, i: Input.Index, best_i: u32) void { const t = &f.tests[f.test_i]; const ref = &t.corpus.items(.ref)[@backingInt(i)]; - const list_i = mem.indexOfScalar(u32, ref.best_i_buf[0..ref.best_i_len], best_i).?; + const list_i = mem.findScalar(u32, ref.best_i_buf[0..ref.best_i_len], best_i).?; ref.best_i_len -= 1; ref.best_i_buf[list_i] = ref.best_i_buf[ref.best_i_len]; @@ -1209,7 +1209,7 @@ const Fuzzer = struct { f.req_bytes = @intCast(f.input_builder.bytes_table.items.len); const quality: Input.Best.Quality = .{ .n_pcs = n_pcs: { - @setRuntimeSafety(builtin.mode == .Debug); // Necessary for vectorization + @setRuntimeSafety(builtin.mode == .debug); // Necessary for vectorization var n: u32 = 0; for (exec.pc_counters) |c| { n += @intFromBool(c != 0); diff --git a/lib/libc/glibc/abilists b/lib/libc/glibc/abilists index 3dec0a31a51a74d915e94a8c647416555d175a13..16ce0e77b3a4af2e7db96148dfbd4e4857b5fce8 100644 Binary files a/lib/libc/glibc/abilists and b/lib/libc/glibc/abilists differ diff --git a/lib/libc/glibc/elf/elf.h b/lib/libc/glibc/elf/elf.h index 46a01281cb0fb5322d5124f0443c11dea4d5b721..b482fcfb64890752fc1aa4e9d208a7b94f022d38 100644 --- a/lib/libc/glibc/elf/elf.h +++ b/lib/libc/glibc/elf/elf.h @@ -798,7 +798,8 @@ typedef struct #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ #define NT_X86_SHSTK 0x204 /* x86 SHSTK state */ #define NT_X86_XSAVE_LAYOUT 0x205 /* XSAVE layout description. */ -#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ +#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves. This was + used in now removed s390-32 arch. */ #define NT_S390_TIMER 0x301 /* s390 timer register */ #define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ #define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ @@ -846,6 +847,7 @@ typedef struct #define NT_RISCV_VECTOR 0x901 /* RISC-V vector registers */ #define NT_RISCV_TAGGED_ADDR_CTRL 0x902 /* RISC-V tagged address control */ +#define NT_RISCV_USER_CFI 0x903 /* RISC-V shadow stack state */ #define NT_LOONGARCH_CPUCFG 0xa00 /* LoongArch CPU config registers. */ #define NT_LOONGARCH_CSR 0xa01 /* LoongArch control and status registers. */ @@ -3470,7 +3472,9 @@ enum /* Valid values for the e_flags field. */ -#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ +#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. + This was used in now removed s390-32 + arch. */ /* Additional s390 relocs */ diff --git a/lib/libc/glibc/include/libc-symbols.h b/lib/libc/glibc/include/libc-symbols.h index bebfc67cec098bf106bb9231bd3ff47e8f85d31f..a6aef303a22fa1a23c2a8f88f33451c803476e38 100644 --- a/lib/libc/glibc/include/libc-symbols.h +++ b/lib/libc/glibc/include/libc-symbols.h @@ -113,6 +113,7 @@ #define HAVE_LIBINTL_H 1 #define HAVE_WCTYPE_H 1 #define HAVE_ISWCTYPE 1 +#define HAVE_MEMPCPY 1 #define ENABLE_NLS 1 /* The symbols in all the user (non-_) macros are C symbols. */ @@ -682,7 +683,7 @@ for linking") /* Helper / base macros for indirect function symbols. */ #define __ifunc_resolver(type_name, name, expr, init, classifier, ...) \ - classifier inhibit_stack_protector \ + classifier \ __typeof (type_name) *name##_ifunc (__VA_ARGS__) \ { \ init (); \ diff --git a/lib/libc/glibc/sysdeps/aarch64/sysdep.h b/lib/libc/glibc/sysdeps/aarch64/sysdep.h index da4b7f3fd32c4fbd62ce777d1857baeda279dcbb..77e6564d97bb5473bc915dde142522f7ee938914 100644 --- a/lib/libc/glibc/sysdeps/aarch64/sysdep.h +++ b/lib/libc/glibc/sysdeps/aarch64/sysdep.h @@ -43,7 +43,6 @@ #define FEATURE_1_PAC 2 #define FEATURE_1_GCS 4 -/* Add a NT_GNU_PROPERTY_TYPE_0 note. */ #define GNU_PROPERTY(type, value) \ .section .note.gnu.property, "a"; \ .p2align 3; \ @@ -57,9 +56,34 @@ .word 0; \ .text -/* Add GNU property note with the supported features to all asm code - where sysdep.h is included. */ -GNU_PROPERTY (FEATURE_1_AND, FEATURE_1_BTI|FEATURE_1_PAC|FEATURE_1_GCS) +#ifdef __ARM_BUILDATTR64_FV +/* Add AArch64 feature bits build attributes. */ +# define FEATURE_1_AND_MARK(value) \ + .aeabi_subsection aeabi_feature_and_bits, optional, ULEB128; \ + .if ((value) & FEATURE_1_BTI); \ + .aeabi_attribute Tag_Feature_BTI, 1; \ + .else; \ + .aeabi_attribute Tag_Feature_BTI, 0; \ + .endif; \ + .if ((value) & FEATURE_1_GCS); \ + .aeabi_attribute Tag_Feature_GCS, 1; \ + .else; \ + .aeabi_attribute Tag_Feature_GCS, 0; \ + .endif; \ + .if ((value) & FEATURE_1_PAC); \ + .aeabi_attribute Tag_Feature_PAC, 1; \ + .else; \ + .aeabi_attribute Tag_Feature_PAC, 0; \ + .endif; \ + .text +#else +/* Add a NT_GNU_PROPERTY_TYPE_0 note. */ +# define FEATURE_1_AND_MARK(value) GNU_PROPERTY (FEATURE_1_AND, value) +#endif /* __ARM_BUILDATTR64_FV */ + +/* Add marking with the supported features to all asm code where sysdep.h + is included. */ +FEATURE_1_AND_MARK (FEATURE_1_BTI | FEATURE_1_PAC | FEATURE_1_GCS) /* Define an entry point visible from C. */ #define ENTRY(name) \ diff --git a/lib/libc/glibc/sysdeps/arm/start.S b/lib/libc/glibc/sysdeps/arm/start.S index a7e62b39346d18be9d46f64048b092e7c873b068..6b154dc7d33e3450b94991e9d827a3edf85acc9f 100644 --- a/lib/libc/glibc/sysdeps/arm/start.S +++ b/lib/libc/glibc/sysdeps/arm/start.S @@ -90,6 +90,7 @@ _start: push { a1 } #ifdef PIC +# ifdef SHARED ldr sl, .L_GOT adr a4, .L_GOT add sl, sl, a4 @@ -103,6 +104,16 @@ _start: /* __libc_start_main (main, argc, argv, init, fini, rtld_fini, stack_end) */ /* Let the libc call main and exit with its return code. */ bl __libc_start_main(PLT) +# else + ldr a1, .L_main_rel /* Load the relative offset of __wrap_main. */ + adr a4, .L_main_rel /* Load the actual runtime address of the label. */ + add a1, a4, a1 /* Add them together to get the absolute address. */ + + mov a4, #0 /* Used to be init. */ + push { a4 } /* Used to be fini. */ + + bl __libc_start_main +# endif /* ifdef SHARED */ #else mov a4, #0 /* Used to init. */ @@ -119,14 +130,30 @@ _start: #ifdef PIC .align 2 +# ifdef SHARED .L_GOT: .word _GLOBAL_OFFSET_TABLE_ - .L_GOT .word main(GOT) +# else +.L_main_rel: + .word __wrap_main - .L_main_rel +# endif #endif .cantunwind .fnend +#if defined PIC && !defined SHARED +/* When main is not defined in the executable but in a shared library then + a wrapper is needed, because crt1.o and rcrt1.o share this code and the + latter (static PIE) must avoid GOT relocations before __libc_start_main + is called. The branch to main is turned into a PLT entry by every linker, + unlike a REL32 data relocation against main. */ + .type __wrap_main, %function +__wrap_main: + b main +#endif + /* Define a symbol for the first piece of initialized data. */ .data .globl __data_start diff --git a/lib/libc/glibc/sysdeps/htl/libc-lockP.h b/lib/libc/glibc/sysdeps/htl/libc-lockP.h index a88eea4344004d7bcacdcd6bb827547ab9a41026..e20e40f2540f0d23b4215910637196cb0ad91959 100644 --- a/lib/libc/glibc/sysdeps/htl/libc-lockP.h +++ b/lib/libc/glibc/sysdeps/htl/libc-lockP.h @@ -21,6 +21,20 @@ #include +typedef pthread_rwlock_t __libc_rwlock_t; + +#define __libc_rwlock_define(CLASS,NAME) \ + CLASS __libc_rwlock_t NAME; +#define __libc_rwlock_define_initialized(CLASS,NAME) \ + CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER; +#define __libc_rwlock_init(NAME) __pthread_rwlock_init (&(NAME), NULL) +#define __libc_rwlock_fini(NAME) ((void) 0) +#define __libc_rwlock_rdlock(NAME) __pthread_rwlock_rdlock (&(NAME)) +#define __libc_rwlock_wrlock(NAME) __pthread_rwlock_wrlock (&(NAME)) +#define __libc_rwlock_tryrdlock(NAME) __pthread_rwlock_tryrdlock (&(NAME)) +#define __libc_rwlock_trywrlock(NAME) __pthread_rwlock_trywrlock (&(NAME)) +#define __libc_rwlock_unlock(NAME) __pthread_rwlock_unlock (&(NAME)) + /* If we check for a weakly referenced symbol and then perform a normal jump to it te code generated for some platforms in case of PIC is unnecessarily slow. What would happen is that the function diff --git a/lib/libc/glibc/sysdeps/loongarch/start.S b/lib/libc/glibc/sysdeps/loongarch/start.S index 72452f5307ef430c06fd5852190c68d5f1295366..7be47a034df972d645cd6bd4a09afa0c450f5ca2 100644 --- a/lib/libc/glibc/sysdeps/loongarch/start.S +++ b/lib/libc/glibc/sysdeps/loongarch/start.S @@ -36,6 +36,7 @@ #define __ASSEMBLY__ 1 #include #include +#include /* The entry point's job is to call __libc_start_main. Per the ABI, a0 contains the address of a function to be passed to atexit. @@ -57,23 +58,32 @@ ENTRY (ENTRY_POINT) /* Terminate call stack by noting ra is undefined. Use a dummy .cfi_label to force starting the FDE. */ .cfi_label .Ldummy - cfi_undefined (1) + cfi_undefined (1) or a5, a0, zero /* rtld_fini */ - la.pcrel a0, t0, main +#if defined PIC && !defined SHARED + /* Avoid relocation in static PIE since _start is called before it + is relocated. */ + la.pcrel a0, __wrap_main +#else + LA_GOT (a0, main) +#endif + REG_L a1, sp, 0 ADDI a2, sp, SZREG - /* Adjust $sp for 16-aligned */ - BSTRINS sp, zero, 3, 0 + /* Adjust $sp for 16-bytes aligned */ + REG_ALIGN_ASM (sp, 4) move a3, zero /* used to be init */ move a4, zero /* used to be fini */ or a6, sp, zero /* stack_end */ - la.pcrel ra, t0, __libc_start_main - jirl ra, ra, 0 + CALL (__libc_start_main) + CALL (abort) - la.pcrel ra, t0, abort - jirl ra, ra, 0 +#if defined PIC && !defined SHARED +__wrap_main: + TAIL (main) +#endif END (ENTRY_POINT) diff --git a/lib/libc/glibc/sysdeps/loongarch/sys/asm.h b/lib/libc/glibc/sysdeps/loongarch/sys/asm.h new file mode 100644 index 0000000000000000000000000000000000000000..de44aacfa411fc9f6be2ddcd64acea0a75117cea --- /dev/null +++ b/lib/libc/glibc/sysdeps/loongarch/sys/asm.h @@ -0,0 +1,104 @@ +/* Miscellaneous macros. + Copyright (C) 2022-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#ifndef _SYS_ASM_H +#define _SYS_ASM_H + +#include +#include + +/* Macros to handle different pointer/register sizes for 32/64-bit code. */ +#if __loongarch_grlen == 64 +#define SZREG 8 +#define REG_L ld.d +#define REG_S st.d +#define SRLI srli.d +#define SLLI slli.d +#define ADDI addi.d +#define ADD add.d +#define SUB sub.d +#define LI li.d +#define BSTRINS bstrins.d + +#elif __loongarch_grlen == 32 + +#define SZREG 4 +#define REG_L ld.w +#define REG_S st.w +#define SRLI srli.w +#define SLLI slli.w +#define ADDI addi.w +#define ADD add.w +#define SUB sub.w +#define LI li.w +#define BSTRINS bstrins.w + +#else +#error __loongarch_grlen must equal 32 or 64 +#endif + +#if __loongarch_frlen == 64 + #define SZFREG 8 + #define FREG_L fld.d + #define FREG_S fst.d +#elif __loongarch_frlen == 32 + #define SZFREG 4 + #define FREG_L fld.s + #define FREG_S fst.s +#endif + +#define SZVREG 16 +#define SZXREG 32 + +/* Declare leaf routine. + The usage of macro LEAF/ENTRY is as follows: + 1. LEAF(fcn) -- the align value of fcn is .align 3 (default value) + 2. LEAF(fcn, 6) -- the align value of fcn is .align 6 +*/ +#define LEAF_IMPL(symbol, aln, ...) \ + .text; \ + .globl symbol; \ + .align aln; \ + .type symbol, @function; \ +symbol: \ + cfi_startproc; + + +#define LEAF(...) LEAF_IMPL(__VA_ARGS__, 3) +#define ENTRY(...) LEAF(__VA_ARGS__) + +#define LEAF_NO_ALIGN(symbol) \ + .text; \ + .globl symbol; \ + .type symbol, @function; \ +symbol: \ + cfi_startproc; + +#define ENTRY_NO_ALIGN(symbol) LEAF_NO_ALIGN(symbol) + + +/* Mark end of function. */ +#undef END +#define END(function) \ + cfi_endproc; \ + .size function, .- function; + +/* Stack alignment. */ +#define ALMASK ~15 + +#endif /* sys/asm.h */ diff --git a/lib/libc/glibc/sysdeps/loongarch/sysdep.h b/lib/libc/glibc/sysdeps/loongarch/sysdep.h new file mode 100644 index 0000000000000000000000000000000000000000..d5fc0b08633b383c8bbcb9e0213c214d9a141c3b --- /dev/null +++ b/lib/libc/glibc/sysdeps/loongarch/sysdep.h @@ -0,0 +1,94 @@ +/* Macros for LoongArch. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#ifndef _LOONGARCH_SYSDEP_H +#define _LOONGARCH_SYSDEP_H + +#if __loongarch_grlen == 64 + +#define PTRLOG 3 +/* Align reg to 2^n. Used in C. */ +#define REG_ALIGN_C(reg, n) \ + "bstrins.d\t" __STRING(reg) ", $zero, (" __STRING(n) "-1), 0" + +#elif __loongarch_grlen == 32 + +#define PTRLOG 2 +#define REG_ALIGN_C(reg, n) \ + "srli.w\t" __STRING(reg)", " __STRING(reg)", " __STRING(n) "\n\t" \ + "slli.w\t" __STRING(reg)", " __STRING(reg)", " __STRING(n) + +#else +#error __loongarch_grlen must equal 32 or 64 +#endif + +#ifdef __ASSEMBLER__ + +/* Stack alignment bytes. */ +#define STACK_ALIGN 16 + +/* Macros to handle different pointer/register sizes for 32/64-bit code. */ +#if __loongarch_grlen == 64 +#define SRAI srai.d + +/* Align reg to 2^n. Used in assembly. */ +#define REG_ALIGN_ASM(reg, n) bstrins.d reg, zero, (n-1), 0 + +#define LOAD_LOCAL(reg, sym) \ + pcalau12i reg, %pc_hi20(sym); \ + ld.d reg, reg, %pc_lo12(sym); + +#define LOAD_GLOBAL(reg, sym) \ + la.got reg, sym; \ + ld.d reg, reg, 0; + +#define LA_GOT(reg, sym) la.got reg, t0, sym + +#define CALL(sym) call36 sym +#define TAIL(sym) tail36 t0, sym + +#elif __loongarch_grlen == 32 /* __loongarch_grlen == 64 */ + +#define SRAI srai.w + +/* LA32R not have bstrins.w, use srli.w and slli.w on both LA32S and LA32R. */ +#define REG_ALIGN_ASM(reg, n) \ + srli.w reg, reg, n; \ + slli.w reg, reg, n; + +#define LOAD_LOCAL(reg, sym) \ + 1: pcaddu12i reg, %pcadd_hi20(sym); \ + ld.w reg, reg, %pcadd_lo12(1b); + +#define LOAD_GLOBAL(reg, sym) \ + 1: pcaddu12i reg, %got_pcadd_hi20(sym); \ + ld.w reg, reg, %pcadd_lo12(1b); \ + ld.w reg, reg, 0; + +#define LA_GOT(reg, sym) la.got reg, sym + +#define CALL(sym) call30 sym +#define TAIL(sym) tail30 t0, sym + +#else /* __loongarch_grlen == 64 */ +#error __loongarch_grlen must equal 32 or 64 +#endif /* __loongarch_grlen == 64 */ + +#endif /* __ASSEMBLER__ */ + +#endif /* _LOONGARCH_SYSDEP_H */ diff --git a/lib/libc/glibc/sysdeps/mach/libc-lock.h b/lib/libc/glibc/sysdeps/mach/libc-lock.h index 236a24ad807ea292bb25258d64ffb5658f5ddcf5..c5c67ccf9daa2fc5a02b63321f9fcdcf4617ec59 100644 --- a/lib/libc/glibc/sysdeps/mach/libc-lock.h +++ b/lib/libc/glibc/sysdeps/mach/libc-lock.h @@ -145,16 +145,16 @@ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; #define __rtld_lock_unlock_recursive(NAME) \ __libc_lock_unlock_recursive (NAME) -/* XXX for now */ -#define __libc_rwlock_define __libc_lock_define -#define __libc_rwlock_define_initialized __libc_lock_define_initialized -#define __libc_rwlock_init __libc_lock_init -#define __libc_rwlock_fini __libc_lock_fini -#define __libc_rwlock_rdlock __libc_lock_lock -#define __libc_rwlock_wrlock __libc_lock_lock -#define __libc_rwlock_tryrdlock __libc_lock_trylock -#define __libc_rwlock_trywrlock __libc_lock_trylock -#define __libc_rwlock_unlock __libc_lock_unlock +/* XXX for now, waiting for a futex-based pthread_rwlock implementation */ +#define __mach_rwlock_define __libc_lock_define +#define __mach_rwlock_define_initialized __libc_lock_define_initialized +#define __mach_rwlock_init __libc_lock_init +#define __mach_rwlock_fini __libc_lock_fini +#define __mach_rwlock_rdlock __libc_lock_lock +#define __mach_rwlock_wrlock __libc_lock_lock +#define __mach_rwlock_tryrdlock __libc_lock_trylock +#define __mach_rwlock_trywrlock __libc_lock_trylock +#define __mach_rwlock_unlock __libc_lock_unlock struct __libc_cleanup_frame { diff --git a/lib/libc/glibc/sysdeps/s390/s390-64/start-2.33.S b/lib/libc/glibc/sysdeps/s390/s390-64/start-2.33.S deleted file mode 100644 index 02ed4aad512752f7299f9eef82763de8db9a8349..0000000000000000000000000000000000000000 --- a/lib/libc/glibc/sysdeps/s390/s390-64/start-2.33.S +++ /dev/null @@ -1,107 +0,0 @@ -/* Startup code compliant to the 64 bit S/390 ELF ABI. - Copyright (C) 2001-2020 Free Software Foundation, Inc. - Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - In addition to the permissions in the GNU Lesser General Public - License, the Free Software Foundation gives you unlimited - permission to link the compiled version of this file with other - programs, and to distribute those programs without any restriction - coming from the use of this file. (The GNU Lesser General Public - License restrictions do apply in other respects; for example, they - cover modification of the file, and distribution when not linked - into another program.) - - Note that people who make modified versions of this file are not - obligated to grant this special exception for their modified - versions; it is their choice whether to do so. The GNU Lesser - General Public License gives permission to release a modified - version without this exception; this exception also makes it - possible to release a modified version which carries forward this - exception. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include - -/* - This is the canonical entry point, usually the first thing in the text - segment. Most registers' values are unspecified, except for: - - %r14 Contains a function pointer to be registered with `atexit'. - This is how the dynamic linker arranges to have DT_FINI - functions called for shared libraries that have been loaded - before this code runs. - - %r15 The stack contains the arguments and environment: - 0(%r15) argc - 8(%r15) argv[0] - ... - (8*argc)(%r15) NULL - (8*(argc+1))(%r15) envp[0] - ... - NULL -*/ - - .text - .globl _start - .type _start,@function -_start: - cfi_startproc - /* Mark r14 as undefined in order to stop unwinding here! */ - cfi_undefined (r14) - /* Load argc and argv from stack. */ - la %r4,8(%r15) # get argv - lg %r3,0(%r15) # get argc - - /* Align the stack to a double word boundary. */ - lghi %r0,-16 - ngr %r15,%r0 - - /* Setup a stack frame and a parameter area. */ - aghi %r15,-176 # make room on stack - xc 0(8,%r15),0(%r15) # clear back-chain - - /* Set up arguments for __libc_start_main: - main, argc, argv, envp, _init, _fini, rtld_fini, stack_end - Note that envp will be determined later in __libc_start_main. - */ - stmg %r14,%r15,160(%r15) # store rtld_fini/stack_end to parameter area - la %r7,160(%r15) - larl %r6,__libc_csu_fini # load pointer to __libc_csu_fini - larl %r5,__libc_csu_init # load pointer to __libc_csu_init - - /* Ok, now branch to the libc main routine. */ -#ifdef PIC - larl %r2,main@GOTENT # load pointer to main - lg %r2,0(%r2) - brasl %r14,__libc_start_main@plt -#else - larl %r2,main # load pointer to main - brasl %r14,__libc_start_main -#endif - - /* Crash if __libc_start_main returns. */ - .word 0 - - cfi_endproc - - /* Define a symbol for the first piece of initialized data. */ - .data - .globl __data_start -__data_start: - .long 0 - .weak data_start - data_start = __data_start diff --git a/lib/libc/glibc/sysdeps/s390/s390-64/start.S b/lib/libc/glibc/sysdeps/s390/s390-64/start.S deleted file mode 100644 index b555503811657b26de5fef1ea9d1feaaea66e359..0000000000000000000000000000000000000000 --- a/lib/libc/glibc/sysdeps/s390/s390-64/start.S +++ /dev/null @@ -1,134 +0,0 @@ -/* Startup code compliant to the 64 bit S/390 ELF ABI. - Copyright (C) 2001-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - In addition to the permissions in the GNU Lesser General Public - License, the Free Software Foundation gives you unlimited - permission to link the compiled version of this file with other - programs, and to distribute those programs without any restriction - coming from the use of this file. (The GNU Lesser General Public - License restrictions do apply in other respects; for example, they - cover modification of the file, and distribution when not linked - into another program.) - - Note that people who make modified versions of this file are not - obligated to grant this special exception for their modified - versions; it is their choice whether to do so. The GNU Lesser - General Public License gives permission to release a modified - version without this exception; this exception also makes it - possible to release a modified version which carries forward this - exception. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include - -/* - This is the canonical entry point, usually the first thing in the text - segment. Most registers' values are unspecified, except for: - - %r14 Contains a function pointer to be registered with `atexit'. - This is how the dynamic linker arranges to have DT_FINI - functions called for shared libraries that have been loaded - before this code runs. - - %r15 The stack contains the arguments and environment: - 0(%r15) argc - 8(%r15) argv[0] - ... - (8*argc)(%r15) NULL - (8*(argc+1))(%r15) envp[0] - ... - NULL -*/ - - .text - .globl _start - .type _start,@function -_start: - cfi_startproc - /* Mark r14 as undefined in order to stop unwinding here! */ - cfi_undefined (r14) - /* Load argc and argv from stack. */ - la %r4,8(%r15) # get argv - lg %r3,0(%r15) # get argc - - /* Align the stack to a double word boundary. */ - lghi %r0,-16 - ngr %r15,%r0 - - /* Setup a stack frame and a parameter area. */ - aghi %r15,-176 # make room on stack - xc 0(8,%r15),0(%r15) # clear back-chain - - /* Set up arguments for __libc_start_main: - main, argc, argv, envp, _init, _fini, rtld_fini, stack_end - Note that envp will be determined later in __libc_start_main. - */ - stmg %r14,%r15,160(%r15) # store rtld_fini/stack_end to parameter area - la %r7,160(%r15) - lghi %r6,0 # Used to be fini. - lghi %r5,0 # Used to be init. - - /* Ok, now branch to the libc main routine. */ -#ifdef PIC -# ifdef SHARED - /* Used for dynamic linked position independent executable. - => Scrt1.o */ - larl %r2,main@GOTENT # load pointer to main - lg %r2,0(%r2) -# else - /* Used for dynamic linked position dependent executable. - => crt1.o (glibc configured without --disable-default-pie: - PIC is defined) - Or for static linked position independent executable. - => rcrt1.o (only available if glibc configured without - --disable-default-pie: PIC is defined) */ - larl %r2,__wrap_main -# endif - brasl %r14,__libc_start_main@plt -#else - /* Used for dynamic/static linked position dependent executable. - => crt1.o (glibc configured with --disable-default-pie: - PIC and SHARED are not defined) */ - larl %r2,main # load pointer to main - brasl %r14,__libc_start_main -#endif - - /* Crash if __libc_start_main returns. */ - .word 0 - - cfi_endproc - -#if defined PIC && !defined SHARED - /* When main is not defined in the executable but in a shared library - then a wrapper is needed in crt1.o of the static-pie enabled libc, - because crt1.o and rcrt1.o share code and the later must avoid the - use of GOT relocations before __libc_start_main is called. */ -__wrap_main: - cfi_startproc - larl %r1,main@GOTENT # load pointer to main - lg %r1,0(%r1) - br %r1 - cfi_endproc -#endif - - /* Define a symbol for the first piece of initialized data. */ - .data - .globl __data_start -__data_start: - .long 0 - .weak data_start - data_start = __data_start diff --git a/lib/libc/glibc/sysdeps/s390/s390-64/sysdep.h b/lib/libc/glibc/sysdeps/s390/s390-64/sysdep.h deleted file mode 100644 index 18ed5f1b039fe6555493d8e230918bf24a41a2bb..0000000000000000000000000000000000000000 --- a/lib/libc/glibc/sysdeps/s390/s390-64/sysdep.h +++ /dev/null @@ -1,93 +0,0 @@ -/* Assembler macros for 64 bit S/390. - Copyright (C) 2001-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include - -#ifdef __ASSEMBLER__ - -/* Syntactic details of assembler. */ - -/* ELF uses byte-counts for .align, most others use log2 of count of bytes. */ -#define ALIGNARG(log2) 1<. */ + +#include + +/* + This is the canonical entry point, usually the first thing in the text + segment. Most registers' values are unspecified, except for: + + %r14 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + %r15 The stack contains the arguments and environment: + 0(%r15) argc + 8(%r15) argv[0] + ... + (8*argc)(%r15) NULL + (8*(argc+1))(%r15) envp[0] + ... + NULL +*/ + + .text + .globl _start + .type _start,@function +_start: + cfi_startproc + /* Mark r14 as undefined in order to stop unwinding here! */ + cfi_undefined (r14) + /* Load argc and argv from stack. */ + la %r4,8(%r15) # get argv + lg %r3,0(%r15) # get argc + + /* Align the stack to a double word boundary. */ + lghi %r0,-16 + ngr %r15,%r0 + + /* Setup a stack frame and a parameter area. */ + aghi %r15,-176 # make room on stack + xc 0(8,%r15),0(%r15) # clear back-chain + + /* Set up arguments for __libc_start_main: + main, argc, argv, envp, _init, _fini, rtld_fini, stack_end + Note that envp will be determined later in __libc_start_main. + */ + stmg %r14,%r15,160(%r15) # store rtld_fini/stack_end to parameter area + la %r7,160(%r15) + larl %r6,__libc_csu_fini # load pointer to __libc_csu_fini + larl %r5,__libc_csu_init # load pointer to __libc_csu_init + + /* Ok, now branch to the libc main routine. */ +#ifdef PIC + larl %r2,main@GOTENT # load pointer to main + lg %r2,0(%r2) + brasl %r14,__libc_start_main@plt +#else + larl %r2,main # load pointer to main + brasl %r14,__libc_start_main +#endif + + /* Crash if __libc_start_main returns. */ + .word 0 + + cfi_endproc + + /* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/lib/libc/glibc/sysdeps/s390/start.S b/lib/libc/glibc/sysdeps/s390/start.S new file mode 100644 index 0000000000000000000000000000000000000000..b555503811657b26de5fef1ea9d1feaaea66e359 --- /dev/null +++ b/lib/libc/glibc/sysdeps/s390/start.S @@ -0,0 +1,134 @@ +/* Startup code compliant to the 64 bit S/390 ELF ABI. + Copyright (C) 2001-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +/* + This is the canonical entry point, usually the first thing in the text + segment. Most registers' values are unspecified, except for: + + %r14 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + %r15 The stack contains the arguments and environment: + 0(%r15) argc + 8(%r15) argv[0] + ... + (8*argc)(%r15) NULL + (8*(argc+1))(%r15) envp[0] + ... + NULL +*/ + + .text + .globl _start + .type _start,@function +_start: + cfi_startproc + /* Mark r14 as undefined in order to stop unwinding here! */ + cfi_undefined (r14) + /* Load argc and argv from stack. */ + la %r4,8(%r15) # get argv + lg %r3,0(%r15) # get argc + + /* Align the stack to a double word boundary. */ + lghi %r0,-16 + ngr %r15,%r0 + + /* Setup a stack frame and a parameter area. */ + aghi %r15,-176 # make room on stack + xc 0(8,%r15),0(%r15) # clear back-chain + + /* Set up arguments for __libc_start_main: + main, argc, argv, envp, _init, _fini, rtld_fini, stack_end + Note that envp will be determined later in __libc_start_main. + */ + stmg %r14,%r15,160(%r15) # store rtld_fini/stack_end to parameter area + la %r7,160(%r15) + lghi %r6,0 # Used to be fini. + lghi %r5,0 # Used to be init. + + /* Ok, now branch to the libc main routine. */ +#ifdef PIC +# ifdef SHARED + /* Used for dynamic linked position independent executable. + => Scrt1.o */ + larl %r2,main@GOTENT # load pointer to main + lg %r2,0(%r2) +# else + /* Used for dynamic linked position dependent executable. + => crt1.o (glibc configured without --disable-default-pie: + PIC is defined) + Or for static linked position independent executable. + => rcrt1.o (only available if glibc configured without + --disable-default-pie: PIC is defined) */ + larl %r2,__wrap_main +# endif + brasl %r14,__libc_start_main@plt +#else + /* Used for dynamic/static linked position dependent executable. + => crt1.o (glibc configured with --disable-default-pie: + PIC and SHARED are not defined) */ + larl %r2,main # load pointer to main + brasl %r14,__libc_start_main +#endif + + /* Crash if __libc_start_main returns. */ + .word 0 + + cfi_endproc + +#if defined PIC && !defined SHARED + /* When main is not defined in the executable but in a shared library + then a wrapper is needed in crt1.o of the static-pie enabled libc, + because crt1.o and rcrt1.o share code and the later must avoid the + use of GOT relocations before __libc_start_main is called. */ +__wrap_main: + cfi_startproc + larl %r1,main@GOTENT # load pointer to main + lg %r1,0(%r1) + br %r1 + cfi_endproc +#endif + + /* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/lib/libc/glibc/sysdeps/s390/sysdep.h b/lib/libc/glibc/sysdeps/s390/sysdep.h new file mode 100644 index 0000000000000000000000000000000000000000..18ed5f1b039fe6555493d8e230918bf24a41a2bb --- /dev/null +++ b/lib/libc/glibc/sysdeps/s390/sysdep.h @@ -0,0 +1,93 @@ +/* Assembler macros for 64 bit S/390. + Copyright (C) 2001-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#ifdef __ASSEMBLER__ + +/* Syntactic details of assembler. */ + +/* ELF uses byte-counts for .align, most others use log2 of count of bytes. */ +#define ALIGNARG(log2) 1< #include #include #include @@ -34,9 +35,9 @@ #undef PSEUDO #define PSEUDO(name, syscall_name, args) \ ENTRY (name); \ - li.d a7, SYS_ify (syscall_name); \ + LI a7, SYS_ify (syscall_name); \ syscall 0; \ - li.d a7, -4096; \ + LI a7, -4096; \ bltu a7, a0, .Lsyscall_error##name; #undef PSEUDO_END @@ -52,16 +53,16 @@ .Lsyscall_error##name : la t0, rtld_errno; \ sub.w a0, zero, a0; \ st.w a0, t0, 0; \ - li.d a0, -1; + LI a0, -1; #else #define SYSCALL_ERROR_HANDLER(name) \ .Lsyscall_error##name : la.tls.ie t0, errno; \ - add.d t0, tp, t0; \ + ADD t0, tp, t0; \ sub.w a0, zero, a0; \ st.w a0, t0, 0; \ - li.d a0, -1; + LI a0, -1; #endif #else @@ -74,7 +75,7 @@ #undef PSEUDO_NEORRNO #define PSEUDO_NOERRNO(name, syscall_name, args) \ ENTRY (name); \ - li.d a7, SYS_ify (syscall_name); \ + LI a7, SYS_ify (syscall_name); \ syscall 0; #undef PSEUDO_END_NOERRNO @@ -85,11 +86,17 @@ /* Performs a system call, returning the error code. */ #undef PSEUDO_ERRVAL +#if __loongarch_grlen == 64 #define PSEUDO_ERRVAL(name, syscall_name, args) \ PSEUDO_NOERRNO (name, syscall_name, args); \ slli.d a0, a0, 32; \ srai.d a0, a0, 32; /* sign_ext */ \ sub.d a0, zero, a0; +#else +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + PSEUDO_NOERRNO (name, syscall_name, args); \ + sub.w a0, zero, a0; +#endif #undef PSEUDO_END_ERRVAL #define PSEUDO_END_ERRVAL(name) END (name); @@ -109,6 +116,18 @@ #undef SYS_ify #define SYS_ify(syscall_name) __NR_##syscall_name +#if __WORDSIZE == 32 +/* Workarounds for generic code needing to handle 64-bit time_t. */ +#define __NR_clock_getres __NR_clock_getres_time64 +#define __NR_futex __NR_futex_time64 +#define __NR_ppoll __NR_ppoll_time64 +#define __NR_pselect6 __NR_pselect6_time64 +#define __NR_recvmmsg __NR_recvmmsg_time64 +#define __NR_rt_sigtimedwait __NR_rt_sigtimedwait_time64 +#define __NR_semtimedop __NR_semtimedop_time64 +#define __NR_utimensat __NR_utimensat_time64 +#endif /* __WORDSIZE == 32 */ + #ifndef __ASSEMBLER__ #define VDSO_NAME "LINUX_5.10" diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/bits/typesizes.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/bits/typesizes.h index 826a1e425c1a2b3b1ee712643d53284412275bfa..6e2be2270f3ef2352418c9ca49af32ecd9e1f9ca 100644 --- a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/bits/typesizes.h +++ b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/bits/typesizes.h @@ -57,42 +57,34 @@ #define __TIMER_T_TYPE void * #define __BLKSIZE_T_TYPE __SLONGWORD_TYPE #define __FSID_T_TYPE struct { int __val[2]; } -#if defined __GNUC__ && __GNUC__ <= 2 -/* Compatibility with g++ 2.95.x. */ -#define __SSIZE_T_TYPE __SWORD_TYPE -#else -/* size_t is unsigned long int on s390 -m31. */ -#define __SSIZE_T_TYPE __SLONGWORD_TYPE -#endif + +/* With s390-32, __SSIZE_T_TYPE was __SWORD_TYPE for compatibility with + g++ 2.95.x. Afterwards __SLONGWORD_TYPE was needed as size_t was + unsigned long int on s390-32. + Now as only s390-64 exists, __SWORD_TYPE can be used as also used in the + generic version as both types result in long int. */ +#define __SSIZE_T_TYPE __SWORD_TYPE + #define __SYSCALL_SLONG_TYPE __SLONGWORD_TYPE #define __SYSCALL_ULONG_TYPE __ULONGWORD_TYPE -#define __CPU_MASK_TYPE __ULONGWORD_TYPE +#define __CPU_MASK_TYPE __ULONGWORD_TYPE -#ifdef __s390x__ /* Tell the libc code that off_t and off64_t are actually the same type for all ABI purposes, even if possibly expressed as different base types for C type-checking purposes. */ -# define __OFF_T_MATCHES_OFF64_T 1 +#define __OFF_T_MATCHES_OFF64_T 1 /* Same for ino_t and ino64_t. */ -# define __INO_T_MATCHES_INO64_T 1 +#define __INO_T_MATCHES_INO64_T 1 /* And for __rlim_t and __rlim64_t. */ -# define __RLIM_T_MATCHES_RLIM64_T 1 +#define __RLIM_T_MATCHES_RLIM64_T 1 /* And for fsblkcnt_t, fsblkcnt64_t, fsfilcnt_t and fsfilcnt64_t. */ -# define __STATFS_MATCHES_STATFS64 1 +#define __STATFS_MATCHES_STATFS64 1 /* And for getitimer, setitimer and rusage */ -# define __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64 1 -#else -# define __RLIM_T_MATCHES_RLIM64_T 0 - -# define __STATFS_MATCHES_STATFS64 0 - -/* And for getitimer, setitimer and rusage */ -# define __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64 0 -#endif +#define __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64 1 /* Number of descriptors that can fit in an `fd_set'. */ #define __FD_SETSIZE 1024 diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/kernel-features.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/kernel-features.h index a955c18738ad557e51a261b279eb2e3111870924..d7af29285fc538b2deda44f9aab98e5fcb60fef1 100644 --- a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/kernel-features.h +++ b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/kernel-features.h @@ -47,9 +47,6 @@ # undef __ASSUME_DIRECT_SYSVIPC_SYSCALLS # undef __ASSUME_SYSVIPC_DEFAULT_IPC_64 #endif -#ifndef __s390x__ -# define __ASSUME_SYSVIPC_BROKEN_MODE_T -#endif #undef __ASSUME_CLONE_DEFAULT #define __ASSUME_CLONE_BACKWARDS2 diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h deleted file mode 100644 index 9c9e2a271f57c5ce5d2efef9fc23c36ea55da6ac..0000000000000000000000000000000000000000 --- a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h +++ /dev/null @@ -1,178 +0,0 @@ -/* Assembler macros for 64 bit S/390. - Copyright (C) 2001-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _LINUX_S390_SYSDEP_H -#define _LINUX_S390_SYSDEP_H - -#include -#include -#include -#include -#include /* For RTLD_PRIVATE_ERRNO. */ -#include - -/* For Linux we can use the system call table in the header file - /usr/include/asm/unistd.h - of the kernel. But these symbols do not follow the SYS_* syntax - so we have to redefine the `SYS_ify' macro here. */ -/* In newer 2.1 kernels __NR_syscall is missing so we define it here. */ -#define __NR_syscall 0 - -#undef SYS_ify -#define SYS_ify(syscall_name) __NR_##syscall_name - -#ifdef __ASSEMBLER__ - -/* Linux uses a negative return value to indicate syscall errors, unlike - most Unices, which use the condition codes' carry flag. - - Since version 2.1 the return value of a system call might be negative - even if the call succeeded. E.g., the `lseek' system call might return - a large offset. Therefore we must not anymore test for < 0, but test - for a real error by making sure the value in gpr2 is a real error - number. Linus said he will make sure that no syscall returns a value - in -1 .. -4095 as a valid result so we can safely test with -4095. */ - -#undef PSEUDO -#define PSEUDO(name, syscall_name, args) \ - .text; \ - ENTRY (name) \ - DO_CALL (syscall_name, args); \ - lghi %r4,-4095 ; \ - clgr %r2,%r4 ; \ - jgnl SYSCALL_ERROR_LABEL - -#undef PSEUDO_END -#define PSEUDO_END(name) \ - SYSCALL_ERROR_HANDLER; \ - END (name) - -#undef PSEUDO_NOERRNO -#define PSEUDO_NOERRNO(name, syscall_name, args) \ - .text; \ - ENTRY (name) \ - DO_CALL (syscall_name, args) - -#undef PSEUDO_END_NOERRNO -#define PSEUDO_END_NOERRNO(name) \ - SYSCALL_ERROR_HANDLER; \ - END (name) - -#undef PSEUDO_ERRVAL -#define PSEUDO_ERRVAL(name, syscall_name, args) \ - .text; \ - ENTRY (name) \ - DO_CALL (syscall_name, args); \ - lcgr %r2,%r2 - -#undef PSEUDO_END_ERRVAL -#define PSEUDO_END_ERRVAL(name) \ - SYSCALL_ERROR_HANDLER; \ - END (name) - -#undef SYSCALL_ERROR_LABEL -#ifndef PIC -# undef SYSCALL_ERROR_LABEL -# define SYSCALL_ERROR_LABEL syscall_error -# define SYSCALL_ERROR_HANDLER -#else -# if RTLD_PRIVATE_ERRNO -# undef SYSCALL_ERROR_LABEL -# define SYSCALL_ERROR_LABEL 0f -# define SYSCALL_ERROR_HANDLER \ -0: larl %r1,rtld_errno; \ - lcr %r2,%r2; \ - st %r2,0(%r1); \ - lghi %r2,-1; \ - br %r14 -# elif defined _LIBC_REENTRANT -# if IS_IN (libc) -# define SYSCALL_ERROR_ERRNO __libc_errno -# else -# define SYSCALL_ERROR_ERRNO errno -# endif -# undef SYSCALL_ERROR_LABEL -# define SYSCALL_ERROR_LABEL 0f -# define SYSCALL_ERROR_HANDLER \ -0: lcr %r0,%r2; \ - larl %r1,SYSCALL_ERROR_ERRNO@indntpoff; \ - lg %r1,0(%r1); \ - ear %r2,%a0; \ - sllg %r2,%r2,32; \ - ear %r2,%a1; \ - st %r0,0(%r1,%r2); \ - lghi %r2,-1; \ - br %r14 -# else -# undef SYSCALL_ERROR_LABEL -# define SYSCALL_ERROR_LABEL 0f -# define SYSCALL_ERROR_HANDLER \ -0: larl %r1,_GLOBAL_OFFSET_TABLE_; \ - lg %r1,errno@GOT(%r1); \ - lcr %r2,%r2; \ - st %r2,0(%r1); \ - lghi %r2,-1; \ - br %r14 -# endif /* _LIBC_REENTRANT */ -#endif /* PIC */ - -/* Linux takes system call arguments in registers: - - syscall number 1 call-clobbered - arg 1 2 call-clobbered - arg 2 3 call-clobbered - arg 3 4 call-clobbered - arg 4 5 call-clobbered - arg 5 6 call-saved - arg 6 7 call-saved - - (Of course a function with say 3 arguments does not have entries for - arguments 4 and 5.) - For system calls with 6 parameters a stack operation is required - to load the 6th parameter to register 7. Call saved register 7 is - moved to register 0 and back to avoid an additional stack frame. - */ - -#define DO_CALL(syscall, args) \ - .if args > 5; \ - lgr %r0,%r7; \ - lg %r7,160(%r15); \ - .endif; \ - lghi %r1,SYS_ify (syscall); \ - svc 0; \ - .if args > 5; \ - lgr %r7,%r0; \ - .endif - -#define ret \ - br 14 - -#define ret_NOERRNO \ - br 14 - -#define ret_ERRVAL \ - br 14 - -#else - -# undef HAVE_INTERNAL_BRK_ADDR_SYMBOL -# define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1 - -#endif /* __ASSEMBLER__ */ - -#endif /* _LINUX_S390_SYSDEP_H */ diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/sysdep.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/sysdep.h index ee2d92edff1f0ee2fb8e0a25217e35dccbd0ff30..42fb8aa4692be8cd884dc9cb076b7c62412c03f0 100644 --- a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/sysdep.h +++ b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/sysdep.h @@ -1,5 +1,5 @@ -/* Syscall definitions, Linux s390 version. - Copyright (C) 2019-2026 Free Software Foundation, Inc. +/* Assembler macros for 64 bit S/390. + Copyright (C) 2001-2026 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -14,15 +14,163 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see - . */ + . */ -#ifndef __ASSEMBLY__ +#ifndef _LINUX_S390_SYSDEP_H +#define _LINUX_S390_SYSDEP_H + +#include +#include +#include +#include /* For RTLD_PRIVATE_ERRNO. */ +#include + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +/* In newer 2.1 kernels __NR_syscall is missing so we define it here. */ +#define __NR_syscall 0 #undef SYS_ify #define SYS_ify(syscall_name) __NR_##syscall_name -#undef INTERNAL_SYSCALL_NCS -#define INTERNAL_SYSCALL_NCS(no, nr, args...) \ +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, unlike + most Unices, which use the condition codes' carry flag. + + Since version 2.1 the return value of a system call might be negative + even if the call succeeded. E.g., the `lseek' system call might return + a large offset. Therefore we must not anymore test for < 0, but test + for a real error by making sure the value in gpr2 is a real error + number. Linus said he will make sure that no syscall returns a value + in -1 .. -4095 as a valid result so we can safely test with -4095. */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + lghi %r4,-4095 ; \ + clgr %r2,%r4 ; \ + jgnl SYSCALL_ERROR_LABEL + +# undef PSEUDO_END +# define PSEUDO_END(name) \ + SYSCALL_ERROR_HANDLER; \ + END (name) + +# undef PSEUDO_NOERRNO +# define PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args) + +# undef PSEUDO_END_NOERRNO +# define PSEUDO_END_NOERRNO(name) \ + SYSCALL_ERROR_HANDLER; \ + END (name) + +# undef PSEUDO_ERRVAL +# define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + lcgr %r2,%r2 + +# undef PSEUDO_END_ERRVAL +# define PSEUDO_END_ERRVAL(name) \ + SYSCALL_ERROR_HANDLER; \ + END (name) + +# undef SYSCALL_ERROR_LABEL +# ifndef PIC +# undef SYSCALL_ERROR_LABEL +# define SYSCALL_ERROR_LABEL syscall_error +# define SYSCALL_ERROR_HANDLER +# else +# if RTLD_PRIVATE_ERRNO +# undef SYSCALL_ERROR_LABEL +# define SYSCALL_ERROR_LABEL 0f +# define SYSCALL_ERROR_HANDLER \ +0: larl %r1,rtld_errno; \ + lcr %r2,%r2; \ + st %r2,0(%r1); \ + lghi %r2,-1; \ + br %r14 +# elif defined _LIBC_REENTRANT +# if IS_IN (libc) +# define SYSCALL_ERROR_ERRNO __libc_errno +# else +# define SYSCALL_ERROR_ERRNO errno +# endif +# undef SYSCALL_ERROR_LABEL +# define SYSCALL_ERROR_LABEL 0f +# define SYSCALL_ERROR_HANDLER \ +0: lcr %r0,%r2; \ + larl %r1,SYSCALL_ERROR_ERRNO@indntpoff; \ + lg %r1,0(%r1); \ + ear %r2,%a0; \ + sllg %r2,%r2,32; \ + ear %r2,%a1; \ + st %r0,0(%r1,%r2); \ + lghi %r2,-1; \ + br %r14 +# else +# undef SYSCALL_ERROR_LABEL +# define SYSCALL_ERROR_LABEL 0f +# define SYSCALL_ERROR_HANDLER \ +0: larl %r1,_GLOBAL_OFFSET_TABLE_; \ + lg %r1,errno@GOT(%r1); \ + lcr %r2,%r2; \ + st %r2,0(%r1); \ + lghi %r2,-1; \ + br %r14 +# endif /* _LIBC_REENTRANT */ +# endif /* PIC */ + +/* Linux takes system call arguments in registers: + + syscall number 1 call-clobbered + arg 1 2 call-clobbered + arg 2 3 call-clobbered + arg 3 4 call-clobbered + arg 4 5 call-clobbered + arg 5 6 call-saved + arg 6 7 call-saved + + (Of course a function with say 3 arguments does not have entries for + arguments 4 and 5.) + For system calls with 6 parameters a stack operation is required + to load the 6th parameter to register 7. Call saved register 7 is + moved to register 0 and back to avoid an additional stack frame. + */ + +# define DO_CALL(syscall, args) \ + .if args > 5; \ + lgr %r0,%r7; \ + lg %r7,160(%r15); \ + .endif; \ + lghi %r1,SYS_ify (syscall); \ + svc 0; \ + .if args > 5; \ + lgr %r7,%r0; \ + .endif + +# define ret \ + br 14 + +# define ret_NOERRNO \ + br 14 + +# define ret_ERRVAL \ + br 14 + +#else /* not __ASSEMBLER__ */ + +# undef INTERNAL_SYSCALL_NCS +# define INTERNAL_SYSCALL_NCS(no, nr, args...) \ ({ \ DECLARGS_##nr(args) \ register unsigned long int _nr __asm__("1") = (unsigned long int)(no); \ @@ -34,51 +182,52 @@ : "memory" ); \ _ret; }) -#undef INTERNAL_SYSCALL -#define INTERNAL_SYSCALL(name, nr, args...) \ +# undef INTERNAL_SYSCALL +# define INTERNAL_SYSCALL(name, nr, args...) \ INTERNAL_SYSCALL_NCS(__NR_##name, nr, args) -#define DECLARGS_0() -#define DECLARGS_1(arg1) \ +# define DECLARGS_0() +# define DECLARGS_1(arg1) \ register unsigned long int gpr2 __asm__ ("2") = (unsigned long int)(arg1); -#define DECLARGS_2(arg1, arg2) \ +# define DECLARGS_2(arg1, arg2) \ DECLARGS_1(arg1) \ register unsigned long int gpr3 __asm__ ("3") = (unsigned long int)(arg2); -#define DECLARGS_3(arg1, arg2, arg3) \ +# define DECLARGS_3(arg1, arg2, arg3) \ DECLARGS_2(arg1, arg2) \ register unsigned long int gpr4 __asm__ ("4") = (unsigned long int)(arg3); -#define DECLARGS_4(arg1, arg2, arg3, arg4) \ +# define DECLARGS_4(arg1, arg2, arg3, arg4) \ DECLARGS_3(arg1, arg2, arg3) \ register unsigned long int gpr5 __asm__ ("5") = (unsigned long int)(arg4); -#define DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \ +# define DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \ DECLARGS_4(arg1, arg2, arg3, arg4) \ register unsigned long int gpr6 __asm__ ("6") = (unsigned long int)(arg5); -#define DECLARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ +# define DECLARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \ register unsigned long int gpr7 __asm__ ("7") = (unsigned long int)(arg6); -#define ASMFMT_0 -#define ASMFMT_1 , "0" (gpr2) -#define ASMFMT_2 , "0" (gpr2), "d" (gpr3) -#define ASMFMT_3 , "0" (gpr2), "d" (gpr3), "d" (gpr4) -#define ASMFMT_4 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5) -#define ASMFMT_5 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6) -#define ASMFMT_6 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6), "d" (gpr7) +# define ASMFMT_0 +# define ASMFMT_1 , "0" (gpr2) +# define ASMFMT_2 , "0" (gpr2), "d" (gpr3) +# define ASMFMT_3 , "0" (gpr2), "d" (gpr3), "d" (gpr4) +# define ASMFMT_4 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5) +# define ASMFMT_5 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6) +# define ASMFMT_6 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6), "d" (gpr7) -#define VDSO_NAME "LINUX_2.6.29" -#define VDSO_HASH 123718585 +# define VDSO_NAME "LINUX_2.6.29" +# define VDSO_HASH 123718585 /* List of system calls which are supported as vsyscalls. */ -#ifdef __s390x__ -#define HAVE_CLOCK_GETRES64_VSYSCALL "__kernel_clock_getres" -#define HAVE_CLOCK_GETTIME64_VSYSCALL "__kernel_clock_gettime" -#define HAVE_GETRANDOM_VSYSCALL "__kernel_getrandom" -#else -#define HAVE_CLOCK_GETRES_VSYSCALL "__kernel_clock_getres" -#define HAVE_CLOCK_GETTIME_VSYSCALL "__kernel_clock_gettime" -#endif -#define HAVE_GETTIMEOFDAY_VSYSCALL "__kernel_gettimeofday" -#define HAVE_GETCPU_VSYSCALL "__kernel_getcpu" - -#define HAVE_CLONE3_WRAPPER 1 -#endif +# define HAVE_CLOCK_GETRES64_VSYSCALL "__kernel_clock_getres" +# define HAVE_CLOCK_GETTIME64_VSYSCALL "__kernel_clock_gettime" +# define HAVE_GETRANDOM_VSYSCALL "__kernel_getrandom" +# define HAVE_GETTIMEOFDAY_VSYSCALL "__kernel_gettimeofday" +# define HAVE_GETCPU_VSYSCALL "__kernel_getcpu" + +# define HAVE_CLONE3_WRAPPER 1 + +# undef HAVE_INTERNAL_BRK_ADDR_SYMBOL +# define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1 + +#endif /* __ASSEMBLER__ */ + +#endif /* _LINUX_S390_SYSDEP_H */ diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/xstatver.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/xstatver.h index 9923199e407ccd8c3c341695841bcc07802c0189..f24ab4a9ee158d7f0890cd228b20bf1e278d332b 100644 --- a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/xstatver.h +++ b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/xstatver.h @@ -1,19 +1,10 @@ /* Versions of the 'struct stat' data structure used in compatibility xstat functions. */ - -#include - -#if __WORDSIZE == 64 -# define _STAT_VER_KERNEL 0 -# define _STAT_VER_LINUX 1 -# define _MKNOD_VER_LINUX 0 -#else -# define _STAT_VER_LINUX_OLD 1 -# define _STAT_VER_KERNEL 1 -# define _STAT_VER_SVR4 2 -# define _STAT_VER_LINUX 3 -# define _MKNOD_VER_LINUX 1 -# define _MKNOD_VER_SVR4 2 -#endif +#define _STAT_VER_KERNEL 0 +#define _STAT_VER_LINUX 1 #define _STAT_VER _STAT_VER_LINUX + +/* Versions of the 'xmknod' interface used in compatibility xmknod + functions. */ +#define _MKNOD_VER_LINUX 0 #define _MKNOD_VER _MKNOD_VER_LINUX diff --git a/lib/libc/include/aarch64-linux-gnu/bits/hwcap.h b/lib/libc/include/aarch64-linux-gnu/bits/hwcap.h index f4189aa1bfca6909be4967e00821932faf753c7a..ea1c9e30bc803d6c5eb0396d62a46707ca7bdddd 100644 --- a/lib/libc/include/aarch64-linux-gnu/bits/hwcap.h +++ b/lib/libc/include/aarch64-linux-gnu/bits/hwcap.h @@ -55,6 +55,21 @@ #define HWCAP_PACA (1 << 30) #define HWCAP_PACG (1UL << 31) #define HWCAP_GCS (1UL << 32) +#define HWCAP_CMPBR (1UL << 33) +#define HWCAP_FPRCVT (1UL << 34) +#define HWCAP_F8MM8 (1UL << 35) +#define HWCAP_F8MM4 (1UL << 36) +#define HWCAP_SVE_F16MM (1UL << 37) +#define HWCAP_SVE_ELTPERM (1UL << 38) +#define HWCAP_SVE_AES2 (1UL << 39) +#define HWCAP_SVE_BFSCALE (1UL << 40) +#define HWCAP_SVE2P2 (1UL << 41) +#define HWCAP_SME2P2 (1UL << 42) +#define HWCAP_SME_SBITPERM (1UL << 43) +#define HWCAP_SME_AES (1UL << 44) +#define HWCAP_SME_SFEXPA (1UL << 45) +#define HWCAP_SME_STMOP (1UL << 46) +#define HWCAP_SME_SMOP4 (1UL << 47) #define HWCAP2_DCPODP (1 << 0) #define HWCAP2_SVE2 (1 << 1) @@ -122,4 +137,6 @@ #define HWCAP2_POE (1UL << 63) #define HWCAP3_MTE_FAR (1UL << 0) -#define HWCAP3_MTE_STORE_ONLY (1UL << 1) \ No newline at end of file +#define HWCAP3_MTE_STORE_ONLY (1UL << 1) +#define HWCAP3_LSFE (1UL << 2) +#define HWCAP3_LS64 (1UL << 3) \ No newline at end of file diff --git a/lib/libc/include/aarch64-linux-gnu/bits/long-double.h b/lib/libc/include/aarch64-linux-gnu/bits/long-double.h deleted file mode 100644 index af7784dbe6dd85cd9538b5a7b437ab45de22eeb8..0000000000000000000000000000000000000000 --- a/lib/libc/include/aarch64-linux-gnu/bits/long-double.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Properties of long double type. ldbl-128 version. - Copyright (C) 2016-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* long double is distinct from double, so there is nothing to - define here. */ -#define __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI 0 \ No newline at end of file diff --git a/lib/libc/include/aarch64-linux-gnu/bits/math-vector.h b/lib/libc/include/aarch64-linux-gnu/bits/math-vector.h index 68043a976c58a8f126799f7c386006471a4996eb..c83fbc235bcaefcba343ec5122af94a316e67c57 100644 --- a/lib/libc/include/aarch64-linux-gnu/bits/math-vector.h +++ b/lib/libc/include/aarch64-linux-gnu/bits/math-vector.h @@ -157,6 +157,10 @@ # define __DECL_SIMD_pow __DECL_SIMD_aarch64 # undef __DECL_SIMD_powf # define __DECL_SIMD_powf __DECL_SIMD_aarch64 +# undef __DECL_SIMD_powr +# define __DECL_SIMD_powr __DECL_SIMD_aarch64 +# undef __DECL_SIMD_powrf +# define __DECL_SIMD_powrf __DECL_SIMD_aarch64 # undef __DECL_SIMD_rsqrt # define __DECL_SIMD_rsqrt __DECL_SIMD_aarch64 # undef __DECL_SIMD_rsqrtf @@ -243,6 +247,7 @@ __vpcs __f32x4_t _ZGVnN4v_log2f (__f32x4_t); __vpcs __f32x4_t _ZGVnN4v_log2p1f (__f32x4_t); __vpcs __f32x4_t _ZGVnN4v_logp1f (__f32x4_t); __vpcs __f32x4_t _ZGVnN4vv_powf (__f32x4_t, __f32x4_t); +__vpcs __f32x4_t _ZGVnN4vv_powrf (__f32x4_t, __f32x4_t); __vpcs __f32x4_t _ZGVnN4v_rsqrtf (__f32x4_t); __vpcs __f32x4_t _ZGVnN4v_sinf (__f32x4_t); __vpcs __f32x4_t _ZGVnN4v_sinhf (__f32x4_t); @@ -283,6 +288,7 @@ __vpcs __f64x2_t _ZGVnN2v_log2 (__f64x2_t); __vpcs __f64x2_t _ZGVnN2v_log2p1 (__f64x2_t); __vpcs __f64x2_t _ZGVnN2v_logp1 (__f64x2_t); __vpcs __f64x2_t _ZGVnN2vv_pow (__f64x2_t, __f64x2_t); +__vpcs __f64x2_t _ZGVnN2vv_powr (__f64x2_t, __f64x2_t); __vpcs __f64x2_t _ZGVnN2v_rsqrt (__f64x2_t); __vpcs __f64x2_t _ZGVnN2v_sin (__f64x2_t); __vpcs __f64x2_t _ZGVnN2v_sinh (__f64x2_t); @@ -328,6 +334,7 @@ __sv_f32_t _ZGVsMxv_log2f (__sv_f32_t, __sv_bool_t); __sv_f32_t _ZGVsMxv_log2p1f (__sv_f32_t, __sv_bool_t); __sv_f32_t _ZGVsMxv_logp1f (__sv_f32_t, __sv_bool_t); __sv_f32_t _ZGVsMxvv_powf (__sv_f32_t, __sv_f32_t, __sv_bool_t); +__sv_f32_t _ZGVsMxvv_powrf (__sv_f32_t, __sv_f32_t, __sv_bool_t); __sv_f32_t _ZGVsMxv_rsqrtf (__sv_f32_t, __sv_bool_t); __sv_f32_t _ZGVsMxv_sinf (__sv_f32_t, __sv_bool_t); __sv_f32_t _ZGVsMxv_sinhf (__sv_f32_t, __sv_bool_t); @@ -368,6 +375,7 @@ __sv_f64_t _ZGVsMxv_log2 (__sv_f64_t, __sv_bool_t); __sv_f64_t _ZGVsMxv_log2p1 (__sv_f64_t, __sv_bool_t); __sv_f64_t _ZGVsMxv_logp1 (__sv_f64_t, __sv_bool_t); __sv_f64_t _ZGVsMxvv_pow (__sv_f64_t, __sv_f64_t, __sv_bool_t); +__sv_f64_t _ZGVsMxvv_powr (__sv_f64_t, __sv_f64_t, __sv_bool_t); __sv_f64_t _ZGVsMxv_rsqrt (__sv_f64_t, __sv_bool_t); __sv_f64_t _ZGVsMxv_sin (__sv_f64_t, __sv_bool_t); __sv_f64_t _ZGVsMxv_sinh (__sv_f64_t, __sv_bool_t); diff --git a/lib/libc/include/aarch64-linux-gnu/bits/struct_stat.h b/lib/libc/include/aarch64-linux-gnu/bits/struct_stat.h deleted file mode 100644 index 0462d37a6849812f485a6830a7c0dca303332636..0000000000000000000000000000000000000000 --- a/lib/libc/include/aarch64-linux-gnu/bits/struct_stat.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Definition for struct stat. - Copyright (C) 2020-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#if !defined _SYS_STAT_H && !defined _FCNTL_H -# error "Never include directly; use instead." -#endif - -#ifndef _BITS_STRUCT_STAT_H -#define _BITS_STRUCT_STAT_H 1 - -#include -#include - -#if defined __USE_FILE_OFFSET64 -# define __field64(type, type64, name) type64 name -#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T -# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T -# error "ino_t and off_t must both be the same type" -# endif -# define __field64(type, type64, name) type name -#elif __BYTE_ORDER == __LITTLE_ENDIAN -# define __field64(type, type64, name) \ - type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad -#else -# define __field64(type, type64, name) \ - int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name -#endif - -struct stat - { - __dev_t st_dev; /* Device. */ - __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; - -#undef __field64 - -#ifdef __USE_LARGEFILE64 -struct stat64 - { - __dev_t st_dev; /* Device. */ - __ino64_t st_ino; /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __off64_t st_size; /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; -#endif - -/* Tell code we have these members. */ -#define _STATBUF_ST_BLKSIZE -#define _STATBUF_ST_RDEV -/* Nanosecond resolution time values are supported. */ -#define _STATBUF_ST_NSEC - -#endif /* _BITS_STRUCT_STAT_H */ \ No newline at end of file diff --git a/lib/libc/include/aarch64-linux-gnu/bits/timesize.h b/lib/libc/include/aarch64-linux-gnu/bits/timesize.h deleted file mode 100644 index dff2da5ed6bf30ce6f5580aee352e0958d58b623..0000000000000000000000000000000000000000 --- a/lib/libc/include/aarch64-linux-gnu/bits/timesize.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Bit size of the time_t type at glibc build time, general case. - Copyright (C) 2018-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* Size in bits of the 'time_t' type of the default ABI. */ -#define __TIMESIZE 64 \ No newline at end of file diff --git a/lib/libc/include/aarch64-linux-gnu/finclude/math-vector-fortran.h b/lib/libc/include/aarch64-linux-gnu/finclude/math-vector-fortran.h index 59c7f2db4a8dfefe910714f9a659b8e61680df63..2af413c57c6ec176e65b5555ff2394df576a96c6 100644 --- a/lib/libc/include/aarch64-linux-gnu/finclude/math-vector-fortran.h +++ b/lib/libc/include/aarch64-linux-gnu/finclude/math-vector-fortran.h @@ -16,81 +16,83 @@ ! License along with the GNU C Library; if not, see ! . -!GCC$ builtin (acos) attributes simd (notinbranch) -!GCC$ builtin (acosf) attributes simd (notinbranch) -!GCC$ builtin (acosh) attributes simd (notinbranch) -!GCC$ builtin (acoshf) attributes simd (notinbranch) -!GCC$ builtin (acospi) attributes simd (notinbranch) -!GCC$ builtin (acospif) attributes simd (notinbranch) -!GCC$ builtin (asin) attributes simd (notinbranch) -!GCC$ builtin (asinf) attributes simd (notinbranch) -!GCC$ builtin (asinh) attributes simd (notinbranch) -!GCC$ builtin (asinhf) attributes simd (notinbranch) -!GCC$ builtin (asinpi) attributes simd (notinbranch) -!GCC$ builtin (asinpif) attributes simd (notinbranch) -!GCC$ builtin (atan) attributes simd (notinbranch) -!GCC$ builtin (atan2) attributes simd (notinbranch) -!GCC$ builtin (atan2f) attributes simd (notinbranch) -!GCC$ builtin (atan2pi) attributes simd (notinbranch) -!GCC$ builtin (atan2pif) attributes simd (notinbranch) -!GCC$ builtin (atanf) attributes simd (notinbranch) -!GCC$ builtin (atanh) attributes simd (notinbranch) -!GCC$ builtin (atanhf) attributes simd (notinbranch) -!GCC$ builtin (atanpi) attributes simd (notinbranch) -!GCC$ builtin (atanpif) attributes simd (notinbranch) -!GCC$ builtin (cbrt) attributes simd (notinbranch) -!GCC$ builtin (cbrtf) attributes simd (notinbranch) -!GCC$ builtin (cos) attributes simd (notinbranch) -!GCC$ builtin (cosf) attributes simd (notinbranch) -!GCC$ builtin (cosh) attributes simd (notinbranch) -!GCC$ builtin (coshf) attributes simd (notinbranch) -!GCC$ builtin (cospi) attributes simd (notinbranch) -!GCC$ builtin (cospif) attributes simd (notinbranch) -!GCC$ builtin (erf) attributes simd (notinbranch) -!GCC$ builtin (erfc) attributes simd (notinbranch) -!GCC$ builtin (erfcf) attributes simd (notinbranch) -!GCC$ builtin (erff) attributes simd (notinbranch) -!GCC$ builtin (exp) attributes simd (notinbranch) -!GCC$ builtin (exp10) attributes simd (notinbranch) -!GCC$ builtin (exp10f) attributes simd (notinbranch) -!GCC$ builtin (exp10m1) attributes simd (notinbranch) -!GCC$ builtin (exp10m1f) attributes simd (notinbranch) -!GCC$ builtin (exp2) attributes simd (notinbranch) -!GCC$ builtin (exp2f) attributes simd (notinbranch) -!GCC$ builtin (exp2m1) attributes simd (notinbranch) -!GCC$ builtin (exp2m1f) attributes simd (notinbranch) -!GCC$ builtin (expf) attributes simd (notinbranch) -!GCC$ builtin (expm1) attributes simd (notinbranch) -!GCC$ builtin (expm1f) attributes simd (notinbranch) -!GCC$ builtin (hypot) attributes simd (notinbranch) -!GCC$ builtin (hypotf) attributes simd (notinbranch) -!GCC$ builtin (log) attributes simd (notinbranch) -!GCC$ builtin (log10) attributes simd (notinbranch) -!GCC$ builtin (log10f) attributes simd (notinbranch) -!GCC$ builtin (log10p1) attributes simd (notinbranch) -!GCC$ builtin (log10p1f) attributes simd (notinbranch) -!GCC$ builtin (log1p) attributes simd (notinbranch) -!GCC$ builtin (log1pf) attributes simd (notinbranch) -!GCC$ builtin (log2) attributes simd (notinbranch) -!GCC$ builtin (log2f) attributes simd (notinbranch) -!GCC$ builtin (log2p1) attributes simd (notinbranch) -!GCC$ builtin (log2p1f) attributes simd (notinbranch) -!GCC$ builtin (logf) attributes simd (notinbranch) -!GCC$ builtin (logp1) attributes simd (notinbranch) -!GCC$ builtin (logp1f) attributes simd (notinbranch) -!GCC$ builtin (pow) attributes simd (notinbranch) -!GCC$ builtin (powf) attributes simd (notinbranch) -!GCC$ builtin (rsqrt) attributes simd (notinbranch) -!GCC$ builtin (rsqrtf) attributes simd (notinbranch) -!GCC$ builtin (sin) attributes simd (notinbranch) -!GCC$ builtin (sinf) attributes simd (notinbranch) -!GCC$ builtin (sinh) attributes simd (notinbranch) -!GCC$ builtin (sinhf) attributes simd (notinbranch) -!GCC$ builtin (sinpi) attributes simd (notinbranch) -!GCC$ builtin (sinpif) attributes simd (notinbranch) -!GCC$ builtin (tan) attributes simd (notinbranch) -!GCC$ builtin (tanf) attributes simd (notinbranch) -!GCC$ builtin (tanh) attributes simd (notinbranch) -!GCC$ builtin (tanhf) attributes simd (notinbranch) -!GCC$ builtin (tanpi) attributes simd (notinbranch) -!GCC$ builtin (tanpif) attributes simd (notinbranch) \ No newline at end of file +!GCC$ builtin (acos) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (acosf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (acosh) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (acoshf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (acospi) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (acospif) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (asin) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (asinf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (asinh) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (asinhf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (asinpi) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (asinpif) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atan) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atan2) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atan2f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atan2pi) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atan2pif) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atanf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atanh) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atanhf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atanpi) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (atanpif) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (cbrt) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (cbrtf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (cos) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (cosf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (cosh) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (coshf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (cospi) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (cospif) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (erf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (erfc) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (erfcf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (erff) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (exp) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (exp10) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (exp10f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (exp10m1) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (exp10m1f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (exp2) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (exp2f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (exp2m1) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (exp2m1f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (expf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (expm1) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (expm1f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (hypot) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (hypotf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log10) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log10f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log10p1) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log10p1f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log1p) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log1pf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log2) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log2f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log2p1) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (log2p1f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (logf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (logp1) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (logp1f) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (pow) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (powf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (powr) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (powrf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (rsqrt) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (rsqrtf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (sin) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (sinf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (sinh) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (sinhf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (sinpi) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (sinpif) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (tan) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (tanf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (tanh) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (tanhf) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (tanpi) attributes simd (notinbranch) if('fastmath') +!GCC$ builtin (tanpif) attributes simd (notinbranch) if('fastmath') \ No newline at end of file diff --git a/lib/libc/include/aarch64-linux-gnu/gnu/lib-names-lp64.h b/lib/libc/include/aarch64-linux-gnu/gnu/lib-names-lp64.h index e34eb75134323543b3d8d8807e0bc3c7a3c31abd..46acbc27479223aa3abfe70175255d2b346e9cac 100644 --- a/lib/libc/include/aarch64-linux-gnu/gnu/lib-names-lp64.h +++ b/lib/libc/include/aarch64-linux-gnu/gnu/lib-names-lp64.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/aarch64-linux-gnu/gnu/lib-names-lp64_be.h b/lib/libc/include/aarch64-linux-gnu/gnu/lib-names-lp64_be.h index 2fba436ba35ca351e3c28abeda69028774654a92..ad55fcf123ad4488d626ece14689abda37598381 100644 --- a/lib/libc/include/aarch64-linux-gnu/gnu/lib-names-lp64_be.h +++ b/lib/libc/include/aarch64-linux-gnu/gnu/lib-names-lp64_be.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/arc-linux-gnu/bits/struct_stat.h b/lib/libc/include/arc-linux-gnu/bits/struct_stat.h deleted file mode 100644 index 0462d37a6849812f485a6830a7c0dca303332636..0000000000000000000000000000000000000000 --- a/lib/libc/include/arc-linux-gnu/bits/struct_stat.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Definition for struct stat. - Copyright (C) 2020-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#if !defined _SYS_STAT_H && !defined _FCNTL_H -# error "Never include directly; use instead." -#endif - -#ifndef _BITS_STRUCT_STAT_H -#define _BITS_STRUCT_STAT_H 1 - -#include -#include - -#if defined __USE_FILE_OFFSET64 -# define __field64(type, type64, name) type64 name -#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T -# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T -# error "ino_t and off_t must both be the same type" -# endif -# define __field64(type, type64, name) type name -#elif __BYTE_ORDER == __LITTLE_ENDIAN -# define __field64(type, type64, name) \ - type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad -#else -# define __field64(type, type64, name) \ - int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name -#endif - -struct stat - { - __dev_t st_dev; /* Device. */ - __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; - -#undef __field64 - -#ifdef __USE_LARGEFILE64 -struct stat64 - { - __dev_t st_dev; /* Device. */ - __ino64_t st_ino; /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __off64_t st_size; /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; -#endif - -/* Tell code we have these members. */ -#define _STATBUF_ST_BLKSIZE -#define _STATBUF_ST_RDEV -/* Nanosecond resolution time values are supported. */ -#define _STATBUF_ST_NSEC - -#endif /* _BITS_STRUCT_STAT_H */ \ No newline at end of file diff --git a/lib/libc/include/arc-linux-gnu/bits/timesize.h b/lib/libc/include/arc-linux-gnu/bits/timesize.h deleted file mode 100644 index dff2da5ed6bf30ce6f5580aee352e0958d58b623..0000000000000000000000000000000000000000 --- a/lib/libc/include/arc-linux-gnu/bits/timesize.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Bit size of the time_t type at glibc build time, general case. - Copyright (C) 2018-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* Size in bits of the 'time_t' type of the default ABI. */ -#define __TIMESIZE 64 \ No newline at end of file diff --git a/lib/libc/include/arc-linux-gnu/gnu/lib-names.h b/lib/libc/include/arc-linux-gnu/gnu/lib-names.h index 68bed2a1a178f5003654ea064883559b08d5242e..5e617b3a49ddd6da357923e3cfdae83ef4a189fb 100644 --- a/lib/libc/include/arc-linux-gnu/gnu/lib-names.h +++ b/lib/libc/include/arc-linux-gnu/gnu/lib-names.h @@ -25,6 +25,7 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" #endif /* gnu/lib-names.h */ \ No newline at end of file diff --git a/lib/libc/include/csky-linux-gnu/gnu/lib-names.h b/lib/libc/include/csky-linux-gnu/gnu/lib-names.h index fbe1a718fbeb97c65267676396b656897ac0b648..f63e5133babbdfd1309f38fe281c0d29c1ef8a64 100644 --- a/lib/libc/include/csky-linux-gnu/gnu/lib-names.h +++ b/lib/libc/include/csky-linux-gnu/gnu/lib-names.h @@ -31,6 +31,7 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" -#endif /* gnu/lib-names.h */ +#endif /* gnu/lib-names.h */ \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/assert.h b/lib/libc/include/generic-glibc/assert.h index 73562fec4b9cf794aeb03cc1f3e4c5988eeb42cf..11c3cec04420eb0925d865ed489f911f4e29de37 100644 --- a/lib/libc/include/generic-glibc/assert.h +++ b/lib/libc/include/generic-glibc/assert.h @@ -52,13 +52,12 @@ comma in the initializer list, can be passed to assert. This depends on support for variadic macros (added in C99 and GCC 2.95), and on support for _Bool (added in C99 and GCC 3.0) in order to - validate that only a single expression is passed as an argument, - and is currently implemented only for C. */ -#if (__GLIBC_USE (ISOC23) \ - && (defined __GNUC__ \ - ? __GNUC_PREREQ (3, 0) \ - : defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) \ - && !defined __cplusplus) + validate that only a single expression is passed as an argument. */ +#if ((__GLIBC_USE (ISOC23) \ + && (defined __GNUC__ \ + ? __GNUC_PREREQ (3, 0) \ + : defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) \ + || (defined __cplusplus && __cplusplus > 202302L)) # define __ASSERT_VARIADIC 1 #else # define __ASSERT_VARIADIC 0 @@ -108,7 +107,7 @@ extern void __assert (const char *__assertion, const char *__file, int __line) __THROW __attribute__ ((__noreturn__)) __COLD; -# if __ASSERT_VARIADIC +# if __ASSERT_VARIADIC && !defined __cplusplus /* This function is not defined and is not called outside of an unevaluated sizeof, but serves to verify that the argument to assert is a single expression. */ @@ -131,11 +130,22 @@ __END_DECLS # define __ASSERT_FILE __FILE__ # define __ASSERT_LINE __LINE__ # endif -# define assert(expr) \ +# if __ASSERT_VARIADIC +/* The first test of __VA_ARGS__ evaluates it without converting scoped + enumeration values to bool, and the second test checks that it is a + single expression without evaluating it. */ +# define assert(...) \ + ((__VA_ARGS__) \ + ? void (1 ? 1 : bool (__VA_ARGS__)) \ + : __assert_fail (#__VA_ARGS__, __ASSERT_FILE, __ASSERT_LINE, \ + __ASSERT_FUNCTION)) +# else +# define assert(expr) \ (static_cast (expr) \ ? void (0) \ : __assert_fail (#expr, __ASSERT_FILE, __ASSERT_LINE, \ __ASSERT_FUNCTION)) +# endif # elif !defined __GNUC__ || defined __STRICT_ANSI__ # if __ASSERT_VARIADIC # define assert(...) \ diff --git a/lib/libc/include/generic-glibc/bits/cloexec.h b/lib/libc/include/generic-glibc/bits/cloexec.h new file mode 100644 index 0000000000000000000000000000000000000000..030893ff8723fd0d1dfe500c88bbc290d01cc292 --- /dev/null +++ b/lib/libc/include/generic-glibc/bits/cloexec.h @@ -0,0 +1 @@ +#define __O_CLOEXEC 02000000 \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/bits/fcntl-linux.h b/lib/libc/include/generic-glibc/bits/fcntl-linux.h index b6a2979287a93d686f1ca0b44b9faf511eea6b9f..894a22c8ba99c3a72413feca4dcf25c676177510 100644 --- a/lib/libc/include/generic-glibc/bits/fcntl-linux.h +++ b/lib/libc/include/generic-glibc/bits/fcntl-linux.h @@ -81,9 +81,7 @@ #ifndef __O_NOFOLLOW # define __O_NOFOLLOW 0400000 #endif -#ifndef __O_CLOEXEC -# define __O_CLOEXEC 02000000 -#endif +#include #ifndef __O_DIRECT # define __O_DIRECT 040000 #endif @@ -176,8 +174,8 @@ #endif #if defined __USE_UNIX98 || defined __USE_XOPEN2K8 -# define F_SETOWN __F_SETOWN /* Get owner (process receiving SIGIO). */ -# define F_GETOWN __F_GETOWN /* Set owner (process receiving SIGIO). */ +# define F_SETOWN __F_SETOWN /* Set owner (process receiving SIGIO). */ +# define F_GETOWN __F_GETOWN /* Get owner (process receiving SIGIO). */ #endif #ifndef __F_SETSIG @@ -185,15 +183,15 @@ # define __F_GETSIG 11 /* Get number of signal to be sent. */ #endif #ifndef __F_SETOWN_EX -# define __F_SETOWN_EX 15 /* Get owner (thread receiving SIGIO). */ -# define __F_GETOWN_EX 16 /* Set owner (thread receiving SIGIO). */ +# define __F_SETOWN_EX 15 /* Set owner (thread receiving SIGIO). */ +# define __F_GETOWN_EX 16 /* Get owner (thread receiving SIGIO). */ #endif #ifdef __USE_GNU # define F_SETSIG __F_SETSIG /* Set number of signal to be sent. */ # define F_GETSIG __F_GETSIG /* Get number of signal to be sent. */ -# define F_SETOWN_EX __F_SETOWN_EX /* Get owner (thread receiving SIGIO). */ -# define F_GETOWN_EX __F_GETOWN_EX /* Set owner (thread receiving SIGIO). */ +# define F_SETOWN_EX __F_SETOWN_EX /* Set owner (thread receiving SIGIO). */ +# define F_GETOWN_EX __F_GETOWN_EX /* Get owner (thread receiving SIGIO). */ #endif #ifdef __USE_GNU @@ -203,7 +201,7 @@ # define F_DUPFD_QUERY 1027 /* Compare two file descriptors for sameness. */ # define F_CREATED_QUERY 1028 /* Was the file just created? */ # define F_SETPIPE_SZ 1031 /* Set pipe page size array. */ -# define F_GETPIPE_SZ 1032 /* Set pipe page size array. */ +# define F_GETPIPE_SZ 1032 /* Get pipe page size array. */ # define F_ADD_SEALS 1033 /* Add seals to file. */ # define F_GET_SEALS 1034 /* Get seals for file. */ /* Set / get write life time hints. */ @@ -211,6 +209,8 @@ # define F_SET_RW_HINT 1036 # define F_GET_FILE_RW_HINT 1037 # define F_SET_FILE_RW_HINT 1038 +# define F_GETDELEG 1039 /* Get delegation. */ +# define F_SETDELEG 1040 /* Set delegation. */ #endif #ifdef __USE_XOPEN2K8 # define F_DUPFD_CLOEXEC 1030 /* Duplicate file descriptor with @@ -221,6 +221,7 @@ #define FD_CLOEXEC 1 /* Actually anything with low bit set goes */ #ifdef __USE_GNU # define FD_PIDFS_ROOT -10002 /* Root of the pidfs filesystem */ +# define FD_NSFS_ROOT -10003 /* Root of the nsfs filesystem */ #endif #ifndef F_RDLCK diff --git a/lib/libc/include/generic-glibc/bits/libm-simd-decl-stubs.h b/lib/libc/include/generic-glibc/bits/libm-simd-decl-stubs.h index d3b43f59cc01e21655c009ec365eb49b30d15e03..1ae3bf4992d67a9881cd05ea47f64dc4c752ec0c 100644 --- a/lib/libc/include/generic-glibc/bits/libm-simd-decl-stubs.h +++ b/lib/libc/include/generic-glibc/bits/libm-simd-decl-stubs.h @@ -99,6 +99,17 @@ #define __DECL_SIMD_powf64x #define __DECL_SIMD_powf128x +#define __DECL_SIMD_powr +#define __DECL_SIMD_powrf +#define __DECL_SIMD_powrl +#define __DECL_SIMD_powrf16 +#define __DECL_SIMD_powrf32 +#define __DECL_SIMD_powrf64 +#define __DECL_SIMD_powrf128 +#define __DECL_SIMD_powrf32x +#define __DECL_SIMD_powrf64x +#define __DECL_SIMD_powrf128x + #define __DECL_SIMD_acos #define __DECL_SIMD_acosf #define __DECL_SIMD_acosl diff --git a/lib/libc/include/generic-glibc/bits/long-double.h b/lib/libc/include/generic-glibc/bits/long-double.h index ebf6ac878fbf42241d0b2bcaf8c6049d08d827c5..af7784dbe6dd85cd9538b5a7b437ab45de22eeb8 100644 --- a/lib/libc/include/generic-glibc/bits/long-double.h +++ b/lib/libc/include/generic-glibc/bits/long-double.h @@ -1,4 +1,4 @@ -/* Properties of long double type. MIPS version. +/* Properties of long double type. ldbl-128 version. Copyright (C) 2016-2026 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -16,9 +16,6 @@ License along with the GNU C Library; if not, see . */ -#include - -#if !defined __NO_LONG_DOUBLE_MATH && _MIPS_SIM == _ABIO32 -# define __NO_LONG_DOUBLE_MATH 1 -#endif +/* long double is distinct from double, so there is nothing to + define here. */ #define __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI 0 \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/bits/mathcalls.h b/lib/libc/include/generic-glibc/bits/mathcalls.h index 7ff83e5acbeebe7f5fd3b1185735822e436aa5dd..740f26aed89b757cbe7f58e6d4f8570e6dfa74a3 100644 --- a/lib/libc/include/generic-glibc/bits/mathcalls.h +++ b/lib/libc/include/generic-glibc/bits/mathcalls.h @@ -197,6 +197,7 @@ __MATHCALL (compoundn,, (_Mdouble_ __x, long long int __y)); __MATHCALL (pown,, (_Mdouble_ __x, long long int __y)); /* Return X to the Y power. */ +__MATHCALL_VEC (powr,, (_Mdouble_ __x, _Mdouble_ __y)); __MATHCALL (powr,, (_Mdouble_ __x, _Mdouble_ __y)); /* Return the Yth root of X. */ diff --git a/lib/libc/include/generic-glibc/bits/ppc.h b/lib/libc/include/generic-glibc/bits/ppc.h deleted file mode 100644 index 5e98f066e0a95606f78a7129795ff5f06cbe55ad..0000000000000000000000000000000000000000 --- a/lib/libc/include/generic-glibc/bits/ppc.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Facilities specific to the PowerPC architecture on Linux - Copyright (C) 2012-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _BITS_PPC_H -#define _BITS_PPC_H - -#ifndef _SYS_PLATFORM_PPC_H -# error "Never include this file directly; use instead." -#endif - -__BEGIN_DECLS - -/* Read the time base frequency. */ -extern uint64_t __ppc_get_timebase_freq (void); - -__END_DECLS - -#endif \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/bits/sched.h b/lib/libc/include/generic-glibc/bits/sched.h index aa49876c1c353c46701b02b6f7f19b2f565e06e5..a66bfd53a14ce66651062a7ea51673c6e867e863 100644 --- a/lib/libc/include/generic-glibc/bits/sched.h +++ b/lib/libc/include/generic-glibc/bits/sched.h @@ -54,6 +54,9 @@ #define SCHED_FLAG_UTIL_CLAMP \ (SCHED_FLAG_UTIL_CLAMP_MIN | SCHED_FLAG_UTIL_CLAMP_MAX) +/* Flags for the flags argument of sched_getattr. */ +#define SCHED_GETATTR_FLAG_DL_DYNAMIC 0x01 + /* Use "" to work around incorrect macro expansion of the __has_include argument (GCC PR 80005). */ # ifdef __has_include diff --git a/lib/libc/include/generic-glibc/bits/struct_stat.h b/lib/libc/include/generic-glibc/bits/struct_stat.h index 231c875e7ab2c703e50746e2191ddc411c0878a2..0462d37a6849812f485a6830a7c0dca303332636 100644 --- a/lib/libc/include/generic-glibc/bits/struct_stat.h +++ b/lib/libc/include/generic-glibc/bits/struct_stat.h @@ -23,215 +23,105 @@ #ifndef _BITS_STRUCT_STAT_H #define _BITS_STRUCT_STAT_H 1 -#include - -#if _MIPS_SIM == _ABIO32 -/* Structure describing file characteristics. */ -struct stat - { -# ifdef __USE_TIME64_REDIRECTS -# include -# else - unsigned long int st_dev; - long int st_pad1[3]; -# ifndef __USE_FILE_OFFSET64 - __ino_t st_ino; /* File serial number. */ -# else - __ino64_t st_ino; /* File serial number. */ -# endif - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - unsigned long int st_rdev; /* Device number, if device. */ -# ifndef __USE_FILE_OFFSET64 - long int st_pad2[2]; - __off_t st_size; /* Size of file, in bytes. */ - /* SVR4 added this extra long to allow for expansion of off_t. */ - long int st_pad3; -# else - long int st_pad2[3]; - __off64_t st_size; /* Size of file, in bytes. */ -# endif -# ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -# else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif - __blksize_t st_blksize; /* Optimal block size for I/O. */ -# ifndef __USE_FILE_OFFSET64 - __blkcnt_t st_blocks; /* Number of 512-byte blocks allocated. */ -# else - long int st_pad4; - __blkcnt64_t st_blocks; /* Number of 512-byte blocks allocated. */ -# endif - long int st_pad5[14]; -# endif /* __USE_TIME64_REDIRECTS */ - }; - -# ifdef __USE_LARGEFILE64 -struct stat64 - { -# ifdef __USE_TIME64_REDIRECTS -# include -# else - unsigned long int st_dev; - long int st_pad1[3]; - __ino64_t st_ino; /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - unsigned long int st_rdev; /* Device number, if device. */ - long int st_pad2[3]; - __off64_t st_size; /* Size of file, in bytes. */ -# ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif - __blksize_t st_blksize; /* Optimal block size for I/O. */ - long int st_pad3; - __blkcnt64_t st_blocks; /* Number of 512-byte blocks allocated. */ - long int st_pad4[14]; -# endif /* __USE_TIME64_REDIRECTS */ - }; -# endif /* __USE_LARGEFILE64 */ - -#else /* _MIPS_SIM != _ABIO32 */ - -struct stat - { -# ifdef __USE_TIME64_REDIRECTS -# include -# else - __dev_t st_dev; - int st_pad1[3]; /* Reserved for st_dev expansion */ -# ifndef __USE_FILE_OFFSET64 - __ino_t st_ino; -# else - __ino64_t st_ino; -# endif - __mode_t st_mode; - __nlink_t st_nlink; - __uid_t st_uid; - __gid_t st_gid; - __dev_t st_rdev; -# if !defined __USE_FILE_OFFSET64 - unsigned int st_pad2[2]; /* Reserved for st_rdev expansion */ - __off_t st_size; - int st_pad3; -# else - unsigned int st_pad2[3]; /* Reserved for st_rdev expansion */ - __off64_t st_size; -# endif -# ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -# else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif - __blksize_t st_blksize; - unsigned int st_pad4; -# ifndef __USE_FILE_OFFSET64 - __blkcnt_t st_blocks; -# else - __blkcnt64_t st_blocks; -# endif - int st_pad5[14]; +#include +#include + +#if defined __USE_FILE_OFFSET64 +# define __field64(type, type64, name) type64 name +#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T +# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T +# error "ino_t and off_t must both be the same type" # endif +# define __field64(type, type64, name) type name +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define __field64(type, type64, name) \ + type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad +#else +# define __field64(type, type64, name) \ + int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name +#endif + +struct stat + { + __dev_t st_dev; /* Device. */ + __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + __dev_t __pad1; + __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ +#ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +#else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +#endif + int __glibc_reserved[2]; }; +#undef __field64 + #ifdef __USE_LARGEFILE64 struct stat64 { -# ifdef __USE_TIME64_REDIRECTS -# include -# else - __dev_t st_dev; - unsigned int st_pad1[3]; /* Reserved for st_dev expansion */ - __ino64_t st_ino; - __mode_t st_mode; - __nlink_t st_nlink; - __uid_t st_uid; - __gid_t st_gid; - __dev_t st_rdev; - unsigned int st_pad2[3]; /* Reserved for st_rdev expansion */ - __off64_t st_size; -# ifdef __USE_XOPEN2K8 + __dev_t st_dev; /* Device. */ + __ino64_t st_ino; /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + __dev_t __pad1; + __off64_t st_size; /* Size of file, in bytes. */ + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ +#ifdef __USE_XOPEN2K8 /* Nanosecond resolution timestamps are stored in a format equivalent to 'struct timespec'. This is the type used whenever possible but the Unix namespace rules do not allow the identifier 'timespec' to appear in the header. Therefore we have to handle the use of this header in strictly standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# else + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +#else __time_t st_atime; /* Time of last access. */ unsigned long int st_atimensec; /* Nscecs of last access. */ __time_t st_mtime; /* Time of last modification. */ unsigned long int st_mtimensec; /* Nsecs of last modification. */ __time_t st_ctime; /* Time of last status change. */ unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif - __blksize_t st_blksize; - unsigned int st_pad3; - __blkcnt64_t st_blocks; - int st_pad4[14]; -# endif /* __USE_TIME64_REDIRECTS */ -}; #endif - + int __glibc_reserved[2]; + }; #endif /* Tell code we have these members. */ #define _STATBUF_ST_BLKSIZE -#define _STATBUF_ST_RDEV +#define _STATBUF_ST_RDEV +/* Nanosecond resolution time values are supported. */ +#define _STATBUF_ST_NSEC #endif /* _BITS_STRUCT_STAT_H */ \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/bits/syscall.h b/lib/libc/include/generic-glibc/bits/syscall.h index 43e6645f7d238e0805be9874cadff3bfd5889520..147cc816809c06a7ab8a79cb858b50c9aa869f05 100644 --- a/lib/libc/include/generic-glibc/bits/syscall.h +++ b/lib/libc/include/generic-glibc/bits/syscall.h @@ -1,11 +1,11 @@ /* Generated at libc build time from syscall list. */ -/* The system call list corresponds to kernel 6.17. */ +/* The system call list corresponds to kernel 7.1. */ #ifndef _SYSCALL_H # error "Never use directly; include instead." #endif -#define __GLIBC_LINUX_VERSION_CODE 397568 +#define __GLIBC_LINUX_VERSION_CODE 459008 #ifdef __NR_FAST_atomic_update # define SYS_FAST_atomic_update __NR_FAST_atomic_update @@ -883,6 +883,10 @@ # define SYS_listmount __NR_listmount #endif +#ifdef __NR_listns +# define SYS_listns __NR_listns +#endif + #ifdef __NR_listxattr # define SYS_listxattr __NR_listxattr #endif @@ -1899,6 +1903,10 @@ # define SYS_rseq __NR_rseq #endif +#ifdef __NR_rseq_slice_yield +# define SYS_rseq_slice_yield __NR_rseq_slice_yield +#endif + #ifdef __NR_rt_sigaction # define SYS_rt_sigaction __NR_rt_sigaction #endif @@ -2551,6 +2559,10 @@ # define SYS_unshare __NR_unshare #endif +#ifdef __NR_uprobe +# define SYS_uprobe __NR_uprobe +#endif + #ifdef __NR_uretprobe # define SYS_uretprobe __NR_uretprobe #endif diff --git a/lib/libc/include/generic-glibc/bits/timesize.h b/lib/libc/include/generic-glibc/bits/timesize.h index 114eea77753240de1509241efac873c28a59e9d0..dff2da5ed6bf30ce6f5580aee352e0958d58b623 100644 --- a/lib/libc/include/generic-glibc/bits/timesize.h +++ b/lib/libc/include/generic-glibc/bits/timesize.h @@ -1,5 +1,5 @@ -/* Bit size of the time_t type at glibc build time, Linux/MIPS. - Copyright (C) 2021-2026 Free Software Foundation, Inc. +/* Bit size of the time_t type at glibc build time, general case. + Copyright (C) 2018-2026 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -16,7 +16,5 @@ License along with the GNU C Library; if not, see . */ -#include - /* Size in bits of the 'time_t' type of the default ABI. */ -#define __TIMESIZE __WORDSIZE \ No newline at end of file +#define __TIMESIZE 64 \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/bits/uio-ext.h b/lib/libc/include/generic-glibc/bits/uio-ext.h index e65cf77f433fcc0e7b4ce718f10c093fcc1d2097..1289a864c6d7432bada85113026c2a94b66a0251 100644 --- a/lib/libc/include/generic-glibc/bits/uio-ext.h +++ b/lib/libc/include/generic-glibc/bits/uio-ext.h @@ -51,6 +51,7 @@ extern ssize_t process_vm_writev (pid_t __pid, const struct iovec *__lvec, #define RWF_ATOMIC 0x00000040 /* Write is to be issued with torn-write prevention. */ #define RWF_DONTCACHE 0x00000080 /* Uncached buffered IO. */ +#define RWF_NOSIGNAL 0x00000100 /* Do not generate SIGPIPE on error. */ __END_DECLS diff --git a/lib/libc/include/generic-glibc/dlfcn.h b/lib/libc/include/generic-glibc/dlfcn.h index f12e3d68cd4e31c856a23e1c63bd5a2d6b597146..439f09dd9e3d8a5937343cc741a7778be646439b 100644 --- a/lib/libc/include/generic-glibc/dlfcn.h +++ b/lib/libc/include/generic-glibc/dlfcn.h @@ -167,7 +167,12 @@ enum the number of program headers in the array. */ RTLD_DI_PHDR = 11, - RTLD_DI_MAX = 11 + /* Treat ARG as `const char **' and at that location, store the address + of the directory name used to expand $ORIGIN in this shared object's + dependency file names. */ + RTLD_DI_ORIGIN_PATH = 12, + + RTLD_DI_MAX = 12 }; diff --git a/lib/libc/include/generic-glibc/elf.h b/lib/libc/include/generic-glibc/elf.h index a45dea41210184770afb26e837fb86f03d226b9a..ea2eca5e6dfbd1c0a63f9a90ddca67982061d64d 100644 --- a/lib/libc/include/generic-glibc/elf.h +++ b/lib/libc/include/generic-glibc/elf.h @@ -798,7 +798,8 @@ typedef struct #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ #define NT_X86_SHSTK 0x204 /* x86 SHSTK state */ #define NT_X86_XSAVE_LAYOUT 0x205 /* XSAVE layout description. */ -#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ +#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves. This was + used in now removed s390-32 arch. */ #define NT_S390_TIMER 0x301 /* s390 timer register */ #define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ #define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ @@ -846,6 +847,7 @@ typedef struct #define NT_RISCV_VECTOR 0x901 /* RISC-V vector registers */ #define NT_RISCV_TAGGED_ADDR_CTRL 0x902 /* RISC-V tagged address control */ +#define NT_RISCV_USER_CFI 0x903 /* RISC-V shadow stack state */ #define NT_LOONGARCH_CPUCFG 0xa00 /* LoongArch CPU config registers. */ #define NT_LOONGARCH_CSR 0xa01 /* LoongArch control and status registers. */ @@ -3470,7 +3472,9 @@ enum /* Valid values for the e_flags field. */ -#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ +#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. + This was used in now removed s390-32 + arch. */ /* Additional s390 relocs */ diff --git a/lib/libc/include/generic-glibc/features.h b/lib/libc/include/generic-glibc/features.h index 5ef3af3beb712cf7cbb02d380cc68ef6f1b18d4d..a248a324911cb478b02d7f95cc87f8f9d6408327 100644 --- a/lib/libc/include/generic-glibc/features.h +++ b/lib/libc/include/generic-glibc/features.h @@ -162,7 +162,7 @@ #undef __GLIBC_USE_DEPRECATED_SCANF #undef __GLIBC_USE_C23_STRTOL -/* Suppress kernel-name space pollution unless user expressedly asks +/* Suppress kernel-name space pollution unless user explicitly asks for it. */ #ifndef _LOOSE_KERNEL_NAMES # define __KERNEL_STRICT_NAMES @@ -580,4 +580,4 @@ #include -#endif /* features.h */ +#endif /* features.h */ \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/fts.h b/lib/libc/include/generic-glibc/fts.h index 97d0f4a8a299fb9f4e439232fc9e33cd851b605e..d2164aa4ee5b51b2bc8b2f46df54614b941a4dbb 100644 --- a/lib/libc/include/generic-glibc/fts.h +++ b/lib/libc/include/generic-glibc/fts.h @@ -52,7 +52,29 @@ #include #include +#include +#include +#include +enum { __I_RING_SIZE = 4 }; + +/* When ir_empty is true, the ring is empty. + Otherwise, ir_data[B..F] are defined, where B..F is the contiguous + range of indices, modulo I_RING_SIZE, from back to front, inclusive. + Undefined elements of ir_data are always set to ir_default_val. + Popping from an empty ring aborts. + Pushing onto a full ring returns the displaced value. + An empty ring has F==B and ir_empty == true. + A ring with one entry still has F==B, but now ir_empty == false. */ +struct __I_ring +{ + int ir_data[__I_RING_SIZE]; + int ir_default_val; + unsigned int ir_front; + unsigned int ir_back; + bool ir_empty; +}; +typedef struct __I_ring __I_ring; typedef struct { struct _ftsent *fts_cur; /* current node */ @@ -73,11 +95,106 @@ typedef struct { #define FTS_SEEDOT 0x0020 /* return dot and dot-dot */ #define FTS_XDEV 0x0040 /* don't cross devices */ #define FTS_WHITEOUT 0x0080 /* return whiteout information */ -#define FTS_OPTIONMASK 0x00ff /* valid user option mask */ + + /* There are two ways to detect cycles. + The lazy way (which works only with FTS_PHYSICAL), + with which one may process a directory that is a + part of the cycle several times before detecting the cycle. + The "tight" way, whereby fts uses more memory (proportional + to number of "active" directories, aka distance from root + of current tree to current directory -- see active_dir_ht) + to detect any cycle right away. For example, du must use + this option to avoid counting disk space in a cycle multiple + times, but chown -R need not. + The default is to use the constant-memory lazy way, when possible + (see below). + + However, with FTS_LOGICAL (when following symlinks, e.g., chown -L) + using lazy cycle detection is inadequate. For example, traversing + a directory containing a symbolic link to a peer directory, it is + possible to encounter the same directory twice even though there + is no cycle: + dir + ... + slink -> dir + So, when FTS_LOGICAL is selected, we have to use a different + mode of cycle detection: FTS_TIGHT_CYCLE_CHECK. */ +#define FTS_TIGHT_CYCLE_CHECK 0x0400 + + /* Use this flag to enable semantics with which the parent + application may be made both more efficient and more robust. + Whereas the default is to visit each directory in a recursive + traversal (via chdir), using this flag makes it so the initial + working directory is never changed. Instead, these functions + perform the traversal via a virtual working directory, maintained + through the file descriptor member, fts_cwd_fd. */ +# define FTS_CWDFD 0x0800 + + /* Historically, for each directory that fts initially encounters, it would + open it, read all entries, and stat each entry, storing the results, and + then it would process the first entry. But that behavior is bad for + locality of reference, and also causes trouble with inode-simulating + file systems like FAT, CIFS, FUSE-based ones, etc., when entries from + their name/inode cache are flushed too early. + Use this flag to make fts_open and fts_read defer the stat/lstat/fststat + of each entry until it is actually processed. However, note that if you + use this option and also specify a comparison function, that function may + not examine any data via fts_statp. However, when fts_statp->st_mode is + nonzero, the S_IFMT type bits are valid, with mapped dirent.d_type data. + Of course, that happens only on file systems that provide useful + dirent.d_type data. */ +#define FTS_DEFER_STAT 0x1000 + + /* Use this flag to disable stripping of trailing slashes + from input path names during fts_open initialization. */ +#define FTS_VERBATIM 0x2000 + +#define FTS_MOUNT 0x4000 /* skip other devices */ +#define FTS_OPTIONMASK 0x7fff /* valid user option mask */ #define FTS_NAMEONLY 0x0100 /* (private) child names only */ #define FTS_STOP 0x0200 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ + + int fts_cwd_fd; /* the file descriptor on which the + virtual cwd is open, or AT_FDCWD */ + + /* Map a directory's device number to a boolean. The boolean is + true if for that file system (type determined by a single fstatfs + call per FS) st_nlink can be used to calculate the number of + sub-directory entries in a directory. + Using this table is an optimization that permits us to look up + file system type on a per-inode basis at the minimal cost of + calling fstatfs only once per traversed device. */ + struct hash_table *fts_leaf_optimization_works_ht; + + union { + /* This data structure is used if FTS_TIGHT_CYCLE_CHECK is + specified. It records the directories between a starting + point and the current directory. I.e., a directory is + recorded here IFF we have visited it once, but we have not + yet completed processing of all its entries. Every time we + visit a new directory, we add that directory to this set. + When we finish with a directory (usually by visiting it a + second time), we remove it from this set. Each entry in + this data structure is a device/inode pair. This data + structure is used to detect directory cycles efficiently and + promptly even when the depth of a hierarchy is in the tens + of thousands. */ + struct hash_table *ht; + + /* FIXME: rename these two members to have the fts_ prefix */ + /* This data structure uses a lazy cycle-detection algorithm, + as done by rm via cycle-check.c. It's the default, + but it's not appropriate for programs like du. */ + struct cycle_check_state *state; + } fts_cycle; + + /* A stack of the file descriptors corresponding to the + most-recently traversed parent directories. + Currently used only in FTS_CWDFD mode. */ + __I_ring fts_fd_ring; } FTS; #ifdef __USE_LARGEFILE64 @@ -92,6 +209,13 @@ typedef struct { int fts_nitems; /* elements in the sort array */ int (*fts_compar) (const void *, const void *); /* compare fn */ int fts_options; /* fts_open options, global flags */ + int fts_cwd_fd; + struct hash_table *fts_leaf_optimization_works_ht; + union { + struct hash_table *ht; + struct cycle_check_state *state; + } fts_cycle; + __I_ring fts_fd_ring; } FTS64; #endif diff --git a/lib/libc/include/generic-glibc/gnu/lib-names-32.h b/lib/libc/include/generic-glibc/gnu/lib-names-32.h index 77fbbc46100d7b2fcad49cb67f4af22df471f3a3..33f2700fb049c9de98b511c395753670af4df99b 100644 --- a/lib/libc/include/generic-glibc/gnu/lib-names-32.h +++ b/lib/libc/include/generic-glibc/gnu/lib-names-32.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/gnu/lib-names-hard.h b/lib/libc/include/generic-glibc/gnu/lib-names-hard.h index 393a0f91f49473362cb28026ea93f876f41da4c9..80f8b2e87ee57205b72076031c8e4711617647e2 100644 --- a/lib/libc/include/generic-glibc/gnu/lib-names-hard.h +++ b/lib/libc/include/generic-glibc/gnu/lib-names-hard.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/gnu/lib-names-n32_hard.h b/lib/libc/include/generic-glibc/gnu/lib-names-n32_hard.h index 2d2d46e4f5c3b76030cf34eb89a95f1debf40f27..09f068b64409436bd6e070b7f4642a596bb5907d 100644 --- a/lib/libc/include/generic-glibc/gnu/lib-names-n32_hard.h +++ b/lib/libc/include/generic-glibc/gnu/lib-names-n32_hard.h @@ -23,4 +23,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/gnu/lib-names-n64_hard.h b/lib/libc/include/generic-glibc/gnu/lib-names-n64_hard.h index 3d545313911cc42780f3f625b29e4b6078dd4c4e..caed888c6bd100ca1c0627bd0bdfba5146140775 100644 --- a/lib/libc/include/generic-glibc/gnu/lib-names-n64_hard.h +++ b/lib/libc/include/generic-glibc/gnu/lib-names-n64_hard.h @@ -23,4 +23,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/gnu/lib-names-o32_hard.h b/lib/libc/include/generic-glibc/gnu/lib-names-o32_hard.h index ab69cdcb7cfa958560ef796ba6f94a50398448dd..592d60dd33b5df50b16200332cf576666c2adf58 100644 --- a/lib/libc/include/generic-glibc/gnu/lib-names-o32_hard.h +++ b/lib/libc/include/generic-glibc/gnu/lib-names-o32_hard.h @@ -23,4 +23,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/gnu/lib-names-o32_soft.h b/lib/libc/include/generic-glibc/gnu/lib-names-o32_soft.h index 9be4d1e62012f6c7ce0ce5ed579989a65c795c7f..5ae29e9fb109b3f2bdfe275ae1a829769d66b0fb 100644 --- a/lib/libc/include/generic-glibc/gnu/lib-names-o32_soft.h +++ b/lib/libc/include/generic-glibc/gnu/lib-names-o32_soft.h @@ -23,4 +23,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/gnu/lib-names-soft.h b/lib/libc/include/generic-glibc/gnu/lib-names-soft.h index c7a71323508f709975e8cb9f792dd2f928a275a3..fa665583dd54d5e8c17f2423181476fd94412be8 100644 --- a/lib/libc/include/generic-glibc/gnu/lib-names-soft.h +++ b/lib/libc/include/generic-glibc/gnu/lib-names-soft.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/gnu/stubs-64.h b/lib/libc/include/generic-glibc/gnu/stubs-64.h deleted file mode 100644 index 636dc73283f9e3508fca4713d7d911f47d284387..0000000000000000000000000000000000000000 --- a/lib/libc/include/generic-glibc/gnu/stubs-64.h +++ /dev/null @@ -1,16 +0,0 @@ -/* This file is automatically generated. - It defines a symbol `__stub_FUNCTION' for each function - in the C library which is a stub, meaning it will fail - every time called, usually setting errno to ENOSYS. */ - -#ifdef _LIBC - #error Applications may not define the macro _LIBC -#endif - -#define __stub_chflags -#define __stub_fchflags -#define __stub_gtty -#define __stub_revoke -#define __stub_setlogin -#define __stub_sigreturn -#define __stub_stty \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/netinet/in.h b/lib/libc/include/generic-glibc/netinet/in.h index 450338576f11be16bcf50d09d016d593f9ab5ca7..68b2016cdec8019a5e061dce477e6b1a69d3443e 100644 --- a/lib/libc/include/generic-glibc/netinet/in.h +++ b/lib/libc/include/generic-glibc/netinet/in.h @@ -91,6 +91,8 @@ enum #define IPPROTO_MPLS IPPROTO_MPLS IPPROTO_ETHERNET = 143, /* Ethernet-within-IPv6 Encapsulation. */ #define IPPROTO_ETHERNET IPPROTO_ETHERNET + IPPROTO_AGGFRAG = 144, /* AGGFRAG in ESP (RFC 9347). */ +#define IPPROTO_AGGFRAG IPPROTO_AGGFRAG IPPROTO_RAW = 255, /* Raw IP packets. */ #define IPPROTO_RAW IPPROTO_RAW IPPROTO_SMC = 256, /* Shared Memory Communications. */ diff --git a/lib/libc/include/generic-glibc/netinet/tcp.h b/lib/libc/include/generic-glibc/netinet/tcp.h index 49764361e72d032438c000c278a16c8f77bbc555..ae66195fa6dc6b8181e6d4ad4092806a14295d33 100644 --- a/lib/libc/include/generic-glibc/netinet/tcp.h +++ b/lib/libc/include/generic-glibc/netinet/tcp.h @@ -80,6 +80,9 @@ as a cmsg on read. */ #define TCP_CM_INQ TCP_INQ #define TCP_TX_DELAY 37 /* Delay outgoing packets by XX usec. */ +#define TCP_RTO_MAX_MS 44 /* Max time to retransmit (msec). */ +#define TCP_RTO_MIN_US 45 /* Min time to retransmit (usec). */ +#define TCP_DELACK_MAX_US 46 /* Max delayed ack time (usec). */ #define TCP_REPAIR_ON 1 #define TCP_REPAIR_OFF 0 @@ -226,6 +229,24 @@ enum tcp_ca_state TCP_CA_Loss = 4 }; +/* Values for tcpi_ecn_mode after negotiation. */ +#define TCPI_ECN_MODE_DISABLED 0x0 +#define TCPI_ECN_MODE_RFC3168 0x1 +#define TCPI_ECN_MODE_ACCECN 0x2 +#define TCPI_ECN_MODE_PENDING 0x3 + +/* Values for tcpi_accecn_opt_seen. */ +#define TCP_ACCECN_OPT_NOT_SEEN 0x0 +#define TCP_ACCECN_OPT_EMPTY_SEEN 0x1 +#define TCP_ACCECN_OPT_COUNTER_SEEN 0x2 +#define TCP_ACCECN_OPT_FAIL_SEEN 0x3 + +/* Values for tcpi_accecn_fail_mode. */ +#define TCP_ACCECN_ACE_FAIL_SEND 0x1 +#define TCP_ACCECN_ACE_FAIL_RECV 0x2 +#define TCP_ACCECN_OPT_FAIL_SEND 0x4 +#define TCP_ACCECN_OPT_FAIL_RECV 0x8 + struct tcp_info { uint8_t tcpi_state; @@ -319,8 +340,10 @@ struct tcp_info uint32_t tcpi_received_e1_bytes; uint32_t tcpi_received_e0_bytes; uint32_t tcpi_received_ce_bytes; - uint16_t tcpi_accecn_fail_mode; - uint16_t tcpi_accecn_opt_seen; + uint32_t tcpi_ecn_mode:2, + tcpi_accecn_opt_seen:2, + tcpi_accecn_fail_mode:4, + tcpi_options2:24; }; /* Netlink attributes types for SCM_TIMESTAMPING_OPT_STATS */ diff --git a/lib/libc/include/generic-glibc/regex.h b/lib/libc/include/generic-glibc/regex.h index 29964af5b251c24a729a3326c173a0ae96455d96..5ff2fb611c92f20565163ee3430e43348665c37c 100644 --- a/lib/libc/include/generic-glibc/regex.h +++ b/lib/libc/include/generic-glibc/regex.h @@ -74,7 +74,7 @@ typedef unsigned long int reg_syntax_t; #ifdef __USE_GNU /* If this bit is not set, then \ inside a bracket expression is literal. If set, then such a \ quotes the following character. */ -# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) +# define RE_BACKSLASH_ESCAPE_IN_LISTS 1ul /* If this bit is not set, then + and ? are operators, and \+ and \? are literals. diff --git a/lib/libc/include/generic-glibc/spawn.h b/lib/libc/include/generic-glibc/spawn.h index b8e1eaee8f8c1432cb21fb069d2134573536827e..265a63ca28b30e0822fe9cf86e2214ec9de3cf3e 100644 --- a/lib/libc/include/generic-glibc/spawn.h +++ b/lib/libc/include/generic-glibc/spawn.h @@ -200,6 +200,26 @@ extern int posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t * int __fd, int __newfd) __THROW __nonnull ((1)); +#ifdef __USE_XOPEN2K24XSI + +/* Add an action changing the directory to PATH during spawn. This + affects the subsequent file actions. + Alias of posix_spawn_file_actions_addchdir_np. */ +extern int __REDIRECT_NTH (posix_spawn_file_actions_addchdir, + (posix_spawn_file_actions_t * __restrict __actions, + const char *__restrict __path), + posix_spawn_file_actions_addchdir_np); + +/* Add an action changing the directory to FD during spawn. This + affects the subsequent file actions. FD is not duplicated and must + be open when the file action is executed. + Alias of posix_spawn_file_actions_addfchdir_np. */ +extern int __REDIRECT_NTH (posix_spawn_file_actions_addfchdir, + (posix_spawn_file_actions_t *, int __fd), + posix_spawn_file_actions_addfchdir_np); + +#endif /* __USE_XOPEN2K24XSI */ + #ifdef __USE_MISC /* Add an action changing the directory to PATH during spawn. This affects the subsequent file actions. */ diff --git a/lib/libc/include/generic-glibc/stdlib.h b/lib/libc/include/generic-glibc/stdlib.h index 3ca2bb1f91bc38a0f6244c99113a3fb520f15b20..7d8d57f4cd907c77714fefe6615acf92624080cb 100644 --- a/lib/libc/include/generic-glibc/stdlib.h +++ b/lib/libc/include/generic-glibc/stdlib.h @@ -1225,4 +1225,4 @@ extern size_t memalignment (const void *__p); __END_DECLS -#endif /* stdlib.h */ +#endif /* stdlib.h */ \ No newline at end of file diff --git a/lib/libc/include/generic-glibc/sys/mount.h b/lib/libc/include/generic-glibc/sys/mount.h index bf226f5a738b6369caba0558d98357d3cb06e975..95834f8bf77e7fb2dbcb33fdb69ea81197335d5e 100644 --- a/lib/libc/include/generic-glibc/sys/mount.h +++ b/lib/libc/include/generic-glibc/sys/mount.h @@ -21,7 +21,6 @@ #ifndef _SYS_MOUNT_H #define _SYS_MOUNT_H 1 -#include #include #include #include @@ -190,6 +189,11 @@ enum /* fsmount flags. */ #define FSMOUNT_CLOEXEC 0x00000001 +// zig patch: check target glibc version +#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 44) || __GLIBC__ > 2 +#define FSMOUNT_NAMESPACE 0x00000002 /* Create the mount in a new mount + namespace. */ +#endif /* (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 44) || __GLIBC__ > 2 */ /* mount attributes used on fsmount. */ #define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only. */ @@ -267,10 +271,20 @@ enum fsconfig_command #define FSOPEN_CLOEXEC 0x00000001 /* open_tree flags. */ -#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */ -#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */ +#ifndef OPEN_TREE_CLONE +# define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */ +#endif +#define OPEN_TREE_NAMESPACE (1 << 1) /* Clone the target tree into a new mount + namespace */ +#ifndef O_CLOEXEC +# include +# define O_CLOEXEC __O_CLOEXEC +#endif +#ifndef OPEN_TREE_CLOEXEC +# define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */ +#endif -#endif +#endif /* (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 36) || __GLIBC__ > 2 */ __BEGIN_DECLS diff --git a/lib/libc/include/generic-glibc/sys/pidfd.h b/lib/libc/include/generic-glibc/sys/pidfd.h index 3d9ab9430c72d2b947860d9fa6b9525a6ebc11aa..19ac5235e5868de39a7a0659b8da9d122467bb8f 100644 --- a/lib/libc/include/generic-glibc/sys/pidfd.h +++ b/lib/libc/include/generic-glibc/sys/pidfd.h @@ -64,6 +64,15 @@ #define PIDFD_INFO_EXIT (1UL << 3) /* Only returned if requested. */ #define PIDFD_INFO_COREDUMP (1UL << 4) +// zig patch: check target glibc version +#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 44) || __GLIBC__ > 2 +/* Want/got supported mask flags */ +#define PIDFD_INFO_SUPPORTED_MASK (1UL << 5) +/* Always returned if PIDFD_INFO_COREDUMP is requested. */ +#define PIDFD_INFO_COREDUMP_SIGNAL (1UL << 6) +/* Always returned if PIDFD_INFO_COREDUMP is requested. */ +#define PIDFD_INFO_COREDUMP_CODE (1UL << 7) +#endif /* (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 44) || __GLIBC__ > 2 */ /* Value for coredump_mask in pidfd_info. Only valid if PIDFD_INFO_COREDUMP @@ -95,11 +104,28 @@ struct pidfd_info __uint32_t fsgid; __int32_t exit_code; __uint32_t coredump_mask; +// zig patch: check target glibc version +#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 44) || __GLIBC__ > 2 + __uint32_t coredump_signal; + __uint32_t coredump_code; + __uint32_t coredump_pad; + __uint64_t supported_mask; +#else __uint32_t __spare1; +#endif /* (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 44) || __GLIBC__ > 2 */ }; /* sizeof first published struct */ #define PIDFD_INFO_SIZE_VER0 64 +// zig patch: check target glibc version +#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 44) || __GLIBC__ > 2 +/* sizeof second published struct */ +#define PIDFD_INFO_SIZE_VER1 72 +/* sizeof third published struct */ +#define PIDFD_INFO_SIZE_VER2 80 +/* sizeof fourth published struct */ +#define PIDFD_INFO_SIZE_VER3 88 +#endif /* (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 44) || __GLIBC__ > 2 */ #define PIDFD_GET_INFO _IOWR(PIDFS_IOCTL_MAGIC, 11, struct pidfd_info) diff --git a/lib/libc/include/generic-glibc/sys/platform/ppc.h b/lib/libc/include/generic-glibc/sys/platform/ppc.h deleted file mode 100644 index 6e7df94235d78f7b3ad6c8644301f8d0441a264e..0000000000000000000000000000000000000000 --- a/lib/libc/include/generic-glibc/sys/platform/ppc.h +++ /dev/null @@ -1,146 +0,0 @@ -/* Facilities specific to the PowerPC architecture - Copyright (C) 2012-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _SYS_PLATFORM_PPC_H -#define _SYS_PLATFORM_PPC_H 1 - -#include -#include -#include - -/* Read the Time Base Register. */ -static __inline__ uint64_t -__ppc_get_timebase (void) -{ -#if __GNUC_PREREQ (4, 8) - return __builtin_ppc_get_timebase (); -#else -# ifdef __powerpc64__ - uint64_t __tb; - /* "volatile" is necessary here, because the user expects this assembly - isn't moved after an optimization. */ - __asm__ volatile ("mfspr %0, 268" : "=r" (__tb)); - return __tb; -# else /* not __powerpc64__ */ - uint32_t __tbu, __tbl, __tmp; \ - __asm__ volatile ("0:\n\t" - "mftbu %0\n\t" - "mftbl %1\n\t" - "mftbu %2\n\t" - "cmpw %0, %2\n\t" - "bne- 0b" - : "=r" (__tbu), "=r" (__tbl), "=r" (__tmp)); - return (((uint64_t) __tbu << 32) | __tbl); -# endif /* not __powerpc64__ */ -#endif -} - -/* The following functions provide hints about the usage of shared processor - resources, as defined in ISA 2.06 and newer. */ - -/* Provides a hint that performance will probably be improved if shared - resources dedicated to the executing processor are released for use by other - processors. */ -static __inline__ void -__ppc_yield (void) -{ - __asm__ volatile ("or 27,27,27"); -} - -/* Provides a hint that performance will probably be improved if shared - resources dedicated to the executing processor are released until - all outstanding storage accesses to caching-inhibited storage have been - completed. */ -static __inline__ void -__ppc_mdoio (void) -{ - __asm__ volatile ("or 29,29,29"); -} - -/* Provides a hint that performance will probably be improved if shared - resources dedicated to the executing processor are released until all - outstanding storage accesses to cacheable storage for which the data is not - in the cache have been completed. */ -static __inline__ void -__ppc_mdoom (void) -{ - __asm__ volatile ("or 30,30,30"); -} - - -/* ISA 2.05 and beyond support the Program Priority Register (PPR) to adjust - thread priorities based on lock acquisition, wait and release. The ISA - defines the use of form 'or Rx,Rx,Rx' as the way to modify the PRI field. - The unprivileged priorities are: - Rx = 1 (low) - Rx = 2 (medium) - Rx = 6 (medium-low/normal) - The 'or' instruction form is a nop in previous hardware, so it is safe to - use unguarded. The default value is 'medium'. - */ - -static __inline__ void -__ppc_set_ppr_med (void) -{ - __asm__ volatile ("or 2,2,2"); -} - -static __inline__ void -__ppc_set_ppr_med_low (void) -{ - __asm__ volatile ("or 6,6,6"); -} - -static __inline__ void -__ppc_set_ppr_low (void) -{ - __asm__ volatile ("or 1,1,1"); -} - -/* Power ISA 2.07 (Book II, Chapter 3) extends the priorities that can be set - to the Program Priority Register (PPR). The form 'or Rx,Rx,Rx' is used to - modify the PRI field of the PPR, the same way as described above. - The new priority levels are: - Rx = 31 (very low) - Rx = 5 (medium high) - Any program can set the priority to very low, low, medium low, and medium, - as these are unprivileged. - The medium high priority, on the other hand, is privileged, and may only be - set during certain time intervals by problem-state programs. If the program - priority is medium high when the time interval expires or if an attempt is - made to set the priority to medium high when it is not allowed, the PRI - field is set to medium. - */ - -#ifdef _ARCH_PWR8 - -static __inline__ void -__ppc_set_ppr_very_low (void) -{ - __asm__ volatile ("or 31,31,31"); -} - -static __inline__ void -__ppc_set_ppr_med_high (void) -{ - __asm__ volatile ("or 5,5,5"); -} - -#endif - -#endif /* sys/platform/ppc.h */ \ No newline at end of file diff --git a/lib/libc/include/generic-netbsd/fcntl.h b/lib/libc/include/generic-netbsd/fcntl.h index af43c74a3daca814d873e6bda87f497dc6f0de4b..311effadd406e25dae75c281ff217008e87ab001 100644 --- a/lib/libc/include/generic-netbsd/fcntl.h +++ b/lib/libc/include/generic-netbsd/fcntl.h @@ -1,4 +1,4 @@ -/* $NetBSD: fcntl.h,v 1.57 2025/07/25 23:24:46 kre Exp $ */ +/* $NetBSD: fcntl.h,v 1.57.2.1 2026/06/16 09:06:50 martin Exp $ */ /*- * Copyright (c) 1983, 1990, 1993 @@ -121,6 +121,9 @@ #if defined(_NETBSD_SOURCE) #define O_NOSIGPIPE 0x01000000 /* don't deliver sigpipe */ #define O_REGULAR 0x02000000 /* fail if not a regular file */ +#endif +#if (_POSIX_C_SOURCE - 0) >= 200809L || (_XOPEN_SOURCE - 0 >= 700) || \ + defined(_NETBSD_SOURCE) #define O_EXEC 0x04000000 /* open for executing only */ #endif #if (_POSIX_C_SOURCE - 0) >= 202405L || (_XOPEN_SOURCE - 0 >= 800) || \ diff --git a/lib/libc/include/generic-netbsd/i386/mcontext.h b/lib/libc/include/generic-netbsd/i386/mcontext.h index eca7a40be452d1894f78d3de2424c400ea2dbd6e..bf34279f20a8dfa0fb8aa61839b7de8b2b96f640 100644 --- a/lib/libc/include/generic-netbsd/i386/mcontext.h +++ b/lib/libc/include/generic-netbsd/i386/mcontext.h @@ -1,4 +1,4 @@ -/* $NetBSD: mcontext.h,v 1.19 2024/11/30 01:04:10 christos Exp $ */ +/* $NetBSD: mcontext.h,v 1.19.2.1 2026/07/19 15:57:27 martin Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -40,6 +40,7 @@ #define _UC_CLRSTACK _UC_MD_BIT17 #define _UC_VM _UC_MD_BIT18 #define _UC_TLSBASE _UC_MD_BIT19 +#define _UC_XSAVE _UC_MD_BIT20 /* * Layout of mcontext_t according to the System V Application Binary Interface, @@ -85,6 +86,27 @@ typedef struct { char __fp_xmm[512]; } __fp_xmm_state; /* x87 and xmm regs in fxsave format */ int __fp_fpregs[128]; + struct { + /* + * `The XSAVE feature set does not use bytes + * 511:416; bytes 463:416 are reserved.' + * + * We take a part out of this to form a pointer + * to an external XSAVE area. This way, we can + * replicate the FXSAVE parts for the benefit + * of userland programs that aren't aware of + * the XSAVE pointer, have used the extended + * CPU registers (ymmN/zmmN/&c.), and want to + * examine the x87/SSE register state in a + * signal handler. The kernel does not use + * this part. + */ + char __fxsave[416]; + char __rsvd[48]; + __greg_t __xsaveptr; + __greg_t __xsavelen; + char __pad[40]; + } __xsave; } __fp_reg_set; int __fp_pad[33]; /* Historic padding */ } __fpregset_t; diff --git a/lib/libc/include/generic-netbsd/i386/wchar_limits.h b/lib/libc/include/generic-netbsd/i386/wchar_limits.h index e3bf3b7090c9ee41148b6edc36944d5dad30fe8e..76ee442d874d23f7e4570df9abf167a81d39b79b 100644 --- a/lib/libc/include/generic-netbsd/i386/wchar_limits.h +++ b/lib/libc/include/generic-netbsd/i386/wchar_limits.h @@ -44,4 +44,4 @@ #define WINT_MIN (-0x7fffffff-1) /* wint_t */ #define WINT_MAX 0x7fffffff /* wint_t */ -#endif /* !_I386_WCHAR_LIMITS_H_ */ +#endif /* !_I386_WCHAR_LIMITS_H_ */ \ No newline at end of file diff --git a/lib/libc/include/generic-netbsd/machine/pte.h b/lib/libc/include/generic-netbsd/machine/pte.h index 760dc280552255428ff7144e68346bb813c363cd..f19d4ffe10144f61bc3ef3a8fd35d06a81de4c78 100644 --- a/lib/libc/include/generic-netbsd/machine/pte.h +++ b/lib/libc/include/generic-netbsd/machine/pte.h @@ -1,4 +1,4 @@ -/* $NetBSD: pte.h,v 1.14.2.2 2025/10/26 12:28:36 martin Exp $ */ +/* $NetBSD: pte.h,v 1.14.2.3 2026/06/03 18:17:02 martin Exp $ */ /* * Copyright (c) 2014, 2019, 2021 The NetBSD Foundation, Inc. @@ -139,6 +139,12 @@ pte_modified_p(pt_entry_t pte) return (pte & PTE_D) != 0; } +static inline bool +pte_referenced_p(pt_entry_t pte) +{ + return (pte & PTE_A) != 0; +} + static inline bool pte_cached_p(pt_entry_t pte) { @@ -177,9 +183,15 @@ pte_nv_entry(bool kernel_p) } static inline pt_entry_t -pte_prot_nowrite(pt_entry_t pte) +pte_clear_modify(pt_entry_t pte) { - return pte & ~PTE_W; + return pte & ~PTE_D; +} + +static inline pt_entry_t +pte_clear_reference(pt_entry_t pte) +{ + return pte & ~PTE_A; } static inline pt_entry_t @@ -237,28 +249,29 @@ pte_make_enter(paddr_t pa, struct vm_page_md *mdpg, vm_prot_t prot, pte |= pte_prot_bits(mdpg, prot, kernel_p); pte |= pte_enter_flags_to_pbmt(flags); + /* + * pmap_enter should have checked flags and updated + * VM_PAGEMD_{REFERENCED,MODIFIED}_P, so there is no + * need here. + */ + KASSERT(((flags & VM_PROT_ALL) == 0) || VM_PAGEMD_REFERENCED_P(mdpg)); + KASSERT(((flags & VM_PROT_WRITE) == 0) || VM_PAGEMD_MODIFIED_P(mdpg)); + if (mdpg != NULL) { - - if ((prot & VM_PROT_WRITE) != 0 && - ((flags & VM_PROT_WRITE) != 0 || VM_PAGEMD_MODIFIED_P(mdpg))) { + if ((prot & VM_PROT_WRITE) != 0 && VM_PAGEMD_MODIFIED_P(mdpg)) { /* - * This is a writable mapping, and the page's mod state - * indicates it has already been modified. No need for - * modified emulation. - */ + * This is a writable mapping, and the page's mod state + * indicates it has already been modified. No need for + * reference or modified emulation. + */ pte |= PTE_A | PTE_D; - } else if ((flags & VM_PROT_ALL) || VM_PAGEMD_REFERENCED_P(mdpg)) { + } else if (VM_PAGEMD_REFERENCED_P(mdpg)) { /* - * - The access type indicates that we don't need to do - * referenced emulation. - * OR - * - The physical page has already been referenced so no need - * to re-do referenced emulation here. - */ + * The physical page has already been referenced so no need + * to re-do referenced emulation here. + */ pte |= PTE_A; } - } else { - pte |= PTE_A | PTE_D; } return pte; diff --git a/lib/libc/include/generic-netbsd/machine/vmparam.h b/lib/libc/include/generic-netbsd/machine/vmparam.h index b483e18e8574ce42273a16ae6e90df2b10157c6c..ba9c754dce496cd5d52b0bda02691afeba05e979 100644 --- a/lib/libc/include/generic-netbsd/machine/vmparam.h +++ b/lib/libc/include/generic-netbsd/machine/vmparam.h @@ -1,4 +1,4 @@ -/* $NetBSD: vmparam.h,v 1.14 2023/05/07 12:41:48 skrll Exp $ */ +/* $NetBSD: vmparam.h,v 1.14.8.2 2026/06/03 18:17:02 martin Exp $ */ /*- * Copyright (c) 2014, 2020 The NetBSD Foundation, Inc. @@ -50,6 +50,25 @@ #define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK (PAGE_SIZE - 1) +#ifdef _LP64 +/* + * Default pager_map of 16MB is awfully small. There is plenty + * of VA so use it. + */ +#define PAGER_MAP_DEFAULT_SIZE (512 * 1024 * 1024) + +/* + * Defaults for Unified Buffer Cache parameters. + */ + +#ifndef UBC_WINSHIFT +#define UBC_WINSHIFT 16 /* 64kB */ +#endif +#ifndef UBC_NWINS +#define UBC_NWINS 4096 /* 256MB */ +#endif +#endif + /* * USRSTACK is the top (end) of the user stack. * @@ -125,12 +144,6 @@ #define VM_MAX_KERNEL_ADDRESS ((vaddr_t)0xffffffd000000000) #else /* Sv32 */ -/* - * kernel virtual space layout: - * 0x8000_0000 - 64GiB KERNEL VM Space (inc. text/data/bss) - * (0x4000_0000 +1GiB) KERNEL VM start of KVA - * (0x0000_0000 64GiB) reserved - */ /* * kernel virtual space layout without direct map (common case) @@ -154,13 +167,12 @@ * */ - - #define VM_MAXUSER_ADDRESS ((vaddr_t)-0x7fffffff-1)/* 0xffff_ffff_8000_0000 */ #define VM_MIN_KERNEL_ADDRESS ((vaddr_t)-0x7fffffff-1)/* 0xffff_ffff_8000_0000 */ #define VM_MAX_KERNEL_ADDRESS ((vaddr_t)-0x10000000) /* 0xffff_ffff_f000_0000 */ #endif + #define VM_KERNEL_BASE VM_MIN_KERNEL_ADDRESS #define VM_KERNEL_SIZE 0x2000000 /* 32 MiB (8 / 16 megapages) */ #define VM_KERNEL_DTB_BASE (VM_KERNEL_BASE + VM_KERNEL_SIZE) diff --git a/lib/libc/include/generic-netbsd/mips/pte.h b/lib/libc/include/generic-netbsd/mips/pte.h index 986baa4788a4a805c38fb9abf7a22b1be167ecd5..4b41ce44e84d89be8bbd496407183ae801fdbe8c 100644 --- a/lib/libc/include/generic-netbsd/mips/pte.h +++ b/lib/libc/include/generic-netbsd/mips/pte.h @@ -1,4 +1,4 @@ -/* $NetBSD: pte.h,v 1.27 2020/08/22 15:34:51 skrll Exp $ */ +/* $NetBSD: pte.h,v 1.27.28.1 2026/06/03 18:17:03 martin Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -269,6 +269,12 @@ pte_modified_p(pt_entry_t pte) return (pte & MIPS_MMU(PG_D)) != 0; } +static inline bool +pte_referenced_p(pt_entry_t pte) +{ + return false; +} + static inline bool pte_global_p(pt_entry_t pte) { @@ -340,11 +346,17 @@ pte_prot_downgrade(pt_entry_t pte, vm_prot_t prot) } static inline pt_entry_t -pte_prot_nowrite(pt_entry_t pte) +pte_clear_modify(pt_entry_t pte) { return pte & ~MIPS_MMU(PG_D); } +static inline pt_entry_t +pte_clear_reference(pt_entry_t pte) +{ + return pte; +} + static inline pt_entry_t pte_cached_change(pt_entry_t pte, bool cached) { diff --git a/lib/libc/include/generic-netbsd/netinet/tcp_timer.h b/lib/libc/include/generic-netbsd/netinet/tcp_timer.h index 0cef4010264fec7628c35943f450a5671cc554d3..b27152185d19fbc7ff1a3bcf9e299827b9e00871 100644 --- a/lib/libc/include/generic-netbsd/netinet/tcp_timer.h +++ b/lib/libc/include/generic-netbsd/netinet/tcp_timer.h @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_timer.h,v 1.30 2019/08/06 15:48:18 riastradh Exp $ */ +/* $NetBSD: tcp_timer.h,v 1.30.34.1 2026/07/19 15:51:03 martin Exp $ */ /*- * Copyright (c) 2001, 2005 The NetBSD Foundation, Inc. @@ -119,7 +119,7 @@ #define TCPTV_MSL ( 30*PR_SLOWHZ) /* max seg lifetime (hah!) */ #define TCPTV_SRTTBASE 0 /* base roundtrip time; if 0, no idea yet */ -#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ +#define TCPTV_SRTTDFLT ( 1*PR_SLOWHZ) /* initial RTO; RFC 6298 (2.1) */ #define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistance */ #define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ diff --git a/lib/libc/include/generic-netbsd/nfs/nfs.h b/lib/libc/include/generic-netbsd/nfs/nfs.h index 8759c291d4faa0fd0e63eb9967fc8c2429ece6a9..cb66894f3100cb4d2f5c27e5182ffce64249e2fa 100644 --- a/lib/libc/include/generic-netbsd/nfs/nfs.h +++ b/lib/libc/include/generic-netbsd/nfs/nfs.h @@ -1,4 +1,4 @@ -/* $NetBSD: nfs.h,v 1.81 2024/12/07 02:05:55 riastradh Exp $ */ +/* $NetBSD: nfs.h,v 1.81.2.1 2026/06/27 09:46:05 martin Exp $ */ /* * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. @@ -451,6 +451,8 @@ struct nfssvc_sock { int ns_sflags; /* b: */ int ns_cc; /* b: */ int ns_reclen; /* b: */ + int ns_frag_count; /* b: */ + int ns_streamlen; /* b: */ int ns_numuids; u_int32_t ns_sref; /* g: */ SIMPLEQ_HEAD(, nfsrv_descript) ns_sendq; /* s: send reply list */ diff --git a/lib/libc/include/generic-netbsd/nfs/nfsmount.h b/lib/libc/include/generic-netbsd/nfs/nfsmount.h index 2a38bbd2cc5d098a77903043f413a503c9201453..8c418f4509b62647c63be23a70ec5e7272aeb684 100644 --- a/lib/libc/include/generic-netbsd/nfs/nfsmount.h +++ b/lib/libc/include/generic-netbsd/nfs/nfsmount.h @@ -1,4 +1,4 @@ -/* $NetBSD: nfsmount.h,v 1.54 2024/12/07 02:05:55 riastradh Exp $ */ +/* $NetBSD: nfsmount.h,v 1.54.2.1 2026/06/03 18:46:36 martin Exp $ */ /* * Copyright (c) 1989, 1993 @@ -92,13 +92,15 @@ struct nfs_args { #define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ #define NFSMNT_XLATECOOKIE 0x00040000 /* 32<->64 dir cookie xlation */ #define NFSMNT_NOAC 0x00080000 /* Turn off attribute cache */ +#define NFSMNT_NOWCCMSG 0x00100000 /* Turn off attribute wcc messages */ #define NFSMNT_BITS "\177\20" \ "b\00soft\0b\01wsize\0b\02rsize\0b\03timeo\0" \ "b\04retrans\0b\05maxgrps\0b\06intr\0b\07noconn\0" \ "b\10nqnfs\0b\11nfsv3\0b\12kerb\0b\13dumbtimr\0" \ "b\14leaseterm\0b\15readahead\0b\16deadthresh\0b\17resvport\0" \ - "b\20rdirplus\0b\21readdirsize\0b\22xlatecookie\0b\23noac\0" + "b\20rdirplus\0b\21readdirsize\0b\22xlatecookie\0b\23noac\0" \ + "b\24nowccmsg\0" /* * NFS internal flags (nm_iflag) */ diff --git a/lib/libc/include/generic-netbsd/pthread.h b/lib/libc/include/generic-netbsd/pthread.h index b530af73b802a2ce1cab22be7c9e422d90d08a0d..0d201332f4cb7fb92b1d13f4af7ccb37728ae4ca 100644 --- a/lib/libc/include/generic-netbsd/pthread.h +++ b/lib/libc/include/generic-netbsd/pthread.h @@ -461,4 +461,4 @@ __END_DECLS #endif /* __LIBPTHREAD_SOURCE__ */ -#endif /* _LIB_PTHREAD_H */ +#endif /* _LIB_PTHREAD_H */ \ No newline at end of file diff --git a/lib/libc/include/generic-netbsd/riscv/pte.h b/lib/libc/include/generic-netbsd/riscv/pte.h index 760dc280552255428ff7144e68346bb813c363cd..f19d4ffe10144f61bc3ef3a8fd35d06a81de4c78 100644 --- a/lib/libc/include/generic-netbsd/riscv/pte.h +++ b/lib/libc/include/generic-netbsd/riscv/pte.h @@ -1,4 +1,4 @@ -/* $NetBSD: pte.h,v 1.14.2.2 2025/10/26 12:28:36 martin Exp $ */ +/* $NetBSD: pte.h,v 1.14.2.3 2026/06/03 18:17:02 martin Exp $ */ /* * Copyright (c) 2014, 2019, 2021 The NetBSD Foundation, Inc. @@ -139,6 +139,12 @@ pte_modified_p(pt_entry_t pte) return (pte & PTE_D) != 0; } +static inline bool +pte_referenced_p(pt_entry_t pte) +{ + return (pte & PTE_A) != 0; +} + static inline bool pte_cached_p(pt_entry_t pte) { @@ -177,9 +183,15 @@ pte_nv_entry(bool kernel_p) } static inline pt_entry_t -pte_prot_nowrite(pt_entry_t pte) +pte_clear_modify(pt_entry_t pte) { - return pte & ~PTE_W; + return pte & ~PTE_D; +} + +static inline pt_entry_t +pte_clear_reference(pt_entry_t pte) +{ + return pte & ~PTE_A; } static inline pt_entry_t @@ -237,28 +249,29 @@ pte_make_enter(paddr_t pa, struct vm_page_md *mdpg, vm_prot_t prot, pte |= pte_prot_bits(mdpg, prot, kernel_p); pte |= pte_enter_flags_to_pbmt(flags); + /* + * pmap_enter should have checked flags and updated + * VM_PAGEMD_{REFERENCED,MODIFIED}_P, so there is no + * need here. + */ + KASSERT(((flags & VM_PROT_ALL) == 0) || VM_PAGEMD_REFERENCED_P(mdpg)); + KASSERT(((flags & VM_PROT_WRITE) == 0) || VM_PAGEMD_MODIFIED_P(mdpg)); + if (mdpg != NULL) { - - if ((prot & VM_PROT_WRITE) != 0 && - ((flags & VM_PROT_WRITE) != 0 || VM_PAGEMD_MODIFIED_P(mdpg))) { + if ((prot & VM_PROT_WRITE) != 0 && VM_PAGEMD_MODIFIED_P(mdpg)) { /* - * This is a writable mapping, and the page's mod state - * indicates it has already been modified. No need for - * modified emulation. - */ + * This is a writable mapping, and the page's mod state + * indicates it has already been modified. No need for + * reference or modified emulation. + */ pte |= PTE_A | PTE_D; - } else if ((flags & VM_PROT_ALL) || VM_PAGEMD_REFERENCED_P(mdpg)) { + } else if (VM_PAGEMD_REFERENCED_P(mdpg)) { /* - * - The access type indicates that we don't need to do - * referenced emulation. - * OR - * - The physical page has already been referenced so no need - * to re-do referenced emulation here. - */ + * The physical page has already been referenced so no need + * to re-do referenced emulation here. + */ pte |= PTE_A; } - } else { - pte |= PTE_A | PTE_D; } return pte; diff --git a/lib/libc/include/generic-netbsd/riscv/vmparam.h b/lib/libc/include/generic-netbsd/riscv/vmparam.h index b483e18e8574ce42273a16ae6e90df2b10157c6c..ba9c754dce496cd5d52b0bda02691afeba05e979 100644 --- a/lib/libc/include/generic-netbsd/riscv/vmparam.h +++ b/lib/libc/include/generic-netbsd/riscv/vmparam.h @@ -1,4 +1,4 @@ -/* $NetBSD: vmparam.h,v 1.14 2023/05/07 12:41:48 skrll Exp $ */ +/* $NetBSD: vmparam.h,v 1.14.8.2 2026/06/03 18:17:02 martin Exp $ */ /*- * Copyright (c) 2014, 2020 The NetBSD Foundation, Inc. @@ -50,6 +50,25 @@ #define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK (PAGE_SIZE - 1) +#ifdef _LP64 +/* + * Default pager_map of 16MB is awfully small. There is plenty + * of VA so use it. + */ +#define PAGER_MAP_DEFAULT_SIZE (512 * 1024 * 1024) + +/* + * Defaults for Unified Buffer Cache parameters. + */ + +#ifndef UBC_WINSHIFT +#define UBC_WINSHIFT 16 /* 64kB */ +#endif +#ifndef UBC_NWINS +#define UBC_NWINS 4096 /* 256MB */ +#endif +#endif + /* * USRSTACK is the top (end) of the user stack. * @@ -125,12 +144,6 @@ #define VM_MAX_KERNEL_ADDRESS ((vaddr_t)0xffffffd000000000) #else /* Sv32 */ -/* - * kernel virtual space layout: - * 0x8000_0000 - 64GiB KERNEL VM Space (inc. text/data/bss) - * (0x4000_0000 +1GiB) KERNEL VM start of KVA - * (0x0000_0000 64GiB) reserved - */ /* * kernel virtual space layout without direct map (common case) @@ -154,13 +167,12 @@ * */ - - #define VM_MAXUSER_ADDRESS ((vaddr_t)-0x7fffffff-1)/* 0xffff_ffff_8000_0000 */ #define VM_MIN_KERNEL_ADDRESS ((vaddr_t)-0x7fffffff-1)/* 0xffff_ffff_8000_0000 */ #define VM_MAX_KERNEL_ADDRESS ((vaddr_t)-0x10000000) /* 0xffff_ffff_f000_0000 */ #endif + #define VM_KERNEL_BASE VM_MIN_KERNEL_ADDRESS #define VM_KERNEL_SIZE 0x2000000 /* 32 MiB (8 / 16 megapages) */ #define VM_KERNEL_DTB_BASE (VM_KERNEL_BASE + VM_KERNEL_SIZE) diff --git a/lib/libc/include/generic-netbsd/sys/fcntl.h b/lib/libc/include/generic-netbsd/sys/fcntl.h index af43c74a3daca814d873e6bda87f497dc6f0de4b..311effadd406e25dae75c281ff217008e87ab001 100644 --- a/lib/libc/include/generic-netbsd/sys/fcntl.h +++ b/lib/libc/include/generic-netbsd/sys/fcntl.h @@ -1,4 +1,4 @@ -/* $NetBSD: fcntl.h,v 1.57 2025/07/25 23:24:46 kre Exp $ */ +/* $NetBSD: fcntl.h,v 1.57.2.1 2026/06/16 09:06:50 martin Exp $ */ /*- * Copyright (c) 1983, 1990, 1993 @@ -121,6 +121,9 @@ #if defined(_NETBSD_SOURCE) #define O_NOSIGPIPE 0x01000000 /* don't deliver sigpipe */ #define O_REGULAR 0x02000000 /* fail if not a regular file */ +#endif +#if (_POSIX_C_SOURCE - 0) >= 200809L || (_XOPEN_SOURCE - 0 >= 700) || \ + defined(_NETBSD_SOURCE) #define O_EXEC 0x04000000 /* open for executing only */ #endif #if (_POSIX_C_SOURCE - 0) >= 202405L || (_XOPEN_SOURCE - 0 >= 800) || \ diff --git a/lib/libc/include/generic-netbsd/sys/lua.h b/lib/libc/include/generic-netbsd/sys/lua.h index 2657da9e21de60c9a06eb7fcc80afbe6441cc2d2..8c820f69cd81e6074d2b75cf825eb63b1ceca35c 100644 --- a/lib/libc/include/generic-netbsd/sys/lua.h +++ b/lib/libc/include/generic-netbsd/sys/lua.h @@ -1,4 +1,4 @@ -/* $NetBSD: lua.h,v 1.9 2023/07/11 14:57:21 martin Exp $ */ +/* $NetBSD: lua.h,v 1.9.8.1 2026/06/29 19:52:23 martin Exp $ */ /* * Copyright (c) 2014 by Lourival Vieira Neto . @@ -33,7 +33,9 @@ #define _SYS_LUA_H_ #include + #include +#include #include /* for lua_State */ diff --git a/lib/libc/include/generic-netbsd/sys/param.h b/lib/libc/include/generic-netbsd/sys/param.h index 2590fadb10c70c69eb8735d851e4111e9206e7e3..423ccfd7ce7797dfeebb3008147363821784d01b 100644 --- a/lib/libc/include/generic-netbsd/sys/param.h +++ b/lib/libc/include/generic-netbsd/sys/param.h @@ -1,4 +1,4 @@ -/* $NetBSD: param.h,v 1.738.2.5 2026/05/12 04:23:51 martin Exp $ */ +/* $NetBSD: param.h,v 1.738.2.9 2026/07/30 15:23:12 martin Exp $ */ /*- * Copyright (c) 1982, 1986, 1989, 1993 @@ -566,4 +566,4 @@ extern size_t coherency_unit; #endif #endif /* !__ASSEMBLER__ */ -#endif /* !_SYS_PARAM_H_ */ +#endif /* !_SYS_PARAM_H_ */ \ No newline at end of file diff --git a/lib/libc/include/generic-netbsd/x86/cpu_extended_state.h b/lib/libc/include/generic-netbsd/x86/cpu_extended_state.h index ccad28305b4e3e4f49b5940ee1b98361e10887e8..d45664ead197649dcde26de0dbef00d29ffc8a55 100644 --- a/lib/libc/include/generic-netbsd/x86/cpu_extended_state.h +++ b/lib/libc/include/generic-netbsd/x86/cpu_extended_state.h @@ -1,4 +1,4 @@ -/* $NetBSD: cpu_extended_state.h,v 1.19 2025/04/24 01:50:39 riastradh Exp $ */ +/* $NetBSD: cpu_extended_state.h,v 1.19.2.1 2026/07/19 15:57:27 martin Exp $ */ #ifndef _X86_CPU_EXTENDED_STATE_H_ #define _X86_CPU_EXTENDED_STATE_H_ @@ -142,6 +142,8 @@ struct xsave_header { }; __CTASSERT(sizeof(struct xsave_header) == 512 + 64); +#define XSAVE_ALIGN 64 + /* * The ymm save area actually follows the xsave_header. */ diff --git a/lib/libc/include/generic-netbsd/x86/fpu.h b/lib/libc/include/generic-netbsd/x86/fpu.h index 311cd9655549bab305e2c74063d7649da9649a93..e1280905a59724cfc05cb74005d9f3cb7d6a25d8 100644 --- a/lib/libc/include/generic-netbsd/x86/fpu.h +++ b/lib/libc/include/generic-netbsd/x86/fpu.h @@ -1,4 +1,4 @@ -/* $NetBSD: fpu.h,v 1.23 2020/10/24 07:14:29 mgorny Exp $ */ +/* $NetBSD: fpu.h,v 1.23.28.1 2026/07/19 15:57:27 martin Exp $ */ #ifndef _X86_FPU_H_ #define _X86_FPU_H_ @@ -46,6 +46,12 @@ int process_read_xstate(struct lwp *, struct xstate *); int process_verify_xstate(const struct xstate *); int process_write_xstate(struct lwp *, const struct xstate *); +bool process_xsave_needed_p(struct lwp *); +void process_read_xsave(struct lwp *, const struct xsave_header **, size_t *); +int process_verify_xsavelen(struct lwp *, size_t); +int process_verify_xsave(struct lwp *, const struct xsave_header *, size_t); +void process_write_xsave(struct lwp *, const struct xsave_header *, size_t); + #endif #endif /* _X86_FPU_H_ */ \ No newline at end of file diff --git a/lib/libc/include/generic-netbsd/x86/specialreg.h b/lib/libc/include/generic-netbsd/x86/specialreg.h index 5158f8c4fab86eabf620d0c69394165e4d9d1707..36635ca349a1a9d3459471f003074119c1a94c0c 100644 --- a/lib/libc/include/generic-netbsd/x86/specialreg.h +++ b/lib/libc/include/generic-netbsd/x86/specialreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: specialreg.h,v 1.219 2025/04/28 13:01:27 riastradh Exp $ */ +/* $NetBSD: specialreg.h,v 1.219.2.1 2026/07/19 15:57:27 martin Exp $ */ /* * Copyright (c) 2014-2020 The NetBSD Foundation, Inc. @@ -183,16 +183,82 @@ "\0" /* - * Known FPU bits, only these get enabled. The save area is sized for all the - * fields below. + * XCR0_FPU: Known FPU bits, only these get enabled. The save area is + * sized for all the fields below. + * + * Any bits added to this will expand the extended CPU state that we + * may have to save and restore with XSAVE for userland processes, + * either in the kernel when preempting threads, or on the user's stack + * when delivering a signal. + * + * The kernel can dyanmically allocate larger sizes (on amd64, anyway, + * though not currently on i386 or Xen PV). But if the XSAVE area is + * expanded so much that it and mcontext_t exceed MINSIGSTKSZ + * (currently 8192), a userland ABI change and compatibility layer is + * required to accommodate that, because existing programs may use + * sigaltstack(2) with stacks sized for the old MINSIGSTKSZ. + * + * The current stack requirement is 3160 bytes of space plus up to + * 63+15+8=86 bytes of padding for alignment (could be reduced by + * around 512 bytes by having mcontext_t overlap with the XSAVE area a + * little in machdep.c cpu_getmcontext_xsave, but we don't do that + * right now): + * + * - mcontext_t (728 bytes: general registers and 512-byte FXSAVE area) + * - XSAVE header (576 bytes: 512 bytes of FXSAVE, 64 bytes of metadata) + * - AVX state: ymm0..ymm15 high 128-bit halves (256 bytes) + * - AVX-512 state: + * . k0..k7 opmask registers (64 bytes) + * . zmm0..zmm15 high 256-bit halves (512 bytes) + * . zmm16..zmm31 registers (1024 bytes) + * + * Likely future extensions that would expand the state beyond + * MINSIGSTKSZ: + * + * - AMX (Advanced Matrix Extensions) and ACE (AI Compute Extensions) + * state: + * . [AMX/ACE] TILECFG (64 bytes) + * . [AMX/ACE] TILEDATA (8192 bytes) + * . [ACE] SCALEDATA (128 bytes) + * + * As a precaution against ABI breakage, x86/identcpu.c will panic at + * boot if the XSAVE state size enabled in XCR0 exceeds MINSIGSTKSZ. + * + * References: + * + * - Intel 64 and IA-32 Architectures Software Developer's Manual, + * Volume 1: Basic Architecture, Intel, Order Number: 253665-092US, + * June 2026, Sec. 13.1 `XSAVE-Supported Features and State-Component + * Bitmaps', pp. 13-1 -- 13-2. + * https://web.archive.org/web/20260709150417/https://cdrdv2-public.intel.com/922477/253665-092-sdm-vol-1.pdf + * + * - AI Compute Extensions (ACE) Specification, x86 Ecosystem Advisory + * Group, Version 1.15, 2026-05-15, Sec 15.4.1 `XSAVE State + * Components', p. 86. + * https://web.archive.org/web/20260619062626/https://x86ecosystem.org/wp-content/uploads/2026/06/ACE_v1_Specification_public_1_15.pdf */ #if defined __i386__ || defined XENPV /* XXX XENPV PR kern/59371 */ #define XCR0_FPU (XCR0_X87 | XCR0_SSE | XCR0_YMM_Hi128 | \ XCR0_Opmask | XCR0_ZMM_Hi256 | XCR0_Hi16_ZMM) #else #define XCR0_FPU (XCR0_X87 | XCR0_SSE | XCR0_YMM_Hi128 | \ - XCR0_Opmask | XCR0_ZMM_Hi256 | XCR0_Hi16_ZMM | \ - XCR0_TILECFG | XCR0_TILEDATA) + XCR0_Opmask | XCR0_ZMM_Hi256 | XCR0_Hi16_ZMM) +#endif + +/* + * Maximum size of XSAVE state that we can handle without ABI changes + * to userland. Must match usage in cpu_getmcontext. Extra 8 is neeed + * on amd64 to have space for return address in 16-byte-aligned stack + * frame. + */ +#ifdef __x86_64__ +#define XSAVE_MAX_BYTES \ + (MINSIGSTKSZ - (8 + STACK_ALIGNBYTES + \ + sizeof(struct sigframe_siginfo) + (XSAVE_ALIGN - 1))) +#else +#define XSAVE_MAX_BYTES \ + (MINSIGSTKSZ - (STACK_ALIGNBYTES + \ + sizeof(struct sigframe_siginfo) + (XSAVE_ALIGN - 1))) #endif /* diff --git a/lib/libc/include/loongarch-linux-gnu/bits/hwcap.h b/lib/libc/include/loongarch-linux-gnu/bits/hwcap.h index d6335ffaa97c3c61cd1452cd3f01b8fc0903aa9d..72f26b63da5cbca1bac2ca0cbce6d3ff5f21c398 100644 --- a/lib/libc/include/loongarch-linux-gnu/bits/hwcap.h +++ b/lib/libc/include/loongarch-linux-gnu/bits/hwcap.h @@ -36,4 +36,6 @@ #define HWCAP_LOONGARCH_LBT_ARM (1 << 11) #define HWCAP_LOONGARCH_LBT_MIPS (1 << 12) #define HWCAP_LOONGARCH_PTW (1 << 13) -#define HWCAP_LOONGARCH_LSPW (1 << 14) \ No newline at end of file +#define HWCAP_LOONGARCH_LSPW (1 << 14) +#define HWCAP_LOONGARCH_SCQ (1 << 15) +#define HWCAP_LOONGARCH_LAM_BH (1 << 16) \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/bits/long-double.h b/lib/libc/include/loongarch-linux-gnu/bits/long-double.h deleted file mode 100644 index af7784dbe6dd85cd9538b5a7b437ab45de22eeb8..0000000000000000000000000000000000000000 --- a/lib/libc/include/loongarch-linux-gnu/bits/long-double.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Properties of long double type. ldbl-128 version. - Copyright (C) 2016-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* long double is distinct from double, so there is nothing to - define here. */ -#define __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI 0 \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/bits/struct_stat.h b/lib/libc/include/loongarch-linux-gnu/bits/struct_stat.h deleted file mode 100644 index 0462d37a6849812f485a6830a7c0dca303332636..0000000000000000000000000000000000000000 --- a/lib/libc/include/loongarch-linux-gnu/bits/struct_stat.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Definition for struct stat. - Copyright (C) 2020-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#if !defined _SYS_STAT_H && !defined _FCNTL_H -# error "Never include directly; use instead." -#endif - -#ifndef _BITS_STRUCT_STAT_H -#define _BITS_STRUCT_STAT_H 1 - -#include -#include - -#if defined __USE_FILE_OFFSET64 -# define __field64(type, type64, name) type64 name -#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T -# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T -# error "ino_t and off_t must both be the same type" -# endif -# define __field64(type, type64, name) type name -#elif __BYTE_ORDER == __LITTLE_ENDIAN -# define __field64(type, type64, name) \ - type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad -#else -# define __field64(type, type64, name) \ - int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name -#endif - -struct stat - { - __dev_t st_dev; /* Device. */ - __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; - -#undef __field64 - -#ifdef __USE_LARGEFILE64 -struct stat64 - { - __dev_t st_dev; /* Device. */ - __ino64_t st_ino; /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __off64_t st_size; /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; -#endif - -/* Tell code we have these members. */ -#define _STATBUF_ST_BLKSIZE -#define _STATBUF_ST_RDEV -/* Nanosecond resolution time values are supported. */ -#define _STATBUF_ST_NSEC - -#endif /* _BITS_STRUCT_STAT_H */ \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/bits/timesize.h b/lib/libc/include/loongarch-linux-gnu/bits/timesize.h deleted file mode 100644 index dff2da5ed6bf30ce6f5580aee352e0958d58b623..0000000000000000000000000000000000000000 --- a/lib/libc/include/loongarch-linux-gnu/bits/timesize.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Bit size of the time_t type at glibc build time, general case. - Copyright (C) 2018-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* Size in bits of the 'time_t' type of the default ABI. */ -#define __TIMESIZE 64 \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/bits/wordsize.h b/lib/libc/include/loongarch-linux-gnu/bits/wordsize.h index 5038df494751b3446f652bcb4d1c5d3e721a61ec..d4d561400b42e6e7004737b99bd8d82f6dc2a4f7 100644 --- a/lib/libc/include/loongarch-linux-gnu/bits/wordsize.h +++ b/lib/libc/include/loongarch-linux-gnu/bits/wordsize.h @@ -15,5 +15,16 @@ License along with the GNU C Library; if not, see . */ -#define __WORDSIZE 64 -#define __WORDSIZE_TIME64_COMPAT32 0 \ No newline at end of file +// zig patch: handle 32-bit and 64-bit in the same header +#if __loongarch_grlen == (__SIZEOF_POINTER__ * 8) +# define __WORDSIZE __loongarch_grlen +#else +# error unsupported ABI +#endif + +#define __WORDSIZE_TIME64_COMPAT32 0 + +#if __WORDSIZE == 32 +# define __WORDSIZE32_SIZE_ULONG 0 +# define __WORDSIZE32_PTRDIFF_LONG 0 +#endif diff --git a/lib/libc/include/loongarch-linux-gnu/fpu_control.h b/lib/libc/include/loongarch-linux-gnu/fpu_control.h index 69cd4213c79b5db9e6c6ec60dc454c8177c8ba6d..2a2354d760dcfaa389df58e0a942d4a679994387 100644 --- a/lib/libc/include/loongarch-linux-gnu/fpu_control.h +++ b/lib/libc/include/loongarch-linux-gnu/fpu_control.h @@ -94,6 +94,15 @@ extern void __loongarch_fpu_setcw (fpu_control_t) __THROW; #define _FPU_GETCW(cw) __asm__ volatile ("movfcsr2gr %0,$fcsr0" : "=r"(cw)) #define _FPU_SETCW(cw) __asm__ volatile ("movgr2fcsr $fcsr0,%0" : : "r"(cw)) +#define _FPU_GET_ENABLES(cw) __asm__ volatile ("movfcsr2gr %0,$fcsr1" : "=r"(cw)) +#define _FPU_SET_ENABLES(cw) __asm__ volatile ("movgr2fcsr $fcsr1,%0" : : "r"(cw)) + +#define _FPU_GET_FLAGS_CAUSE(cw) __asm__ volatile ("movfcsr2gr %0,$fcsr2" : "=r"(cw)) +#define _FPU_SET_FLAGS_CAUSE(cw) __asm__ volatile ("movgr2fcsr $fcsr2,%0" : : "r"(cw)) + +#define _FPU_GET_RM(cw) __asm__ volatile ("movfcsr2gr %0,$fcsr3" : "=r"(cw)) +#define _FPU_SET_RM(cw) __asm__ volatile ("movgr2fcsr $fcsr3,%0" : : "r"(cw)) + /* Default control word set at startup. */ extern fpu_control_t __fpu_control; diff --git a/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-ilp32d.h b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-ilp32d.h new file mode 100644 index 0000000000000000000000000000000000000000..f0780d70ef3f21f2e1cefa6f15f2bbc34c5ec651 --- /dev/null +++ b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-ilp32d.h @@ -0,0 +1,28 @@ +/* This file is automatically generated. */ +#ifndef __GNU_LIB_NAMES_H +# error "Never use directly; include instead." +#endif + +#define LD_LINUX_LOONGARCH_ILP32D_SO "ld-linux-loongarch-ilp32d.so.1" +#define LD_SO "ld-linux-loongarch-ilp32d.so.1" +#define LIBANL_SO "libanl.so.1" +#define LIBBROKENLOCALE_SO "libBrokenLocale.so.1" +#define LIBC_MALLOC_DEBUG_SO "libc_malloc_debug.so.0" +#define LIBC_SO "libc.so.6" +#define LIBDL_SO "libdl.so.2" +#define LIBGCC_S_SO "libgcc_s.so.1" +#define LIBMVEC_SO "libmvec.so.1" +#define LIBM_SO "libm.so.6" +#define LIBNSL_SO "libnsl.so.1" +#define LIBNSS_COMPAT_SO "libnss_compat.so.2" +#define LIBNSS_DB_SO "libnss_db.so.2" +#define LIBNSS_DNS_SO "libnss_dns.so.2" +#define LIBNSS_FILES_SO "libnss_files.so.2" +#define LIBNSS_HESIOD_SO "libnss_hesiod.so.2" +#define LIBNSS_LDAP_SO "libnss_ldap.so.2" +#define LIBPTHREAD_SO "libpthread.so.0" +#define LIBRESOLV_SO "libresolv.so.2" +#define LIBRT_SO "librt.so.1" +#define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" +#define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-ilp32s.h b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-ilp32s.h new file mode 100644 index 0000000000000000000000000000000000000000..012654c98f178fc1163e564175ccf9aee4521874 --- /dev/null +++ b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-ilp32s.h @@ -0,0 +1,28 @@ +/* This file is automatically generated. */ +#ifndef __GNU_LIB_NAMES_H +# error "Never use directly; include instead." +#endif + +#define LD_LINUX_LOONGARCH_ILP32S_SO "ld-linux-loongarch-ilp32s.so.1" +#define LD_SO "ld-linux-loongarch-ilp32s.so.1" +#define LIBANL_SO "libanl.so.1" +#define LIBBROKENLOCALE_SO "libBrokenLocale.so.1" +#define LIBC_MALLOC_DEBUG_SO "libc_malloc_debug.so.0" +#define LIBC_SO "libc.so.6" +#define LIBDL_SO "libdl.so.2" +#define LIBGCC_S_SO "libgcc_s.so.1" +#define LIBMVEC_SO "libmvec.so.1" +#define LIBM_SO "libm.so.6" +#define LIBNSL_SO "libnsl.so.1" +#define LIBNSS_COMPAT_SO "libnss_compat.so.2" +#define LIBNSS_DB_SO "libnss_db.so.2" +#define LIBNSS_DNS_SO "libnss_dns.so.2" +#define LIBNSS_FILES_SO "libnss_files.so.2" +#define LIBNSS_HESIOD_SO "libnss_hesiod.so.2" +#define LIBNSS_LDAP_SO "libnss_ldap.so.2" +#define LIBPTHREAD_SO "libpthread.so.0" +#define LIBRESOLV_SO "libresolv.so.2" +#define LIBRT_SO "librt.so.1" +#define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" +#define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-lp64d.h b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-lp64d.h index 8f030679c89545ea0ac048e744799051778f0b2c..000df5a7ec275335f903b9ce6a53861189deeca6 100644 --- a/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-lp64d.h +++ b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-lp64d.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-lp64s.h b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-lp64s.h index 7c8b796194b2f179d2dfddbd0a7040a76ba37aeb..0a812d367cac3923d148b019ece28f5698001930 100644 --- a/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-lp64s.h +++ b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names-lp64s.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/gnu/lib-names.h b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names.h index c3eba41e095a1705b8478909b27017a74c8a7ff5..d7367183c2d250b519e7fc3018c51b7751930f2e 100644 --- a/lib/libc/include/loongarch-linux-gnu/gnu/lib-names.h +++ b/lib/libc/include/loongarch-linux-gnu/gnu/lib-names.h @@ -6,6 +6,12 @@ #include +#if __WORDSIZE == 32 && defined __loongarch_soft_float +# include +#endif +#if __WORDSIZE == 32 && defined __loongarch_double_float +# include +#endif #if __WORDSIZE == 64 && defined __loongarch_soft_float # include #endif diff --git a/lib/libc/include/loongarch-linux-gnu/gnu/stubs-ilp32d.h b/lib/libc/include/loongarch-linux-gnu/gnu/stubs-ilp32d.h new file mode 100644 index 0000000000000000000000000000000000000000..4c2911dd6d66a591544d5c76448086f5de7b36d5 --- /dev/null +++ b/lib/libc/include/loongarch-linux-gnu/gnu/stubs-ilp32d.h @@ -0,0 +1,21 @@ +/* This file is automatically generated. + It defines a symbol `__stub_FUNCTION' for each function + in the C library which is a stub, meaning it will fail + every time called, usually setting errno to ENOSYS. */ + +#ifdef _LIBC + #error Applications may not define the macro _LIBC +#endif + +#define __stub___compat_bdflush +#define __stub___compat_create_module +#define __stub___compat_get_kernel_syms +#define __stub___compat_query_module +#define __stub___compat_uselib +#define __stub_chflags +#define __stub_fchflags +#define __stub_gtty +#define __stub_revoke +#define __stub_setlogin +#define __stub_sigreturn +#define __stub_stty \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/gnu/stubs-ilp32s.h b/lib/libc/include/loongarch-linux-gnu/gnu/stubs-ilp32s.h new file mode 100644 index 0000000000000000000000000000000000000000..6ce02418e69609f4642a522910708769e96d6ee9 --- /dev/null +++ b/lib/libc/include/loongarch-linux-gnu/gnu/stubs-ilp32s.h @@ -0,0 +1,38 @@ +/* This file is automatically generated. + It defines a symbol `__stub_FUNCTION' for each function + in the C library which is a stub, meaning it will fail + every time called, usually setting errno to ENOSYS. */ + +#ifdef _LIBC + #error Applications may not define the macro _LIBC +#endif + +#define __stub___compat_bdflush +#define __stub___compat_create_module +#define __stub___compat_get_kernel_syms +#define __stub___compat_query_module +#define __stub___compat_uselib +#define __stub_chflags +#define __stub_fchflags +#define __stub_feclearexcept +#define __stub_fedisableexcept +#define __stub_feenableexcept +#define __stub_fegetenv +#define __stub_fegetexcept +#define __stub_fegetexceptflag +#define __stub_fegetmode +#define __stub_fegetround +#define __stub_feholdexcept +#define __stub_feraiseexcept +#define __stub_fesetenv +#define __stub_fesetexcept +#define __stub_fesetexceptflag +#define __stub_fesetmode +#define __stub_fesetround +#define __stub_fetestexcept +#define __stub_feupdateenv +#define __stub_gtty +#define __stub_revoke +#define __stub_setlogin +#define __stub_sigreturn +#define __stub_stty \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-gnu/gnu/stubs.h b/lib/libc/include/loongarch-linux-gnu/gnu/stubs.h index ea3f10c4213c01ccc0c0dd0fd9aef9b114ddf0cd..694ca60a5bfeabaa4e0ea8b594839408d21be11d 100644 --- a/lib/libc/include/loongarch-linux-gnu/gnu/stubs.h +++ b/lib/libc/include/loongarch-linux-gnu/gnu/stubs.h @@ -4,6 +4,12 @@ #include +#if __WORDSIZE == 32 && defined __loongarch_soft_float +# include +#endif +#if __WORDSIZE == 32 && defined __loongarch_double_float +# include +#endif #if __WORDSIZE == 64 && defined __loongarch_soft_float # include #endif diff --git a/lib/libc/include/loongarch-linux-gnu/sys/asm.h b/lib/libc/include/loongarch-linux-gnu/sys/asm.h index 973feb6effa26ea10d6b1af85ce2784a32ec8135..17465154a3ebe02d36cdf4b013c23acad75a58d4 100644 --- a/lib/libc/include/loongarch-linux-gnu/sys/asm.h +++ b/lib/libc/include/loongarch-linux-gnu/sys/asm.h @@ -23,10 +23,8 @@ #include /* Macros to handle different pointer/register sizes for 32/64-bit code. */ +#if __loongarch_grlen == 64 #define SZREG 8 -#define SZFREG 8 -#define SZVREG 16 -#define SZXREG 32 #define REG_L ld.d #define REG_S st.d #define SRLI srli.d @@ -34,10 +32,38 @@ #define ADDI addi.d #define ADD add.d #define SUB sub.d -#define BSTRINS bstrins.d #define LI li.d -#define FREG_L fld.d -#define FREG_S fst.d +#define BSTRINS bstrins.d + +#elif __loongarch_grlen == 32 + +#define SZREG 4 +#define REG_L ld.w +#define REG_S st.w +#define SRLI srli.w +#define SLLI slli.w +#define ADDI addi.w +#define ADD add.w +#define SUB sub.w +#define LI li.w +#define BSTRINS bstrins.w + +#else +#error __loongarch_grlen must equal 32 or 64 +#endif + +#if __loongarch_frlen == 64 + #define SZFREG 8 + #define FREG_L fld.d + #define FREG_S fst.d +#elif __loongarch_frlen == 32 + #define SZFREG 4 + #define FREG_L fld.s + #define FREG_S fst.s +#endif + +#define SZVREG 16 +#define SZXREG 32 /* Declare leaf routine. The usage of macro LEAF/ENTRY is as follows: diff --git a/lib/libc/include/m68k-linux-gnu/gnu/lib-names.h b/lib/libc/include/m68k-linux-gnu/gnu/lib-names.h index f72e37a69b31d263771248ddb6141300af975b2e..82aba9b01dc90b844da3f9efb076aa950cc5e348 100644 --- a/lib/libc/include/m68k-linux-gnu/gnu/lib-names.h +++ b/lib/libc/include/m68k-linux-gnu/gnu/lib-names.h @@ -24,6 +24,7 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" #endif /* gnu/lib-names.h */ \ No newline at end of file diff --git a/lib/libc/include/mips-linux-gnu/bits/long-double.h b/lib/libc/include/mips-linux-gnu/bits/long-double.h new file mode 100644 index 0000000000000000000000000000000000000000..ebf6ac878fbf42241d0b2bcaf8c6049d08d827c5 --- /dev/null +++ b/lib/libc/include/mips-linux-gnu/bits/long-double.h @@ -0,0 +1,24 @@ +/* Properties of long double type. MIPS version. + Copyright (C) 2016-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#if !defined __NO_LONG_DOUBLE_MATH && _MIPS_SIM == _ABIO32 +# define __NO_LONG_DOUBLE_MATH 1 +#endif +#define __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI 0 \ No newline at end of file diff --git a/lib/libc/include/mips-linux-gnu/bits/struct_stat.h b/lib/libc/include/mips-linux-gnu/bits/struct_stat.h new file mode 100644 index 0000000000000000000000000000000000000000..231c875e7ab2c703e50746e2191ddc411c0878a2 --- /dev/null +++ b/lib/libc/include/mips-linux-gnu/bits/struct_stat.h @@ -0,0 +1,237 @@ +/* Definition for struct stat. + Copyright (C) 2020-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#if !defined _SYS_STAT_H && !defined _FCNTL_H +# error "Never include directly; use instead." +#endif + +#ifndef _BITS_STRUCT_STAT_H +#define _BITS_STRUCT_STAT_H 1 + +#include + +#if _MIPS_SIM == _ABIO32 +/* Structure describing file characteristics. */ +struct stat + { +# ifdef __USE_TIME64_REDIRECTS +# include +# else + unsigned long int st_dev; + long int st_pad1[3]; +# ifndef __USE_FILE_OFFSET64 + __ino_t st_ino; /* File serial number. */ +# else + __ino64_t st_ino; /* File serial number. */ +# endif + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + unsigned long int st_rdev; /* Device number, if device. */ +# ifndef __USE_FILE_OFFSET64 + long int st_pad2[2]; + __off_t st_size; /* Size of file, in bytes. */ + /* SVR4 added this extra long to allow for expansion of off_t. */ + long int st_pad3; +# else + long int st_pad2[3]; + __off64_t st_size; /* Size of file, in bytes. */ +# endif +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + __blksize_t st_blksize; /* Optimal block size for I/O. */ +# ifndef __USE_FILE_OFFSET64 + __blkcnt_t st_blocks; /* Number of 512-byte blocks allocated. */ +# else + long int st_pad4; + __blkcnt64_t st_blocks; /* Number of 512-byte blocks allocated. */ +# endif + long int st_pad5[14]; +# endif /* __USE_TIME64_REDIRECTS */ + }; + +# ifdef __USE_LARGEFILE64 +struct stat64 + { +# ifdef __USE_TIME64_REDIRECTS +# include +# else + unsigned long int st_dev; + long int st_pad1[3]; + __ino64_t st_ino; /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + unsigned long int st_rdev; /* Device number, if device. */ + long int st_pad2[3]; + __off64_t st_size; /* Size of file, in bytes. */ +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + __blksize_t st_blksize; /* Optimal block size for I/O. */ + long int st_pad3; + __blkcnt64_t st_blocks; /* Number of 512-byte blocks allocated. */ + long int st_pad4[14]; +# endif /* __USE_TIME64_REDIRECTS */ + }; +# endif /* __USE_LARGEFILE64 */ + +#else /* _MIPS_SIM != _ABIO32 */ + +struct stat + { +# ifdef __USE_TIME64_REDIRECTS +# include +# else + __dev_t st_dev; + int st_pad1[3]; /* Reserved for st_dev expansion */ +# ifndef __USE_FILE_OFFSET64 + __ino_t st_ino; +# else + __ino64_t st_ino; +# endif + __mode_t st_mode; + __nlink_t st_nlink; + __uid_t st_uid; + __gid_t st_gid; + __dev_t st_rdev; +# if !defined __USE_FILE_OFFSET64 + unsigned int st_pad2[2]; /* Reserved for st_rdev expansion */ + __off_t st_size; + int st_pad3; +# else + unsigned int st_pad2[3]; /* Reserved for st_rdev expansion */ + __off64_t st_size; +# endif +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + __blksize_t st_blksize; + unsigned int st_pad4; +# ifndef __USE_FILE_OFFSET64 + __blkcnt_t st_blocks; +# else + __blkcnt64_t st_blocks; +# endif + int st_pad5[14]; +# endif + }; + +#ifdef __USE_LARGEFILE64 +struct stat64 + { +# ifdef __USE_TIME64_REDIRECTS +# include +# else + __dev_t st_dev; + unsigned int st_pad1[3]; /* Reserved for st_dev expansion */ + __ino64_t st_ino; + __mode_t st_mode; + __nlink_t st_nlink; + __uid_t st_uid; + __gid_t st_gid; + __dev_t st_rdev; + unsigned int st_pad2[3]; /* Reserved for st_rdev expansion */ + __off64_t st_size; +# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the + identifier 'timespec' to appear in the header. + Therefore we have to handle the use of this header in strictly + standard-compliant sources special. */ + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +# endif + __blksize_t st_blksize; + unsigned int st_pad3; + __blkcnt64_t st_blocks; + int st_pad4[14]; +# endif /* __USE_TIME64_REDIRECTS */ +}; +#endif + +#endif + +/* Tell code we have these members. */ +#define _STATBUF_ST_BLKSIZE +#define _STATBUF_ST_RDEV + +#endif /* _BITS_STRUCT_STAT_H */ \ No newline at end of file diff --git a/lib/libc/include/mips-linux-gnu/bits/timesize.h b/lib/libc/include/mips-linux-gnu/bits/timesize.h new file mode 100644 index 0000000000000000000000000000000000000000..114eea77753240de1509241efac873c28a59e9d0 --- /dev/null +++ b/lib/libc/include/mips-linux-gnu/bits/timesize.h @@ -0,0 +1,22 @@ +/* Bit size of the time_t type at glibc build time, Linux/MIPS. + Copyright (C) 2021-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +/* Size in bits of the 'time_t' type of the default ABI. */ +#define __TIMESIZE __WORDSIZE \ No newline at end of file diff --git a/lib/libc/include/mips-linux-gnu/bits/waitstatus.h b/lib/libc/include/mips-linux-gnu/bits/waitstatus.h new file mode 100644 index 0000000000000000000000000000000000000000..1b7a5a3195a98951a56088ee2e3d7b48874dd835 --- /dev/null +++ b/lib/libc/include/mips-linux-gnu/bits/waitstatus.h @@ -0,0 +1,68 @@ +/* Definitions of status bits for `wait' et al. + MIPS version, based on the generic version (bits/waitstatus.h). + + Copyright (C) 1992-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#if !defined _SYS_WAIT_H && !defined _STDLIB_H +# error "Never include directly; use instead." +#endif + + +/* On MIPS SIGRTMAX is 127, so we need to handle the status code 127 + which is impossible on other ports. */ + +/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */ +#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8) + +/* If WIFSIGNALED(STATUS), the terminating signal. */ +#define __WTERMSIG(status) ((status) & 0x7f) + +/* If WIFSTOPPED(STATUS), the signal that stopped the child. */ +#define __WSTOPSIG(status) __WEXITSTATUS(status) + +/* Nonzero if STATUS indicates normal termination. */ +#define __WIFEXITED(status) (__WTERMSIG(status) == 0) + +/* Nonzero if STATUS indicates termination by a signal. */ +static __inline int +__WIFSIGNALED (int __status) +{ + return ((signed char) ((__status & 0x7f) + 1) >> 1) > 0 || __status == 0x7f; +} + +/* Nonzero if STATUS indicates the child is stopped. */ +static __inline int +__WIFSTOPPED (int __status) +{ + return (__status & 0xff) == 0x7f && __status != 0x7f; +} + +/* Nonzero if STATUS indicates the child continued after a stop. We only + define this if provides the WCONTINUED flag bit. */ +#ifdef WCONTINUED +# define __WIFCONTINUED(status) ((status) == __W_CONTINUED) +#endif + +/* Nonzero if STATUS indicates the child dumped core. */ +#define __WCOREDUMP(status) ((status) & __WCOREFLAG) + +/* Macros for constructing status values. */ +#define __W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) +#define __W_STOPCODE(sig) ((sig) << 8 | 0x7f) +#define __W_CONTINUED 0xffff +#define __WCOREFLAG 0x80 \ No newline at end of file diff --git a/lib/libc/include/powerpc-linux-gnu/bits/long-double.h b/lib/libc/include/powerpc-linux-gnu/bits/long-double.h index 6c9cf2949f916b13700552fd7c1fe852fa507460..e20cbda37abca98ee6597594ff6264ae7ed8f3a7 100644 --- a/lib/libc/include/powerpc-linux-gnu/bits/long-double.h +++ b/lib/libc/include/powerpc-linux-gnu/bits/long-double.h @@ -1,5 +1,5 @@ /* Properties of long double type. ldbl-opt version. - Copyright (C) 2016-2026 Free Software Foundation, Inc. + Copyright (C) 2019-2026 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or diff --git a/lib/libc/include/powerpc-linux-gnu/bits/ppc.h b/lib/libc/include/powerpc-linux-gnu/bits/ppc.h new file mode 100644 index 0000000000000000000000000000000000000000..5e98f066e0a95606f78a7129795ff5f06cbe55ad --- /dev/null +++ b/lib/libc/include/powerpc-linux-gnu/bits/ppc.h @@ -0,0 +1,33 @@ +/* Facilities specific to the PowerPC architecture on Linux + Copyright (C) 2012-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _BITS_PPC_H +#define _BITS_PPC_H + +#ifndef _SYS_PLATFORM_PPC_H +# error "Never include this file directly; use instead." +#endif + +__BEGIN_DECLS + +/* Read the time base frequency. */ +extern uint64_t __ppc_get_timebase_freq (void); + +__END_DECLS + +#endif \ No newline at end of file diff --git a/lib/libc/include/powerpc-linux-gnu/bits/struct_mutex.h b/lib/libc/include/powerpc-linux-gnu/bits/struct_mutex.h index ebf2d50922ee0114298519286785f965771985d9..95fc7f4cc7e18960cc0aa678b866c18b3a03e9be 100644 --- a/lib/libc/include/powerpc-linux-gnu/bits/struct_mutex.h +++ b/lib/libc/include/powerpc-linux-gnu/bits/struct_mutex.h @@ -59,4 +59,4 @@ struct __pthread_mutex_s 0, 0, 0, __kind, 0, { { 0, 0 } } #endif -#endif +#endif \ No newline at end of file diff --git a/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-32.h b/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-32.h deleted file mode 100644 index af615a3d9f90d11fa61205c10ed15dbb63cb8985..0000000000000000000000000000000000000000 --- a/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-32.h +++ /dev/null @@ -1,26 +0,0 @@ -/* This file is automatically generated. */ -#ifndef __GNU_LIB_NAMES_H -# error "Never use directly; include instead." -#endif - -#define LD_SO "ld.so.1" -#define LIBANL_SO "libanl.so.1" -#define LIBBROKENLOCALE_SO "libBrokenLocale.so.1" -#define LIBC_MALLOC_DEBUG_SO "libc_malloc_debug.so.0" -#define LIBC_SO "libc.so.6" -#define LIBDL_SO "libdl.so.2" -#define LIBGCC_S_SO "libgcc_s.so.1" -#define LIBMVEC_SO "libmvec.so.1" -#define LIBM_SO "libm.so.6" -#define LIBNSL_SO "libnsl.so.1" -#define LIBNSS_COMPAT_SO "libnss_compat.so.2" -#define LIBNSS_DB_SO "libnss_db.so.2" -#define LIBNSS_DNS_SO "libnss_dns.so.2" -#define LIBNSS_FILES_SO "libnss_files.so.2" -#define LIBNSS_HESIOD_SO "libnss_hesiod.so.2" -#define LIBNSS_LDAP_SO "libnss_ldap.so.2" -#define LIBPTHREAD_SO "libpthread.so.0" -#define LIBRESOLV_SO "libresolv.so.2" -#define LIBRT_SO "librt.so.1" -#define LIBTHREAD_DB_SO "libthread_db.so.1" -#define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-64-v1.h b/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-64-v1.h deleted file mode 100644 index 4b2c00bbd6ba2e0be21db7253984abfc9e0b8e35..0000000000000000000000000000000000000000 --- a/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-64-v1.h +++ /dev/null @@ -1,27 +0,0 @@ -/* This file is automatically generated. */ -#ifndef __GNU_LIB_NAMES_H -# error "Never use directly; include instead." -#endif - -#define LD64_SO "ld64.so.1" -#define LD_SO "ld64.so.1" -#define LIBANL_SO "libanl.so.1" -#define LIBBROKENLOCALE_SO "libBrokenLocale.so.1" -#define LIBC_MALLOC_DEBUG_SO "libc_malloc_debug.so.0" -#define LIBC_SO "libc.so.6" -#define LIBDL_SO "libdl.so.2" -#define LIBGCC_S_SO "libgcc_s.so.1" -#define LIBMVEC_SO "libmvec.so.1" -#define LIBM_SO "libm.so.6" -#define LIBNSL_SO "libnsl.so.1" -#define LIBNSS_COMPAT_SO "libnss_compat.so.2" -#define LIBNSS_DB_SO "libnss_db.so.2" -#define LIBNSS_DNS_SO "libnss_dns.so.2" -#define LIBNSS_FILES_SO "libnss_files.so.2" -#define LIBNSS_HESIOD_SO "libnss_hesiod.so.2" -#define LIBNSS_LDAP_SO "libnss_ldap.so.2" -#define LIBPTHREAD_SO "libpthread.so.0" -#define LIBRESOLV_SO "libresolv.so.2" -#define LIBRT_SO "librt.so.1" -#define LIBTHREAD_DB_SO "libthread_db.so.1" -#define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-64-v2.h b/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-64-v2.h index 36329b69d756c708f60be53d92609a7175acef8a..0041d62398223239ae58d9bc47f4b552610cedeb 100644 --- a/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-64-v2.h +++ b/lib/libc/include/powerpc-linux-gnu/gnu/lib-names-64-v2.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/powerpc-linux-gnu/gnu/stubs-64-v1.h b/lib/libc/include/powerpc-linux-gnu/gnu/stubs-64-v1.h deleted file mode 100644 index 636dc73283f9e3508fca4713d7d911f47d284387..0000000000000000000000000000000000000000 --- a/lib/libc/include/powerpc-linux-gnu/gnu/stubs-64-v1.h +++ /dev/null @@ -1,16 +0,0 @@ -/* This file is automatically generated. - It defines a symbol `__stub_FUNCTION' for each function - in the C library which is a stub, meaning it will fail - every time called, usually setting errno to ENOSYS. */ - -#ifdef _LIBC - #error Applications may not define the macro _LIBC -#endif - -#define __stub_chflags -#define __stub_fchflags -#define __stub_gtty -#define __stub_revoke -#define __stub_setlogin -#define __stub_sigreturn -#define __stub_stty \ No newline at end of file diff --git a/lib/libc/include/powerpc-linux-gnu/sys/platform/ppc.h b/lib/libc/include/powerpc-linux-gnu/sys/platform/ppc.h new file mode 100644 index 0000000000000000000000000000000000000000..6e7df94235d78f7b3ad6c8644301f8d0441a264e --- /dev/null +++ b/lib/libc/include/powerpc-linux-gnu/sys/platform/ppc.h @@ -0,0 +1,146 @@ +/* Facilities specific to the PowerPC architecture + Copyright (C) 2012-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _SYS_PLATFORM_PPC_H +#define _SYS_PLATFORM_PPC_H 1 + +#include +#include +#include + +/* Read the Time Base Register. */ +static __inline__ uint64_t +__ppc_get_timebase (void) +{ +#if __GNUC_PREREQ (4, 8) + return __builtin_ppc_get_timebase (); +#else +# ifdef __powerpc64__ + uint64_t __tb; + /* "volatile" is necessary here, because the user expects this assembly + isn't moved after an optimization. */ + __asm__ volatile ("mfspr %0, 268" : "=r" (__tb)); + return __tb; +# else /* not __powerpc64__ */ + uint32_t __tbu, __tbl, __tmp; \ + __asm__ volatile ("0:\n\t" + "mftbu %0\n\t" + "mftbl %1\n\t" + "mftbu %2\n\t" + "cmpw %0, %2\n\t" + "bne- 0b" + : "=r" (__tbu), "=r" (__tbl), "=r" (__tmp)); + return (((uint64_t) __tbu << 32) | __tbl); +# endif /* not __powerpc64__ */ +#endif +} + +/* The following functions provide hints about the usage of shared processor + resources, as defined in ISA 2.06 and newer. */ + +/* Provides a hint that performance will probably be improved if shared + resources dedicated to the executing processor are released for use by other + processors. */ +static __inline__ void +__ppc_yield (void) +{ + __asm__ volatile ("or 27,27,27"); +} + +/* Provides a hint that performance will probably be improved if shared + resources dedicated to the executing processor are released until + all outstanding storage accesses to caching-inhibited storage have been + completed. */ +static __inline__ void +__ppc_mdoio (void) +{ + __asm__ volatile ("or 29,29,29"); +} + +/* Provides a hint that performance will probably be improved if shared + resources dedicated to the executing processor are released until all + outstanding storage accesses to cacheable storage for which the data is not + in the cache have been completed. */ +static __inline__ void +__ppc_mdoom (void) +{ + __asm__ volatile ("or 30,30,30"); +} + + +/* ISA 2.05 and beyond support the Program Priority Register (PPR) to adjust + thread priorities based on lock acquisition, wait and release. The ISA + defines the use of form 'or Rx,Rx,Rx' as the way to modify the PRI field. + The unprivileged priorities are: + Rx = 1 (low) + Rx = 2 (medium) + Rx = 6 (medium-low/normal) + The 'or' instruction form is a nop in previous hardware, so it is safe to + use unguarded. The default value is 'medium'. + */ + +static __inline__ void +__ppc_set_ppr_med (void) +{ + __asm__ volatile ("or 2,2,2"); +} + +static __inline__ void +__ppc_set_ppr_med_low (void) +{ + __asm__ volatile ("or 6,6,6"); +} + +static __inline__ void +__ppc_set_ppr_low (void) +{ + __asm__ volatile ("or 1,1,1"); +} + +/* Power ISA 2.07 (Book II, Chapter 3) extends the priorities that can be set + to the Program Priority Register (PPR). The form 'or Rx,Rx,Rx' is used to + modify the PRI field of the PPR, the same way as described above. + The new priority levels are: + Rx = 31 (very low) + Rx = 5 (medium high) + Any program can set the priority to very low, low, medium low, and medium, + as these are unprivileged. + The medium high priority, on the other hand, is privileged, and may only be + set during certain time intervals by problem-state programs. If the program + priority is medium high when the time interval expires or if an attempt is + made to set the priority to medium high when it is not allowed, the PRI + field is set to medium. + */ + +#ifdef _ARCH_PWR8 + +static __inline__ void +__ppc_set_ppr_very_low (void) +{ + __asm__ volatile ("or 31,31,31"); +} + +static __inline__ void +__ppc_set_ppr_med_high (void) +{ + __asm__ volatile ("or 5,5,5"); +} + +#endif + +#endif /* sys/platform/ppc.h */ \ No newline at end of file diff --git a/lib/libc/include/powerpc-netbsd-eabi/powerpc/oea/pmap.h b/lib/libc/include/powerpc-netbsd-eabi/powerpc/oea/pmap.h index 8510dfa5f6337ddab007b85ea157e17a4aa396c6..b0584b636d5db885176da01d834d116b31dc8574 100644 --- a/lib/libc/include/powerpc-netbsd-eabi/powerpc/oea/pmap.h +++ b/lib/libc/include/powerpc-netbsd-eabi/powerpc/oea/pmap.h @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.h,v 1.39 2023/12/15 09:42:33 rin Exp $ */ +/* $NetBSD: pmap.h,v 1.39.4.1 2026/07/03 17:51:59 martin Exp $ */ /*- * Copyright (C) 1995, 1996 Wolfgang Solfrank. @@ -122,11 +122,13 @@ __BEGIN_DECLS #include /* - * For OEA and OEA64_BRIDGE, we guarantee that pa below USER_ADDR - * (== 3GB < VM_MIN_KERNEL_ADDRESS) is direct-mapped. + * Physical memory below PMAP_DIRECT_MAPPED_LEN is direct-mapped + * (pa == va). Direct region covers the segments below BOTH + * the user copyin window (USER_SR) and the kernel HTAB window + * (KERNEL_SR), so it can never overlap. */ #if defined(PPC_OEA) || defined(PPC_OEA64_BRIDGE) -#define PMAP_DIRECT_MAPPED_SR (USER_SR - 1) +#define PMAP_DIRECT_MAPPED_SR (MIN(USER_SR, KERNEL_SR) - 1) #define PMAP_DIRECT_MAPPED_LEN \ ((vaddr_t)SEGMENT_LENGTH * (PMAP_DIRECT_MAPPED_SR + 1)) #endif diff --git a/lib/libc/include/riscv-linux-gnu/bits/long-double.h b/lib/libc/include/riscv-linux-gnu/bits/long-double.h deleted file mode 100644 index af7784dbe6dd85cd9538b5a7b437ab45de22eeb8..0000000000000000000000000000000000000000 --- a/lib/libc/include/riscv-linux-gnu/bits/long-double.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Properties of long double type. ldbl-128 version. - Copyright (C) 2016-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* long double is distinct from double, so there is nothing to - define here. */ -#define __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI 0 \ No newline at end of file diff --git a/lib/libc/include/riscv-linux-gnu/bits/struct_stat.h b/lib/libc/include/riscv-linux-gnu/bits/struct_stat.h deleted file mode 100644 index 0462d37a6849812f485a6830a7c0dca303332636..0000000000000000000000000000000000000000 --- a/lib/libc/include/riscv-linux-gnu/bits/struct_stat.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Definition for struct stat. - Copyright (C) 2020-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library. If not, see - . */ - -#if !defined _SYS_STAT_H && !defined _FCNTL_H -# error "Never include directly; use instead." -#endif - -#ifndef _BITS_STRUCT_STAT_H -#define _BITS_STRUCT_STAT_H 1 - -#include -#include - -#if defined __USE_FILE_OFFSET64 -# define __field64(type, type64, name) type64 name -#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T -# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T -# error "ino_t and off_t must both be the same type" -# endif -# define __field64(type, type64, name) type name -#elif __BYTE_ORDER == __LITTLE_ENDIAN -# define __field64(type, type64, name) \ - type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad -#else -# define __field64(type, type64, name) \ - int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name -#endif - -struct stat - { - __dev_t st_dev; /* Device. */ - __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; - -#undef __field64 - -#ifdef __USE_LARGEFILE64 -struct stat64 - { - __dev_t st_dev; /* Device. */ - __ino64_t st_ino; /* File serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - __dev_t __pad1; - __off64_t st_size; /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ -#ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -#else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -#endif - int __glibc_reserved[2]; - }; -#endif - -/* Tell code we have these members. */ -#define _STATBUF_ST_BLKSIZE -#define _STATBUF_ST_RDEV -/* Nanosecond resolution time values are supported. */ -#define _STATBUF_ST_NSEC - -#endif /* _BITS_STRUCT_STAT_H */ \ No newline at end of file diff --git a/lib/libc/include/riscv-linux-gnu/bits/timesize.h b/lib/libc/include/riscv-linux-gnu/bits/timesize.h deleted file mode 100644 index dff2da5ed6bf30ce6f5580aee352e0958d58b623..0000000000000000000000000000000000000000 --- a/lib/libc/include/riscv-linux-gnu/bits/timesize.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Bit size of the time_t type at glibc build time, general case. - Copyright (C) 2018-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* Size in bits of the 'time_t' type of the default ABI. */ -#define __TIMESIZE 64 \ No newline at end of file diff --git a/lib/libc/include/riscv-linux-gnu/gnu/lib-names-ilp32d.h b/lib/libc/include/riscv-linux-gnu/gnu/lib-names-ilp32d.h index 33fd7061de58a4aeca1c876789202fc51a5be641..37e0c85dd4ea29bcca29f0b710981b74e5e8e3bc 100644 --- a/lib/libc/include/riscv-linux-gnu/gnu/lib-names-ilp32d.h +++ b/lib/libc/include/riscv-linux-gnu/gnu/lib-names-ilp32d.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/riscv-linux-gnu/gnu/lib-names-lp64d.h b/lib/libc/include/riscv-linux-gnu/gnu/lib-names-lp64d.h index 0b66bda6d611e45af8ebfbaa34b5569ae01e0c87..8117af98ffff4eec5296b1d16e390402785df0d8 100644 --- a/lib/libc/include/riscv-linux-gnu/gnu/lib-names-lp64d.h +++ b/lib/libc/include/riscv-linux-gnu/gnu/lib-names-lp64d.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/elfclass.h b/lib/libc/include/s390x-linux-gnu/bits/elfclass.h index 325ca0fe4b41d0af0242fb38611aca0b39d4b525..1082cffe057afa53e293fe6aec0c117aab32723d 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/elfclass.h +++ b/lib/libc/include/s390x-linux-gnu/bits/elfclass.h @@ -27,11 +27,6 @@ #define __ELF_NATIVE_CLASS __WORDSIZE -#if __WORDSIZE == 64 /* 64 bit Linux for S/390 is exceptional as it has .hash section with 64 bit entries. */ -typedef uint64_t Elf_Symndx; -#else -/* 32 bit Linux for S/390 has normal .hash section entries with 32 bits. */ -typedef uint32_t Elf_Symndx; -#endif \ No newline at end of file +typedef uint64_t Elf_Symndx; \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/environments.h b/lib/libc/include/s390x-linux-gnu/bits/environments.h deleted file mode 100644 index 6a5d3e997c9e6592b4c5077da6e5f1d9e40d9b40..0000000000000000000000000000000000000000 --- a/lib/libc/include/s390x-linux-gnu/bits/environments.h +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (C) 1999-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _UNISTD_H -# error "Never include this file directly. Use instead" -#endif - -#include - -/* This header should define the following symbols under the described - situations. A value `1' means that the model is always supported, - `-1' means it is never supported. Undefined means it cannot be - statically decided. - - _POSIX_V7_ILP32_OFF32 32bit int, long, pointers, and off_t type - _POSIX_V7_ILP32_OFFBIG 32bit int, long, and pointers and larger off_t type - - _POSIX_V7_LP64_OFF32 64bit long and pointers and 32bit off_t type - _POSIX_V7_LPBIG_OFFBIG 64bit long and pointers and large off_t type - - The macros _POSIX_V6_ILP32_OFF32, _POSIX_V6_ILP32_OFFBIG, - _POSIX_V6_LP64_OFF32, _POSIX_V6_LPBIG_OFFBIG, _XBS5_ILP32_OFF32, - _XBS5_ILP32_OFFBIG, _XBS5_LP64_OFF32, and _XBS5_LPBIG_OFFBIG were - used in previous versions of the Unix standard and are available - only for compatibility. -*/ - -#if __WORDSIZE == 64 - -/* Environments with 32-bit wide pointers are optionally provided. - Therefore following macros aren't defined: - # undef _POSIX_V7_ILP32_OFF32 - # undef _POSIX_V7_ILP32_OFFBIG - # undef _POSIX_V6_ILP32_OFF32 - # undef _POSIX_V6_ILP32_OFFBIG - # undef _XBS5_ILP32_OFF32 - # undef _XBS5_ILP32_OFFBIG - and users need to check at runtime. */ - -/* We also have no use (for now) for an environment with bigger pointers - and offsets. */ -# define _POSIX_V7_LPBIG_OFFBIG -1 -# define _POSIX_V6_LPBIG_OFFBIG -1 -# define _XBS5_LPBIG_OFFBIG -1 - -/* By default we have 64-bit wide `long int', pointers and `off_t'. */ -# define _POSIX_V7_LP64_OFF64 1 -# define _POSIX_V6_LP64_OFF64 1 -# define _XBS5_LP64_OFF64 1 - -#else /* __WORDSIZE == 32 */ - -/* By default we have 32-bit wide `int', `long int', pointers and `off_t' - and all platforms support LFS. */ -# define _POSIX_V7_ILP32_OFF32 1 -# define _POSIX_V7_ILP32_OFFBIG 1 -# define _POSIX_V6_ILP32_OFF32 1 -# define _POSIX_V6_ILP32_OFFBIG 1 -# define _XBS5_ILP32_OFF32 1 -# define _XBS5_ILP32_OFFBIG 1 - -/* We optionally provide an environment with the above size but an 64-bit - side `off_t'. Therefore we don't define _POSIX_V7_ILP32_OFFBIG. */ - -/* Environments with 64-bit wide pointers can be provided, - so these macros aren't defined: - # undef _POSIX_V7_LP64_OFF64 - # undef _POSIX_V7_LPBIG_OFFBIG - # undef _POSIX_V6_LP64_OFF64 - # undef _POSIX_V6_LPBIG_OFFBIG - # undef _XBS5_LP64_OFF64 - # undef _XBS5_LPBIG_OFFBIG - and sysconf tests for it at runtime. */ - -#endif /* __WORDSIZE == 32 */ - -#define __ILP32_OFF32_CFLAGS "-m31" -#define __ILP32_OFFBIG_CFLAGS "-m31 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" -#define __ILP32_OFF32_LDFLAGS "-m31" -#define __ILP32_OFFBIG_LDFLAGS "-m31" -#define __LP64_OFF64_CFLAGS "-m64" -#define __LP64_OFF64_LDFLAGS "-m64" \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/fcntl.h b/lib/libc/include/s390x-linux-gnu/bits/fcntl.h index 1d209c616c834cb7d1e8c4220a68852418694265..65df93eaf1e48e53690ec83f9cf4c1f17b3c6026 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/fcntl.h +++ b/lib/libc/include/s390x-linux-gnu/bits/fcntl.h @@ -22,29 +22,20 @@ #include -#if __WORDSIZE == 64 /* Not necessary, files are always with 64bit off_t. */ -# define __O_LARGEFILE 0 -#endif +#define __O_LARGEFILE 0 -#if __WORDSIZE == 64 /* Not necessary, we always have 64-bit offsets. */ -# define F_GETLK64 5 /* Get record locking info. */ -# define F_SETLK64 6 /* Set record locking info (non-blocking). */ -# define F_SETLKW64 7 /* Set record locking info (blocking). */ -#endif +#define F_GETLK64 5 /* Get record locking info. */ +#define F_SETLK64 6 /* Set record locking info (non-blocking). */ +#define F_SETLKW64 7 /* Set record locking info (blocking). */ struct flock { short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ short int l_whence; /* Where `l_start' is relative to (like `lseek'). */ -#if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64 __off_t l_start; /* Offset where the lock begins. */ __off_t l_len; /* Size of the locked area; zero means until EOF. */ -#else - __off64_t l_start; /* Offset where the lock begins. */ - __off64_t l_len; /* Size of the locked area; zero means until EOF. */ -#endif __pid_t l_pid; /* Process holding the lock. */ }; @@ -59,13 +50,8 @@ struct flock64 }; #endif -#if __WORDSIZE == 64 -# define __POSIX_FADV_DONTNEED 6 /* Don't need these pages. */ -# define __POSIX_FADV_NOREUSE 7 /* Data will be accessed once. */ -#else -# define __POSIX_FADV_DONTNEED 4 /* Don't need these pages. */ -# define __POSIX_FADV_NOREUSE 5 /* Data will be accessed once. */ -#endif +#define __POSIX_FADV_DONTNEED 6 /* Don't need these pages. */ +#define __POSIX_FADV_NOREUSE 7 /* Data will be accessed once. */ /* Include generic Linux declarations. */ #include \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/fenv.h b/lib/libc/include/s390x-linux-gnu/bits/fenv.h index 6fb9372043231b6e4303457c2b102b56fc39e728..e53e9e1d9ab8b9b5ff63b5f3c6f959ad2253b6ed 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/fenv.h +++ b/lib/libc/include/s390x-linux-gnu/bits/fenv.h @@ -77,9 +77,9 @@ typedef struct { fexcept_t __fpc; void *__glibc_reserved; - /* The field __unused (formerly __ieee_instruction_pointer) is a relict from - commit "Remove PTRACE_PEEKUSER" (87b9b50f0d4b92248905e95a06a13c513dc45e59) - and isn't used anymore. */ + /* The field __glibc_reserved (formerly __ieee_instruction_pointer) is a + relict from commit "Remove PTRACE_PEEKUSER" + (87b9b50f0d4b92248905e95a06a13c513dc45e59) and isn't used anymore. */ } fenv_t; /* If the default argument is used we use this value. */ @@ -96,4 +96,4 @@ typedef unsigned int femode_t; /* Default floating-point control modes. */ # define FE_DFL_MODE ((const femode_t *) -1L) -#endif +#endif \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/link.h b/lib/libc/include/s390x-linux-gnu/bits/link.h index 96694b37a417838cb4452446e0217fd7e3d4ebed..9eeb39b381bc9292c9b5c3842c296aa9db0b74b7 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/link.h +++ b/lib/libc/include/s390x-linux-gnu/bits/link.h @@ -23,64 +23,6 @@ typedef char La_s390_vr[16]; #endif -#if __ELF_NATIVE_CLASS == 32 - -/* Registers for entry into PLT on s390-32. */ -typedef struct La_s390_32_regs -{ - uint32_t lr_r2; - uint32_t lr_r3; - uint32_t lr_r4; - uint32_t lr_r5; - uint32_t lr_r6; - double lr_fp0; - double lr_fp2; -# if defined HAVE_S390_VX_ASM_SUPPORT - La_s390_vr lr_v24; - La_s390_vr lr_v25; - La_s390_vr lr_v26; - La_s390_vr lr_v27; - La_s390_vr lr_v28; - La_s390_vr lr_v29; - La_s390_vr lr_v30; - La_s390_vr lr_v31; -# endif -} La_s390_32_regs; - -/* Return values for calls from PLT on s390-32. */ -typedef struct La_s390_32_retval -{ - uint32_t lrv_r2; - uint32_t lrv_r3; - double lrv_fp0; -# if defined HAVE_S390_VX_ASM_SUPPORT - La_s390_vr lrv_v24; -# endif -} La_s390_32_retval; - - -__BEGIN_DECLS - -extern Elf32_Addr la_s390_32_gnu_pltenter (Elf32_Sym *__sym, - unsigned int __ndx, - uintptr_t *__refcook, - uintptr_t *__defcook, - La_s390_32_regs *__regs, - unsigned int *__flags, - const char *__symname, - long int *__framesizep); -extern unsigned int la_s390_32_gnu_pltexit (Elf32_Sym *__sym, - unsigned int __ndx, - uintptr_t *__refcook, - uintptr_t *__defcook, - const La_s390_32_regs *__inregs, - La_s390_32_retval *__outregs, - const char *symname); - -__END_DECLS - -#else - /* Registers for entry into PLT on s390-64. */ typedef struct La_s390_64_regs { @@ -134,6 +76,4 @@ extern unsigned int la_s390_64_gnu_pltexit (Elf64_Sym *__sym, La_s390_64_retval *__outregs, const char *__symname); -__END_DECLS - -#endif \ No newline at end of file +__END_DECLS \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/procfs-extra.h b/lib/libc/include/s390x-linux-gnu/bits/procfs-extra.h deleted file mode 100644 index 7fb00d4146dae8fca24958e976e831c961090952..0000000000000000000000000000000000000000 --- a/lib/libc/include/s390x-linux-gnu/bits/procfs-extra.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Extra sys/procfs.h definitions. S/390 version. - Copyright (C) 2000-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _SYS_PROCFS_H -# error "Never include directly; use instead." -#endif - -#if __WORDSIZE == 64 - -/* Provide 32-bit variants so that BFD can read 32-bit - core files. */ -#define ELF_NGREG32 36 -typedef unsigned int elf_greg_t32; -typedef elf_greg_t32 - elf_gregset_t32[ELF_NGREG32] __attribute__ ((__aligned__ (8))); -typedef elf_fpregset_t elf_fpregset_t32; - -struct elf_prstatus32 - { - struct elf_siginfo pr_info; /* Info associated with signal. */ - short int pr_cursig; /* Current signal. */ - unsigned int pr_sigpend; /* Set of pending signals. */ - unsigned int pr_sighold; /* Set of held signals. */ - __pid_t pr_pid; - __pid_t pr_ppid; - __pid_t pr_pgrp; - __pid_t pr_sid; - struct - { - int tv_sec, tv_usec; - } pr_utime, /* User time. */ - pr_stime, /* System time. */ - pr_cutime, /* Cumulative user time. */ - pr_cstime; /* Cumulative system time. */ - elf_gregset_t32 pr_reg; /* GP registers. */ - int pr_fpvalid; /* True if math copro being used. */ - }; - -struct elf_prpsinfo32 - { - char pr_state; /* Numeric process state. */ - char pr_sname; /* Char for pr_state. */ - char pr_zomb; /* Zombie. */ - char pr_nice; /* Nice val. */ - unsigned int pr_flag; /* Flags. */ - unsigned short int pr_uid; - unsigned short int pr_gid; - int pr_pid, pr_ppid, pr_pgrp, pr_sid; - /* Lots missing */ - char pr_fname[16]; /* Filename of executable. */ - char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */ - }; - -typedef elf_gregset_t32 prgregset32_t; -typedef elf_fpregset_t32 prfpregset32_t; - -typedef struct elf_prstatus32 prstatus32_t; -typedef struct elf_prpsinfo32 prpsinfo32_t; - -#endif \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/procfs-id.h b/lib/libc/include/s390x-linux-gnu/bits/procfs-id.h deleted file mode 100644 index 9e8570cfe612efd5d35867d0a70a20593fde16f9..0000000000000000000000000000000000000000 --- a/lib/libc/include/s390x-linux-gnu/bits/procfs-id.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Types of pr_uid and pr_gid in struct elf_prpsinfo. S/390 version. - Copyright (C) 2018-2026 Free Software Foundation, Inc. - - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _SYS_PROCFS_H -# error "Never include directly; use instead." -#endif - -#if __WORDSIZE == 64 -typedef unsigned int __pr_uid_t; -typedef unsigned int __pr_gid_t; -#else -typedef unsigned short int __pr_uid_t; -typedef unsigned short int __pr_gid_t; -#endif \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/setjmp.h b/lib/libc/include/s390x-linux-gnu/bits/setjmp.h index 7d660921ab0295c49a77d9fb12cf4b021546d8c3..451857ec455a20350777d9bd21ed38353e7c4763 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/setjmp.h +++ b/lib/libc/include/s390x-linux-gnu/bits/setjmp.h @@ -33,13 +33,7 @@ typedef struct __s390_jmp_buf /* We save registers 6-15. */ long int __gregs[10]; -# if __WORDSIZE == 64 - /* We save fpu registers f8 - f15. */ long __fpregs[8]; -# else - /* We save fpu registers 4 and 6. */ - long __fpregs[4]; -# endif } __jmp_buf[1]; #endif diff --git a/lib/libc/include/s390x-linux-gnu/bits/sigaction.h b/lib/libc/include/s390x-linux-gnu/bits/sigaction.h index 44883efbe768731d6953e626f57588887505c712..7012eab006a3e4b42515fb7fc8c7d0c026c1dc98 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/sigaction.h +++ b/lib/libc/include/s390x-linux-gnu/bits/sigaction.h @@ -1,4 +1,4 @@ -/* Definitions for 31 & 64 bit S/390 sigaction. +/* Definitions for 64 bit S/390 sigaction. Copyright (C) 2001-2026 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -23,9 +23,6 @@ # error "Never include directly; use instead." #endif -#include - -#if __WORDSIZE == 64 /* Structure describing the action to be taken when a signal arrives. */ struct sigaction { @@ -55,36 +52,6 @@ struct sigaction /* Additional set of signals to be blocked. */ __sigset_t sa_mask; }; -#else -/* Structure describing the action to be taken when a signal arrives. */ -struct sigaction - { - /* Signal handler. */ -#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED - union - { - /* Used if SA_SIGINFO is not set. */ - __sighandler_t sa_handler; - /* Used if SA_SIGINFO is set. */ - void (*sa_sigaction) (int, siginfo_t *, void *); - } - __sigaction_handler; -# define sa_handler __sigaction_handler.sa_handler -# define sa_sigaction __sigaction_handler.sa_sigaction -#else - __sighandler_t sa_handler; -#endif - - /* Additional set of signals to be blocked. */ - __sigset_t sa_mask; - - /* Special flags. */ - int sa_flags; - - /* Restore handler. */ - void (*sa_restorer) (void); - }; -#endif /* Bits in `sa_flags'. */ #define SA_NOCLDSTOP 1 /* Don't send SIGCHLD when children stop. */ diff --git a/lib/libc/include/s390x-linux-gnu/bits/struct_mutex.h b/lib/libc/include/s390x-linux-gnu/bits/struct_mutex.h index 571265267c2edbc388e00aed800c03b3d2c05b2d..d7b3a380e8f2f32e96a7d8f9b3fe71c52d2bf7a4 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/struct_mutex.h +++ b/lib/libc/include/s390x-linux-gnu/bits/struct_mutex.h @@ -24,39 +24,17 @@ struct __pthread_mutex_s int __lock; unsigned int __count; int __owner; -#if __WORDSIZE == 64 unsigned int __nusers; -#endif /* KIND must stay at this position in the structure to maintain binary compatibility with static initializers. */ int __kind; -#if __WORDSIZE == 64 short __spins; short __glibc_reserved; __pthread_list_t __list; # define __PTHREAD_MUTEX_HAVE_PREV 1 -#else - unsigned int __nusers; - __extension__ union - { - struct - { - short __data_spins; - short __data_unused; - } __data; -# define __spins __data.__data_spins - __pthread_slist_t __list; - }; -# define __PTHREAD_MUTEX_HAVE_PREV 0 -#endif }; -#if __WORDSIZE == 64 -# define __PTHREAD_MUTEX_INITIALIZER(__kind) \ +#define __PTHREAD_MUTEX_INITIALIZER(__kind) \ 0, 0, 0, 0, __kind, 0, 0, { 0, 0 } -#else -# define __PTHREAD_MUTEX_INITIALIZER(__kind) \ - 0, 0, 0, __kind, 0, { { 0, 0 } } -#endif -#endif +#endif \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/struct_rwlock.h b/lib/libc/include/s390x-linux-gnu/bits/struct_rwlock.h index e532dcddf63eef3facc4ec0021639de7ca1b49bc..7d453256eee76416816427df60aca51e65a76466 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/struct_rwlock.h +++ b/lib/libc/include/s390x-linux-gnu/bits/struct_rwlock.h @@ -28,7 +28,6 @@ struct __pthread_rwlock_arch_t unsigned int __writers_futex; unsigned int __pad3; unsigned int __pad4; -#if __WORDSIZE == 64 int __cur_writer; int __shared; unsigned long int __pad1; @@ -36,23 +35,9 @@ struct __pthread_rwlock_arch_t /* FLAGS must stay at this position in the structure to maintain binary compatibility. */ unsigned int __flags; -# else - unsigned char __pad1; - unsigned char __pad2; - unsigned char __shared; - /* FLAGS must stay at this position in the structure to maintain - binary compatibility. */ - unsigned char __flags; - int __cur_writer; -#endif }; -#if __WORDSIZE == 64 -# define __PTHREAD_RWLOCK_INITIALIZER(__flags) \ +#define __PTHREAD_RWLOCK_INITIALIZER(__flags) \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, __flags -#else -# define __PTHREAD_RWLOCK_INITIALIZER(__flags) \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, __flags, 0 -#endif #endif \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/struct_stat.h b/lib/libc/include/s390x-linux-gnu/bits/struct_stat.h index 3d77809e22d16b08b9329cb01c33a48e61177218..47141080639b92a6607dabed7ef00d3f53143736 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/struct_stat.h +++ b/lib/libc/include/s390x-linux-gnu/bits/struct_stat.h @@ -25,7 +25,6 @@ #include -#if __WORDSIZE == 64 struct stat { __dev_t st_dev; /* Device. */ @@ -62,70 +61,8 @@ struct stat __blkcnt_t st_blocks; /* Nr. 512-byte blocks allocated. */ long int __glibc_reserved[3]; }; -#else -struct stat - { -# ifdef __USE_TIME64_REDIRECTS -# include -# else - __dev_t st_dev; /* Device. */ - unsigned int __pad1; -# ifndef __USE_FILE_OFFSET64 - __ino_t st_ino; /* File serial number. */ -# else - __ino_t __st_ino; /* 32bit file serial number. */ -# endif - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - unsigned int __pad2; -# ifndef __USE_FILE_OFFSET64 - __off_t st_size; /* Size of file, in bytes. */ -# else - __off64_t st_size; /* Size of file, in bytes. */ -# endif - __blksize_t st_blksize; /* Optimal block size for I/O. */ - -# ifndef __USE_FILE_OFFSET64 - __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ -# else - __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -# endif -# ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -# else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif -# ifndef __USE_FILE_OFFSET64 - unsigned long int __glibc_reserved4; - unsigned long int __glibc_reserved5; -# else - __ino64_t st_ino; /* File serial number. */ -# endif -# endif - }; -# endif #ifdef __USE_LARGEFILE64 -# if __WORDSIZE == 64 /* Note stat64 is the same shape as stat. */ struct stat64 { @@ -138,7 +75,7 @@ struct stat64 int __glibc_reserved0; __dev_t st_rdev; /* Device number, if device. */ __off_t st_size; /* Size of file, in bytes. */ -# ifdef __USE_XOPEN2K8 +# ifdef __USE_XOPEN2K8 /* Nanosecond resolution timestamps are stored in a format equivalent to 'struct timespec'. This is the type used whenever possible but the Unix namespace rules do not allow the @@ -148,66 +85,21 @@ struct stat64 struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -# else +# define st_atime st_atim.tv_sec /* Backward compatibility. */ +# define st_mtime st_mtim.tv_sec +# define st_ctime st_ctim.tv_sec +# else __time_t st_atime; /* Time of last access. */ unsigned long int st_atimensec; /* Nscecs of last access. */ __time_t st_mtime; /* Time of last modification. */ unsigned long int st_mtimensec; /* Nsecs of last modification. */ __time_t st_ctime; /* Time of last status change. */ unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif +# endif __blksize_t st_blksize; /* Optimal block size for I/O. */ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ long int __glibc_reserved[3]; }; -# else -struct stat64 - { -# ifdef __USE_TIME64_REDIRECTS -# include -# else - __dev_t st_dev; /* Device. */ - unsigned int __pad1; - - __ino_t __st_ino; /* 32bit file serial number. */ - __mode_t st_mode; /* File mode. */ - __nlink_t st_nlink; /* Link count. */ - __uid_t st_uid; /* User ID of the file's owner. */ - __gid_t st_gid; /* Group ID of the file's group.*/ - __dev_t st_rdev; /* Device number, if device. */ - unsigned int __pad2; - __off64_t st_size; /* Size of file, in bytes. */ - __blksize_t st_blksize; /* Optimal block size for I/O. */ - - __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -# ifdef __USE_XOPEN2K8 - /* Nanosecond resolution timestamps are stored in a format - equivalent to 'struct timespec'. This is the type used - whenever possible but the Unix namespace rules do not allow the - identifier 'timespec' to appear in the header. - Therefore we have to handle the use of this header in strictly - standard-compliant sources special. */ - struct timespec st_atim; /* Time of last access. */ - struct timespec st_mtim; /* Time of last modification. */ - struct timespec st_ctim; /* Time of last status change. */ -# define st_atime st_atim.tv_sec /* Backward compatibility. */ -# define st_mtime st_mtim.tv_sec -# define st_ctime st_ctim.tv_sec -# else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ -# endif - __ino64_t st_ino; /* File serial number. */ -# endif - }; -# endif #endif /* Tell code we have these members. */ diff --git a/lib/libc/include/s390x-linux-gnu/bits/timesize.h b/lib/libc/include/s390x-linux-gnu/bits/timesize.h deleted file mode 100644 index 5c231fe380193665c3e791dc1c16ef284787d758..0000000000000000000000000000000000000000 --- a/lib/libc/include/s390x-linux-gnu/bits/timesize.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Bit size of the time_t type at glibc build time, Linux/s390. - Copyright (C) 2021-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include - -/* Size in bits of the 'time_t' type of the default ABI. */ -#define __TIMESIZE __WORDSIZE \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/typesizes.h b/lib/libc/include/s390x-linux-gnu/bits/typesizes.h index 5302d79b87a3bcdf2e8f9052fc3404030f9a3b35..101d3a7a9867d31f59c32464807cd473ced919fd 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/typesizes.h +++ b/lib/libc/include/s390x-linux-gnu/bits/typesizes.h @@ -57,42 +57,34 @@ #define __TIMER_T_TYPE void * #define __BLKSIZE_T_TYPE __SLONGWORD_TYPE #define __FSID_T_TYPE struct { int __val[2]; } -#if defined __GNUC__ && __GNUC__ <= 2 -/* Compatibility with g++ 2.95.x. */ -#define __SSIZE_T_TYPE __SWORD_TYPE -#else -/* size_t is unsigned long int on s390 -m31. */ -#define __SSIZE_T_TYPE __SLONGWORD_TYPE -#endif + +/* With s390-32, __SSIZE_T_TYPE was __SWORD_TYPE for compatibility with + g++ 2.95.x. Afterwards __SLONGWORD_TYPE was needed as size_t was + unsigned long int on s390-32. + Now as only s390-64 exists, __SWORD_TYPE can be used as also used in the + generic version as both types result in long int. */ +#define __SSIZE_T_TYPE __SWORD_TYPE + #define __SYSCALL_SLONG_TYPE __SLONGWORD_TYPE #define __SYSCALL_ULONG_TYPE __ULONGWORD_TYPE -#define __CPU_MASK_TYPE __ULONGWORD_TYPE +#define __CPU_MASK_TYPE __ULONGWORD_TYPE -#ifdef __s390x__ /* Tell the libc code that off_t and off64_t are actually the same type for all ABI purposes, even if possibly expressed as different base types for C type-checking purposes. */ -# define __OFF_T_MATCHES_OFF64_T 1 +#define __OFF_T_MATCHES_OFF64_T 1 /* Same for ino_t and ino64_t. */ -# define __INO_T_MATCHES_INO64_T 1 +#define __INO_T_MATCHES_INO64_T 1 /* And for __rlim_t and __rlim64_t. */ -# define __RLIM_T_MATCHES_RLIM64_T 1 +#define __RLIM_T_MATCHES_RLIM64_T 1 /* And for fsblkcnt_t, fsblkcnt64_t, fsfilcnt_t and fsfilcnt64_t. */ -# define __STATFS_MATCHES_STATFS64 1 +#define __STATFS_MATCHES_STATFS64 1 /* And for getitimer, setitimer and rusage */ -# define __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64 1 -#else -# define __RLIM_T_MATCHES_RLIM64_T 0 - -# define __STATFS_MATCHES_STATFS64 0 - -/* And for getitimer, setitimer and rusage */ -# define __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64 0 -#endif +#define __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64 1 /* Number of descriptors that can fit in an `fd_set'. */ #define __FD_SETSIZE 1024 diff --git a/lib/libc/include/s390x-linux-gnu/bits/utmp.h b/lib/libc/include/s390x-linux-gnu/bits/utmp.h deleted file mode 100644 index 87db119de9415b8be0386c7bca655c4046fb2e36..0000000000000000000000000000000000000000 --- a/lib/libc/include/s390x-linux-gnu/bits/utmp.h +++ /dev/null @@ -1,127 +0,0 @@ -/* The `struct utmp' type, describing entries in the utmp file. GNU version. - Copyright (C) 1993-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _UTMP_H -# error "Never include directly; use instead." -#endif - -#include -#include -#include -#include - - -#define UT_LINESIZE 32 -#define UT_NAMESIZE 32 -#define UT_HOSTSIZE 256 - - -/* The structure describing an entry in the database of - previous logins. */ -struct lastlog - { -#if __WORDSIZE == 32 - int64_t ll_time; -#else - __time_t ll_time; -#endif - char ll_line[UT_LINESIZE]; - char ll_host[UT_HOSTSIZE]; - }; - - -/* The structure describing the status of a terminated process. This - type is used in `struct utmp' below. */ -struct exit_status - { - short int e_termination; /* Process termination status. */ - short int e_exit; /* Process exit status. */ - }; - - -/* The structure describing an entry in the user accounting database. */ -struct utmp -{ - short int ut_type; /* Type of login. */ - pid_t ut_pid; /* Process ID of login process. */ - char ut_line[UT_LINESIZE] - __attribute_nonstring__; /* Devicename. */ - char ut_id[4] - __attribute_nonstring__; /* Inittab ID. */ - char ut_user[UT_NAMESIZE] - __attribute_nonstring__; /* Username. */ - char ut_host[UT_HOSTSIZE] - __attribute_nonstring__; /* Hostname for remote login. */ - struct exit_status ut_exit; /* Exit status of a process marked - as DEAD_PROCESS. */ -/* The ut_session and ut_tv fields must be the same size when compiled - 32- and 64-bit. This allows data files and shared memory to be - shared between 32- and 64-bit applications. */ -#if __WORDSIZE == 32 - int64_t ut_session; /* Session ID, used for windowing. */ - struct - { - int64_t tv_sec; /* Seconds. */ - int64_t tv_usec; /* Microseconds. */ - } ut_tv; /* Time entry was made. */ -#else - long int ut_session; /* Session ID, used for windowing. */ - struct timeval ut_tv; /* Time entry was made. */ -#endif - - int32_t ut_addr_v6[4]; /* Internet address of remote host. */ - char __glibc_reserved[20]; /* Reserved for future use. */ -}; - -/* Backwards compatibility hacks. */ -#define ut_name ut_user -#ifndef _NO_UT_TIME -/* We have a problem here: `ut_time' is also used otherwise. Define - _NO_UT_TIME if the compiler complains. */ -# define ut_time ut_tv.tv_sec -#endif -#define ut_xtime ut_tv.tv_sec -#define ut_addr ut_addr_v6[0] - - -/* Values for the `ut_type' field of a `struct utmp'. */ -#define EMPTY 0 /* No valid user accounting information. */ - -#define RUN_LVL 1 /* The system's runlevel. */ -#define BOOT_TIME 2 /* Time of system boot. */ -#define NEW_TIME 3 /* Time after system clock changed. */ -#define OLD_TIME 4 /* Time when system clock changed. */ - -#define INIT_PROCESS 5 /* Process spawned by the init process. */ -#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */ -#define USER_PROCESS 7 /* Normal process. */ -#define DEAD_PROCESS 8 /* Terminated process. */ - -#define ACCOUNTING 9 - -/* Old Linux name for the EMPTY type. */ -#define UT_UNKNOWN EMPTY - - -/* Tell the user that we have a modern system with UT_HOST, UT_PID, - UT_TYPE, UT_ID and UT_TV fields. */ -#define _HAVE_UT_TYPE 1 -#define _HAVE_UT_PID 1 -#define _HAVE_UT_ID 1 -#define _HAVE_UT_TV 1 -#define _HAVE_UT_HOST 1 \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/utmpx.h b/lib/libc/include/s390x-linux-gnu/bits/utmpx.h deleted file mode 100644 index 00ed2f21a1c4853e7f45dafe7d8ca46a0b4b44a7..0000000000000000000000000000000000000000 --- a/lib/libc/include/s390x-linux-gnu/bits/utmpx.h +++ /dev/null @@ -1,106 +0,0 @@ -/* Structures and definitions for the user accounting database. GNU version. - Copyright (C) 1997-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _UTMPX_H -# error "Never include directly; use instead." -#endif - -#include -#include -#include - - -#ifdef __USE_GNU -# include -# define _PATH_UTMPX _PATH_UTMP -# define _PATH_WTMPX _PATH_WTMP -#endif - - -#define __UT_LINESIZE 32 -#define __UT_NAMESIZE 32 -#define __UT_HOSTSIZE 256 - - -/* The structure describing the status of a terminated process. This - type is used in `struct utmpx' below. */ -struct __exit_status - { -#ifdef __USE_GNU - short int e_termination; /* Process termination status. */ - short int e_exit; /* Process exit status. */ -#else - short int __e_termination; /* Process termination status. */ - short int __e_exit; /* Process exit status. */ -#endif - }; - - -/* The structure describing an entry in the user accounting database. */ -struct utmpx -{ - short int ut_type; /* Type of login. */ - __pid_t ut_pid; /* Process ID of login process. */ - char ut_line[__UT_LINESIZE] - __attribute_nonstring__; /* Devicename. */ - char ut_id[4] - __attribute_nonstring__; /* Inittab ID. */ - char ut_user[__UT_NAMESIZE] - __attribute_nonstring__; /* Username. */ - char ut_host[__UT_HOSTSIZE] - __attribute_nonstring__; /* Hostname for remote login. */ - struct __exit_status ut_exit; /* Exit status of a process marked - as DEAD_PROCESS. */ - -/* The fields ut_session and ut_tv must be the same size when compiled - 32- and 64-bit. This allows files and shared memory to be shared - between 32- and 64-bit applications. */ -#if __WORDSIZE == 32 - __int64_t ut_session; /* Session ID, used for windowing. */ - struct - { - __int64_t tv_sec; /* Seconds. */ - __int64_t tv_usec; /* Microseconds. */ - } ut_tv; /* Time entry was made. */ -#else - long int ut_session; /* Session ID, used for windowing. */ - struct timeval ut_tv; /* Time entry was made. */ -#endif - __int32_t ut_addr_v6[4]; /* Internet address of remote host. */ - char __glibc_reserved[20]; /* Reserved for future use. */ -}; - - -/* Values for the `ut_type' field of a `struct utmpx'. */ -#define EMPTY 0 /* No valid user accounting information. */ - -#ifdef __USE_GNU -# define RUN_LVL 1 /* The system's runlevel. */ -#endif -#define BOOT_TIME 2 /* Time of system boot. */ -#define NEW_TIME 3 /* Time after system clock changed. */ -#define OLD_TIME 4 /* Time when system clock changed. */ - -#define INIT_PROCESS 5 /* Process spawned by the init process. */ -#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */ -#define USER_PROCESS 7 /* Normal process. */ -#define DEAD_PROCESS 8 /* Terminated process. */ - -#ifdef __USE_GNU -# define ACCOUNTING 9 /* System accounting. */ -#endif \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/bits/wordsize.h b/lib/libc/include/s390x-linux-gnu/bits/wordsize.h index 8f3304644bdb1e10ae25ea828e95df45e3d4c124..5038df494751b3446f652bcb4d1c5d3e721a61ec 100644 --- a/lib/libc/include/s390x-linux-gnu/bits/wordsize.h +++ b/lib/libc/include/s390x-linux-gnu/bits/wordsize.h @@ -1,11 +1,19 @@ -/* Determine the wordsize from the preprocessor defines. */ +/* Copyright (C) 1999-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. -#if defined __s390x__ -# define __WORDSIZE 64 -#else -# define __WORDSIZE 32 -# define __WORDSIZE32_SIZE_ULONG 1 -# define __WORDSIZE32_PTRDIFF_LONG 0 -#endif + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. -#define __WORDSIZE_TIME64_COMPAT32 0 \ No newline at end of file + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#define __WORDSIZE 64 +#define __WORDSIZE_TIME64_COMPAT32 0 \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/gnu/lib-names-64.h b/lib/libc/include/s390x-linux-gnu/gnu/lib-names-64.h deleted file mode 100644 index 0df63282ccce3e8edc6f72dc3ac75bf7a29e2b5e..0000000000000000000000000000000000000000 --- a/lib/libc/include/s390x-linux-gnu/gnu/lib-names-64.h +++ /dev/null @@ -1,27 +0,0 @@ -/* This file is automatically generated. */ -#ifndef __GNU_LIB_NAMES_H -# error "Never use directly; include instead." -#endif - -#define LD64_SO "ld64.so.1" -#define LD_SO "ld64.so.1" -#define LIBANL_SO "libanl.so.1" -#define LIBBROKENLOCALE_SO "libBrokenLocale.so.1" -#define LIBC_MALLOC_DEBUG_SO "libc_malloc_debug.so.0" -#define LIBC_SO "libc.so.6" -#define LIBDL_SO "libdl.so.2" -#define LIBGCC_S_SO "libgcc_s.so.1" -#define LIBMVEC_SO "libmvec.so.1" -#define LIBM_SO "libm.so.6" -#define LIBNSL_SO "libnsl.so.1" -#define LIBNSS_COMPAT_SO "libnss_compat.so.2" -#define LIBNSS_DB_SO "libnss_db.so.2" -#define LIBNSS_DNS_SO "libnss_dns.so.2" -#define LIBNSS_FILES_SO "libnss_files.so.2" -#define LIBNSS_HESIOD_SO "libnss_hesiod.so.2" -#define LIBNSS_LDAP_SO "libnss_ldap.so.2" -#define LIBPTHREAD_SO "libpthread.so.0" -#define LIBRESOLV_SO "libresolv.so.2" -#define LIBRT_SO "librt.so.1" -#define LIBTHREAD_DB_SO "libthread_db.so.1" -#define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/gnu/lib-names.h b/lib/libc/include/s390x-linux-gnu/gnu/lib-names.h index ad6471507a48c834a5c8cbc13cd851c2e20b74b9..b76efce6d28b32d6d22ad38b1239a620cf950a8a 100644 --- a/lib/libc/include/s390x-linux-gnu/gnu/lib-names.h +++ b/lib/libc/include/s390x-linux-gnu/gnu/lib-names.h @@ -4,13 +4,28 @@ #ifndef __GNU_LIB_NAMES_H #define __GNU_LIB_NAMES_H 1 -#include - -#if __WORDSIZE == 32 -# include -#endif -#if __WORDSIZE == 64 -# include -#endif +#define LD64_SO "ld64.so.1" +#define LD_SO "ld64.so.1" +#define LIBANL_SO "libanl.so.1" +#define LIBBROKENLOCALE_SO "libBrokenLocale.so.1" +#define LIBC_MALLOC_DEBUG_SO "libc_malloc_debug.so.0" +#define LIBC_SO "libc.so.6" +#define LIBDL_SO "libdl.so.2" +#define LIBGCC_S_SO "libgcc_s.so.1" +#define LIBMVEC_SO "libmvec.so.1" +#define LIBM_SO "libm.so.6" +#define LIBNSL_SO "libnsl.so.1" +#define LIBNSS_COMPAT_SO "libnss_compat.so.2" +#define LIBNSS_DB_SO "libnss_db.so.2" +#define LIBNSS_DNS_SO "libnss_dns.so.2" +#define LIBNSS_FILES_SO "libnss_files.so.2" +#define LIBNSS_HESIOD_SO "libnss_hesiod.so.2" +#define LIBNSS_LDAP_SO "libnss_ldap.so.2" +#define LIBPTHREAD_SO "libpthread.so.0" +#define LIBRESOLV_SO "libresolv.so.2" +#define LIBRT_SO "librt.so.1" +#define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" +#define LIBUTIL_SO "libutil.so.1" #endif /* gnu/lib-names.h */ \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/gnu/stubs.h b/lib/libc/include/s390x-linux-gnu/gnu/stubs.h index 120171a87ae7a525497cffc5786ed0383b47ca33..636dc73283f9e3508fca4713d7d911f47d284387 100644 --- a/lib/libc/include/s390x-linux-gnu/gnu/stubs.h +++ b/lib/libc/include/s390x-linux-gnu/gnu/stubs.h @@ -1,12 +1,16 @@ /* This file is automatically generated. - This file selects the right generated file of `__stub_FUNCTION' macros - based on the architecture being compiled for. */ + It defines a symbol `__stub_FUNCTION' for each function + in the C library which is a stub, meaning it will fail + every time called, usually setting errno to ENOSYS. */ -#include - -#if __WORDSIZE == 32 -# include +#ifdef _LIBC + #error Applications may not define the macro _LIBC #endif -#if __WORDSIZE == 64 -# include -#endif \ No newline at end of file + +#define __stub_chflags +#define __stub_fchflags +#define __stub_gtty +#define __stub_revoke +#define __stub_setlogin +#define __stub_sigreturn +#define __stub_stty \ No newline at end of file diff --git a/lib/libc/include/s390x-linux-gnu/sys/ucontext.h b/lib/libc/include/s390x-linux-gnu/sys/ucontext.h index a766145563a3c44816cf2985502cfc5f11507948..950d26f9b433db86e9b9df218a23aff1cc3e37e8 100644 --- a/lib/libc/include/s390x-linux-gnu/sys/ucontext.h +++ b/lib/libc/include/s390x-linux-gnu/sys/ucontext.h @@ -45,11 +45,7 @@ typedef unsigned long greg_t; the register set is an array, we make gregset_t a simple array that has the same size as s390_regs. This is needed for the elf_prstatus structure. */ -#if __WORDSIZE == 64 -# define __NGREG 27 -#else -# define __NGREG 36 -#endif +#define __NGREG 27 #ifdef __USE_MISC # define NGREG __NGREG #endif diff --git a/lib/libc/include/sparc-linux-gnu/bits/cloexec.h b/lib/libc/include/sparc-linux-gnu/bits/cloexec.h new file mode 100644 index 0000000000000000000000000000000000000000..153b5491cd5cfc283387276a0c6b4b2ae6fb45d8 --- /dev/null +++ b/lib/libc/include/sparc-linux-gnu/bits/cloexec.h @@ -0,0 +1 @@ +#define __O_CLOEXEC 0x400000 \ No newline at end of file diff --git a/lib/libc/include/sparc-linux-gnu/gnu/lib-names-64.h b/lib/libc/include/sparc-linux-gnu/gnu/lib-names-64.h index 7e53ae0eb3f6bb5ea6f99a2c1e5de7cca1491685..ca08483aab3e398663087d84f914fd0903d98232 100644 --- a/lib/libc/include/sparc-linux-gnu/gnu/lib-names-64.h +++ b/lib/libc/include/sparc-linux-gnu/gnu/lib-names-64.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/sparc-linux-gnu/gnu/stubs-64.h b/lib/libc/include/sparc-linux-gnu/gnu/stubs-64.h new file mode 100644 index 0000000000000000000000000000000000000000..636dc73283f9e3508fca4713d7d911f47d284387 --- /dev/null +++ b/lib/libc/include/sparc-linux-gnu/gnu/stubs-64.h @@ -0,0 +1,16 @@ +/* This file is automatically generated. + It defines a symbol `__stub_FUNCTION' for each function + in the C library which is a stub, meaning it will fail + every time called, usually setting errno to ENOSYS. */ + +#ifdef _LIBC + #error Applications may not define the macro _LIBC +#endif + +#define __stub_chflags +#define __stub_fchflags +#define __stub_gtty +#define __stub_revoke +#define __stub_setlogin +#define __stub_sigreturn +#define __stub_stty \ No newline at end of file diff --git a/lib/libc/include/x86-linux-gnu/bits/struct_mutex.h b/lib/libc/include/x86-linux-gnu/bits/struct_mutex.h index 13c9894ad4b3156677a2475ede4c0bc47d1df68a..70b516b1e5d32ca6c8b99c393ad62b7f086723ab 100644 --- a/lib/libc/include/x86-linux-gnu/bits/struct_mutex.h +++ b/lib/libc/include/x86-linux-gnu/bits/struct_mutex.h @@ -59,4 +59,4 @@ struct __pthread_mutex_s 0, 0, 0, __kind, 0, { { 0, 0 } } #endif -#endif +#endif \ No newline at end of file diff --git a/lib/libc/include/x86-linux-gnu/gnu/lib-names-64.h b/lib/libc/include/x86-linux-gnu/gnu/lib-names-64.h index 26bcb6482efed72a960e0f0d5f79aee819f683b4..e570e8dc72828087c96f32b08a0150a17f709224 100644 --- a/lib/libc/include/x86-linux-gnu/gnu/lib-names-64.h +++ b/lib/libc/include/x86-linux-gnu/gnu/lib-names-64.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/x86-linux-gnu/gnu/lib-names-x32.h b/lib/libc/include/x86-linux-gnu/gnu/lib-names-x32.h index 735e8e2d3907906c879428d5433b19c9f8065b24..0ac184ea85c124f89fa21819b5c36c7e16e031ad 100644 --- a/lib/libc/include/x86-linux-gnu/gnu/lib-names-x32.h +++ b/lib/libc/include/x86-linux-gnu/gnu/lib-names-x32.h @@ -24,4 +24,5 @@ #define LIBRESOLV_SO "libresolv.so.2" #define LIBRT_SO "librt.so.1" #define LIBTHREAD_DB_SO "libthread_db.so.1" +#define LIBUNWIND_SO "libunwind.so.1" #define LIBUTIL_SO "libutil.so.1" \ No newline at end of file diff --git a/lib/libc/include/x86-netbsd-none/machine/mcontext.h b/lib/libc/include/x86-netbsd-none/machine/mcontext.h index eca7a40be452d1894f78d3de2424c400ea2dbd6e..bf34279f20a8dfa0fb8aa61839b7de8b2b96f640 100644 --- a/lib/libc/include/x86-netbsd-none/machine/mcontext.h +++ b/lib/libc/include/x86-netbsd-none/machine/mcontext.h @@ -1,4 +1,4 @@ -/* $NetBSD: mcontext.h,v 1.19 2024/11/30 01:04:10 christos Exp $ */ +/* $NetBSD: mcontext.h,v 1.19.2.1 2026/07/19 15:57:27 martin Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -40,6 +40,7 @@ #define _UC_CLRSTACK _UC_MD_BIT17 #define _UC_VM _UC_MD_BIT18 #define _UC_TLSBASE _UC_MD_BIT19 +#define _UC_XSAVE _UC_MD_BIT20 /* * Layout of mcontext_t according to the System V Application Binary Interface, @@ -85,6 +86,27 @@ typedef struct { char __fp_xmm[512]; } __fp_xmm_state; /* x87 and xmm regs in fxsave format */ int __fp_fpregs[128]; + struct { + /* + * `The XSAVE feature set does not use bytes + * 511:416; bytes 463:416 are reserved.' + * + * We take a part out of this to form a pointer + * to an external XSAVE area. This way, we can + * replicate the FXSAVE parts for the benefit + * of userland programs that aren't aware of + * the XSAVE pointer, have used the extended + * CPU registers (ymmN/zmmN/&c.), and want to + * examine the x87/SSE register state in a + * signal handler. The kernel does not use + * this part. + */ + char __fxsave[416]; + char __rsvd[48]; + __greg_t __xsaveptr; + __greg_t __xsavelen; + char __pad[40]; + } __xsave; } __fp_reg_set; int __fp_pad[33]; /* Historic padding */ } __fpregset_t; diff --git a/lib/libc/include/x86_64-netbsd-none/amd64/mcontext.h b/lib/libc/include/x86_64-netbsd-none/amd64/mcontext.h index 9d70991fa91fe048ff0eba745c83912464a15682..911c0c7c0ce632d0643001b55fe627cc56908d38 100644 --- a/lib/libc/include/x86_64-netbsd-none/amd64/mcontext.h +++ b/lib/libc/include/x86_64-netbsd-none/amd64/mcontext.h @@ -1,4 +1,4 @@ -/* $NetBSD: mcontext.h,v 1.24 2024/11/30 01:04:06 christos Exp $ */ +/* $NetBSD: mcontext.h,v 1.24.2.1 2026/07/19 15:57:26 martin Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -56,7 +56,28 @@ typedef __greg_t __gregset_t[_NGREG]; * which requires 16 byte alignment. However the mcontext version * is never directly accessed. */ -typedef char __fpregset_t[512] __aligned(8); +typedef union { + char __fxsave[512] __aligned(8); + struct { + /* + * `The XSAVE feature set does not use bytes 511:416; + * bytes 463:416 are reserved.' + * + * We take a part out of this to form a pointer to an + * external XSAVE area. This way, we can replicate the + * FXSAVE parts for the benefit of userland programs + * that aren't aware of the XSAVE pointer, have used + * the extended CPU registers (ymmN/zmmN/&c.), and want + * to examine the x87/SSE register state in a signal + * handler. The kernel does not use this part. + */ + char __fxsave[416]; + char __rsvd[48]; + __greg_t __xsaveptr; + __greg_t __xsavelen; + char __pad[32]; + } __xsave; +} __fpregset_t; typedef struct { __gregset_t __gregs; @@ -75,6 +96,7 @@ typedef struct { #define _UC_MACHINE_SET_PC(uc, pc) _UC_MACHINE_PC(uc) = (pc) #define _UC_TLSBASE _UC_MD_BIT19 +#define _UC_XSAVE _UC_MD_BIT20 /* * mcontext extensions to handle signal delivery. @@ -127,6 +149,13 @@ typedef struct { struct { char __fp_xmm[512]; } __fp_xmm_state; + struct { + char __fxsave[416]; + char __rsvd[48]; + __greg32_t __xsaveptr; + __greg32_t __xsavelen; + char __pad[40]; + } __xsave; } __fp_reg_set; int __fp_pad[33]; /* Historic padding */ } __fpregset32_t; diff --git a/lib/libc/include/x86_64-netbsd-none/machine/mcontext.h b/lib/libc/include/x86_64-netbsd-none/machine/mcontext.h index 9d70991fa91fe048ff0eba745c83912464a15682..911c0c7c0ce632d0643001b55fe627cc56908d38 100644 --- a/lib/libc/include/x86_64-netbsd-none/machine/mcontext.h +++ b/lib/libc/include/x86_64-netbsd-none/machine/mcontext.h @@ -1,4 +1,4 @@ -/* $NetBSD: mcontext.h,v 1.24 2024/11/30 01:04:06 christos Exp $ */ +/* $NetBSD: mcontext.h,v 1.24.2.1 2026/07/19 15:57:26 martin Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -56,7 +56,28 @@ typedef __greg_t __gregset_t[_NGREG]; * which requires 16 byte alignment. However the mcontext version * is never directly accessed. */ -typedef char __fpregset_t[512] __aligned(8); +typedef union { + char __fxsave[512] __aligned(8); + struct { + /* + * `The XSAVE feature set does not use bytes 511:416; + * bytes 463:416 are reserved.' + * + * We take a part out of this to form a pointer to an + * external XSAVE area. This way, we can replicate the + * FXSAVE parts for the benefit of userland programs + * that aren't aware of the XSAVE pointer, have used + * the extended CPU registers (ymmN/zmmN/&c.), and want + * to examine the x87/SSE register state in a signal + * handler. The kernel does not use this part. + */ + char __fxsave[416]; + char __rsvd[48]; + __greg_t __xsaveptr; + __greg_t __xsavelen; + char __pad[32]; + } __xsave; +} __fpregset_t; typedef struct { __gregset_t __gregs; @@ -75,6 +96,7 @@ typedef struct { #define _UC_MACHINE_SET_PC(uc, pc) _UC_MACHINE_PC(uc) = (pc) #define _UC_TLSBASE _UC_MD_BIT19 +#define _UC_XSAVE _UC_MD_BIT20 /* * mcontext extensions to handle signal delivery. @@ -127,6 +149,13 @@ typedef struct { struct { char __fp_xmm[512]; } __fp_xmm_state; + struct { + char __fxsave[416]; + char __rsvd[48]; + __greg32_t __xsaveptr; + __greg32_t __xsavelen; + char __pad[40]; + } __xsave; } __fp_reg_set; int __fp_pad[33]; /* Historic padding */ } __fpregset32_t; diff --git a/lib/std/Build.zig b/lib/std/Build.zig index fc2d9909729f1417a4ac486ffea254846137d09b..97b80ff490a06211b4fe40c1e2852a087e59fea8 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -45,17 +45,6 @@ debug_log_scopes: []const []const u8 = &.{}, /// Set to 0 to disable stack collection. debug_stack_frames_count: u8 = 8, -/// Experimental. Use system Darling installation to run cross compiled macOS build artifacts. -enable_darling: bool = false, -/// Use system QEMU installation to run cross compiled foreign architecture build artifacts. -enable_qemu: bool = false, -/// Darwin. Use Rosetta to run x86_64 macOS build artifacts on arm64 macOS. -enable_rosetta: bool = false, -/// Use system Wasmtime installation to run cross compiled wasm/wasi build artifacts. -enable_wasmtime: bool = false, -/// Use system Wine installation to run cross compiled Windows build artifacts. -enable_wine: bool = false, - dep_prefix: []const u8 = "", modules: std.array_hash_map.String(*Module), @@ -388,11 +377,6 @@ fn createChild( .default_step = undefined, .top_level_steps = .{}, .debug_log_scopes = parent.debug_log_scopes, - .enable_darling = parent.enable_darling, - .enable_qemu = parent.enable_qemu, - .enable_rosetta = parent.enable_rosetta, - .enable_wasmtime = parent.enable_wasmtime, - .enable_wine = parent.enable_wine, .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }), .modules = .empty, .named_writefiles = .empty, @@ -830,7 +814,7 @@ pub fn addTest(b: *Build, options: TestOptions) *Step.Compile { .kind = if (options.emit_object) .test_obj else .@"test", .root_module = options.root_module, .max_rss = options.max_rss, - .filters = b.dupeStrings(options.filters), + .filters = b.graph.dupeStrings(options.filters), .test_runner = options.test_runner, .use_llvm = options.use_llvm, .use_lld = options.use_lld, @@ -1125,7 +1109,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw const type_id = comptime typeToEnum(T); const enum_options = if (type_id == .@"enum" or type_id == .enum_list) blk: { const EnumType = if (type_id == .enum_list) @typeInfo(T).pointer.child else T; - const field_names = comptime std.meta.fieldNames(EnumType); + const field_names = @typeInfo(EnumType).@"enum".field_names; var options = std.array_list.Managed([]const u8).initCapacity(b.allocator, field_names.len) catch @panic("OOM"); inline for (field_names) |field_name| { @@ -1210,13 +1194,16 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw return null; }, .scalar => |s| { - if (std.meta.stringToEnum(T, s)) |enum_lit| { - return enum_lit; - } else { - log.err("expected -D{s} to be of type {s}", .{ name, @typeName(T) }); - b.markInvalidUserInput(); - return null; + if (T == std.lang.Optimize) { + if (std.lang.Optimize.fromString(s)) |tag| { + return tag; + } + } else if (std.meta.stringToEnum(T, s)) |tag| { + return tag; } + log.err("expected -D{s} to be of type {q}", .{ name, @typeName(T) }); + b.markInvalidUserInput(); + return null; }, }, .string => switch (option_ptr.value) { @@ -1262,23 +1249,36 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw }, .scalar => |s| { const Child = @typeInfo(T).pointer.child; - const value = std.meta.stringToEnum(Child, s) orelse { - log.err("expected -D{s} to be of type {s}", .{ name, @typeName(Child) }); - b.markInvalidUserInput(); - return null; - }; - return arena.dupe(Child, &[_]Child{value}) catch @panic("OOM"); + if (Child == std.lang.Optimize) { + if (std.lang.Optimize.fromString(s)) |tag| { + return arena.dupe(Child, &.{tag}) catch @panic("OOM"); + } + } else { + if (std.meta.stringToEnum(Child, s)) |tag| { + return arena.dupe(Child, &.{tag}) catch @panic("OOM"); + } + } + log.err("expected -D{s} to be of type {q}", .{ name, @typeName(Child) }); + b.markInvalidUserInput(); + return null; }, .list => |lst| { const Child = @typeInfo(T).pointer.child; const new_list = graph.alloc(Child, lst.items.len); for (new_list, lst.items) |*new_item, str| { - new_item.* = std.meta.stringToEnum(Child, str) orelse { - log.err("expected -D{s} to be of type {s}", .{ name, @typeName(Child) }); - b.markInvalidUserInput(); - arena.free(new_list); - return null; - }; + if (Child == std.lang.Optimize) { + if (std.lang.Optimize.fromString(str)) |tag| { + new_item.* = tag; + continue; + } + } + if (std.meta.stringToEnum(Child, str)) |tag| { + new_item.* = tag; + continue; + } + log.err("expected -D{s} to be of type {q}", .{ name, @typeName(Child) }); + b.markInvalidUserInput(); + return null; } return new_list; }, @@ -1359,14 +1359,14 @@ pub fn standardOptimizeOption(b: *Build, options: StandardOptimizeOptionOptions) } return switch (graph.release_mode) { - .off => .Debug, + .off => .debug, .any => { std.debug.print("the project does not declare a preferred optimization mode. choose: --release=fast, --release=safe, or --release=small\n", .{}); process.exit(1); }, - .fast => .ReleaseFast, - .safe => .ReleaseSafe, - .small => .ReleaseSmall, + .fast => .fast, + .safe => .safe, + .small => .small, }; } @@ -1420,7 +1420,7 @@ pub fn parseTargetQuery(options: std.Target.Query.ParseOptions) error{ParseFaile \\available operating systems: \\ , .{diags.os_name.?}); - inline for (comptime std.meta.fieldNames(Target.Os.Tag)) |field_name| { + inline for (@typeInfo(Target.Os.Tag).@"enum".field_names) |field_name| { std.debug.print(" {s}\n", .{field_name}); } return error.ParseFailed; @@ -2144,7 +2144,7 @@ pub fn dependencyLazy(b: *Build, name: []const u8, args: anytype) error{LazyDepe return dependencyResolved(b, name, entry, userInputOptionsFromArgs(b.graph.arena, args)); } -const PackageEntry = struct { +pub const PackageEntry = struct { hash: []const u8, available: bool, build_root: []const u8, @@ -2152,7 +2152,8 @@ const PackageEntry = struct { run_build: ?*const fn (*Build) void, }; -const package_map: std.StaticStringMap(PackageEntry) = blk: { +/// Build system implementation detail. +pub const package_map: std.StaticStringMap(PackageEntry) = blk: { const deps = @import("root").dependencies; const decl_names = @typeInfo(deps.packages).@"struct".decl_names; var kvs: [decl_names.len]struct { []const u8, PackageEntry } = undefined; @@ -2632,7 +2633,10 @@ pub const LazyPath = union(enum) { fn dupeInner(lazy_path: LazyPath, arena: Allocator) LazyPath { return switch (lazy_path) { - .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } }, + .src_path => |sp| .{ .src_path = .{ + .owner = sp.owner, + .sub_path = sp.owner.graph.dupePath(sp.sub_path), + } }, .cwd_relative => |p| .{ .cwd_relative = Graph.dupePathInner(arena, p) }, .relative => |r| .{ .relative = r }, .generated => |gen| .{ .generated = .{ diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index b839523867b4f151b9761b7178bd2d0290e593eb..52c8187b44741880e3457f9a141e304df2019e13 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -15,6 +15,8 @@ unlazy_deps: []String, system_integrations: []SystemIntegration, available_options: []AvailableOption, search_prefixes: []String, +/// Index 0 always exists and is the root package. +packages: []Package, extra: []u32, default_step: Step.Index, generated_files_len: u32, @@ -30,6 +32,7 @@ pub const Header = extern struct { system_integrations_len: u32, available_options_len: u32, search_prefixes_len: u32, + packages_len: u32, extra_len: u32, default_step: Step.Index, @@ -58,6 +61,7 @@ pub const Wip = struct { steps: std.ArrayList(Step) = .empty, path_deps: std.ArrayList(PathDep) = .empty, search_prefixes: std.ArrayList(String) = .empty, + packages: std.ArrayList(Package) = .empty, extra: std.ArrayList(u32) = .empty, next_generated_file_index: u32 = 0, cache_poison: bool = false, @@ -121,7 +125,7 @@ pub const Wip = struct { } pub fn hash(_: @This(), adapted_key: []const u8) u64 { - assert(std.mem.indexOfScalar(u8, adapted_key, 0) == null); + assert(std.mem.findScalar(u8, adapted_key, 0) == null); return std.hash_map.hashString(adapted_key); } }; @@ -139,6 +143,7 @@ pub const Wip = struct { wip.steps.deinit(gpa); wip.path_deps.deinit(gpa); wip.search_prefixes.deinit(gpa); + wip.packages.deinit(gpa); wip.extra.deinit(gpa); wip.* = undefined; } @@ -158,6 +163,7 @@ pub const Wip = struct { .system_integrations_len = @intCast(wip.system_integrations.items.len), .available_options_len = @intCast(wip.available_options.items.len), .search_prefixes_len = @intCast(wip.search_prefixes.items.len), + .packages_len = @intCast(wip.packages.items.len), .extra_len = @intCast(wip.extra.items.len), .default_step = static.default_step, @@ -175,6 +181,7 @@ pub const Wip = struct { @ptrCast(wip.system_integrations.items), @ptrCast(wip.available_options.items), @ptrCast(wip.search_prefixes.items), + @ptrCast(wip.packages.items), @ptrCast(wip.extra.items), }; try w.writeVecAll(&buffers); @@ -182,7 +189,7 @@ pub const Wip = struct { pub fn addString(wip: *Wip, bytes: []const u8) Allocator.Error!String { const gpa = wip.gpa; - assert(std.mem.indexOfScalar(u8, bytes, 0) == null); + assert(std.mem.findScalar(u8, bytes, 0) == null); const gop = try wip.string_table.getOrPutContextAdapted( gpa, @as([]const u8, bytes), @@ -439,7 +446,7 @@ pub const Wip = struct { /// Returned slice expires upon next append to the configuration. pub fn stringSlice(wip: *const Wip, s: String) [:0]const u8 { const start_slice = wip.string_bytes.items[@backingInt(s)..]; - return start_slice[0..std.mem.indexOfScalar(u8, start_slice, 0).? :0]; + return start_slice[0..std.mem.findScalar(u8, start_slice, 0).? :0]; } }; @@ -569,8 +576,7 @@ pub const Step = extern struct { flags2: Flags2, args: Storage.LengthPrefixedList(Arg.Index), cwd: Storage.FlagOptional(.flags, .cwd, LazyPath.Index), - preopen_names: Storage.LengthPrefixedList(String), - preopen_paths: Storage.LengthPrefixedList(LazyPath.Index), + preopens: Storage.FlagLengthPrefixedList(.flags, .preopens, Preopen), captured_stdout: Storage.FlagOptional(.flags, .captured_stdout, CapturedStream), captured_stderr: Storage.FlagOptional(.flags, .captured_stderr, CapturedStream), file_inputs: Storage.LengthPrefixedList(LazyPath.Index), @@ -627,6 +633,13 @@ pub const Step = extern struct { output_file, output_directory, passthru, + /// `prefix` contains the enabled string. + /// `suffix` contains the disabled string. + enable_darling, + enable_qemu, + enable_rosetta, + enable_wasmtime, + enable_wine, }; pub const Index = IndexType(@This()); @@ -646,6 +659,11 @@ pub const Step = extern struct { manual, }; + pub const Preopen = extern struct { + name: String, + path: LazyPath.Index, + }; + pub const StdIn = union(@This().Tag) { none: void, bytes: Bytes, @@ -676,7 +694,8 @@ pub const Step = extern struct { captured_stdout: bool, captured_stderr: bool, environ_map: bool, - _: u4 = 0, + preopens: bool, + _: u3 = 0, }; pub const Flags2 = packed struct(u32) { @@ -979,8 +998,6 @@ pub const Step = extern struct { }; pub const Flags3 = packed struct(u32) { - is_linking_libc: bool, - is_linking_libcpp: bool, version: bool, initial_memory: bool, max_memory: bool, @@ -998,6 +1015,7 @@ pub const Step = extern struct { entry: Entry, lto: Lto, subsystem: Subsystem, + _: u2 = 0, }; pub const Flags4 = packed struct(u32) { @@ -1076,6 +1094,7 @@ pub const Step = extern struct { autoconf_undef, autoconf_at, cmake, + meson, blank, nasm, @@ -1084,6 +1103,7 @@ pub const Step = extern struct { .autoconf_undef => .autoconf_undef, .autoconf_at => .autoconf_at, .cmake => .cmake, + .meson => .meson, .blank => .blank, .nasm => .nasm, }; @@ -1589,30 +1609,28 @@ pub const OptionalGeneratedFileIndex = enum(u32) { } }; -pub const Package = struct { +pub const Package = extern struct { dep_prefix: String, hash: String, root_path: String, + deps: Dep.List.Index, pub const Index = enum(u32) { - root = max_u32, + root, _, - /// Returns `null` for root package. - pub fn get(i: @This(), c: *const Configuration) ?Package { - if (i == .root) return null; - return extraData(c, Package, @backingInt(i)); + pub fn ptr(i: @This(), c: *const Configuration) *const Package { + return &c.packages[@backingInt(i)]; } pub fn depPrefixSlice(i: @This(), c: *const Configuration) [:0]const u8 { - const package = get(i, c) orelse return ""; - return package.dep_prefix.slice(c); + return ptr(i, c).dep_prefix.slice(c); } }; pub const OptionalIndex = enum(u32) { - none = max_u32 - 1, - root = max_u32, + root, + none = max_u32, _, pub fn init(i: Index) OptionalIndex { @@ -1629,6 +1647,28 @@ pub const Package = struct { }; } }; + + pub const Dep = extern struct { + name: String, + /// Must not be `.root`. + package: Package.Index, + + pub const List = struct { + deps: Storage.LengthPrefixedList(Dep), + + pub const Index = enum(u32) { + _, + + pub fn get(this: @This(), c: *const Configuration) List { + return extraData(c, List, @backingInt(this)); + } + + pub fn slice(this: @This(), c: *const Configuration) []const Dep { + return get(this, c).deps.slice; + } + }; + }; + }; }; pub const Module = struct { @@ -1655,10 +1695,10 @@ pub const Module = struct { pub fn init(o: ?std.builtin.OptimizeMode) Optimize { return switch (o orelse return .default) { - .Debug => .debug, - .ReleaseSafe => .safe, - .ReleaseFast => .fast, - .ReleaseSmall => .small, + .debug => .debug, + .safe => .safe, + .fast => .fast, + .small => .small, }; } }; @@ -1946,7 +1986,7 @@ pub const String = enum(u32) { pub fn slice(index: String, c: *const Configuration) [:0]const u8 { const start_slice = c.string_bytes[@backingInt(index)..]; - return start_slice[0..std.mem.indexOfScalar(u8, start_slice, 0).? :0]; + return start_slice[0..std.mem.findScalar(u8, start_slice, 0).? :0]; } }; @@ -2113,27 +2153,18 @@ pub const OptionalCSourceLanguage = enum(u3) { objective_cpp, assembly, assembly_with_preprocessor, + default, pub fn init(x: ?std.Build.Module.CSourceLanguage) @This() { return switch (x orelse return .default) { - .c => .c, - .cpp => .cpp, - .objective_c => .objective_c, - .objective_cpp => .objective_cpp, - .assembly => .assembly, - .assembly_with_preprocessor => .assembly_with_preprocessor, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn get(this: @This()) ?std.Build.Module.CSourceLanguage { return switch (this) { - .c => .c, - .cpp => .cpp, - .objective_c => .objective_c, - .objective_cpp => .objective_cpp, - .assembly => .assembly, - .assembly_with_preprocessor => .assembly_with_preprocessor, + inline else => |tag| @field(std.Build.Module.CSourceLanguage, @tagName(tag)), .default => null, }; } @@ -2261,10 +2292,7 @@ pub const TargetQuery = struct { pub fn init(x: std.Target.Query.CpuModel) @This() { return switch (x) { - .native => .native, - .baseline => .baseline, - .determined_by_arch_os => .determined_by_arch_os, - .explicit => .explicit, + inline else => |_, tag| @field(@This(), @tagName(tag)), }; } }; @@ -2322,71 +2350,13 @@ pub const TargetQuery = struct { pub fn init(x: ?std.Target.Abi) @This() { return switch (x orelse return .default) { - .none => .none, - .gnu => .gnu, - .gnuabin32 => .gnuabin32, - .gnuabi64 => .gnuabi64, - .gnueabi => .gnueabi, - .gnueabihf => .gnueabihf, - .gnuf32 => .gnuf32, - .gnusf => .gnusf, - .gnux32 => .gnux32, - .eabi => .eabi, - .eabihf => .eabihf, - .abin32 => .abin32, - .x32 => .x32, - .ilp32 => .ilp32, - .android => .android, - .androideabi => .androideabi, - .musl => .musl, - .muslabin32 => .muslabin32, - .muslabi64 => .muslabi64, - .musleabi => .musleabi, - .musleabihf => .musleabihf, - .muslf32 => .muslf32, - .muslsf => .muslsf, - .muslx32 => .muslx32, - .msvc => .msvc, - .itanium => .itanium, - .simulator => .simulator, - .ohos => .ohos, - .ohoseabi => .ohoseabi, - .call0 => .call0, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn unwrap(this: @This()) ?std.Target.Abi { return switch (this) { - .none => .none, - .gnu => .gnu, - .gnuabin32 => .gnuabin32, - .gnuabi64 => .gnuabi64, - .gnueabi => .gnueabi, - .gnueabihf => .gnueabihf, - .gnuf32 => .gnuf32, - .gnusf => .gnusf, - .gnux32 => .gnux32, - .eabi => .eabi, - .eabihf => .eabihf, - .abin32 => .abin32, - .x32 => .x32, - .ilp32 => .ilp32, - .android => .android, - .androideabi => .androideabi, - .musl => .musl, - .muslabin32 => .muslabin32, - .muslabi64 => .muslabi64, - .musleabi => .musleabi, - .musleabihf => .musleabihf, - .muslf32 => .muslf32, - .muslsf => .muslsf, - .muslx32 => .muslx32, - .msvc => .msvc, - .itanium => .itanium, - .simulator => .simulator, - .ohos => .ohos, - .ohoseabi => .ohoseabi, - .call0 => .call0, + inline else => |tag| @field(std.Target.Abi, @tagName(tag)), .default => null, }; } @@ -2458,132 +2428,13 @@ pub const TargetQuery = struct { pub fn init(x: ?std.Target.Cpu.Arch) @This() { return switch (x orelse return .default) { - .aarch64 => .aarch64, - .aarch64_be => .aarch64_be, - .alpha => .alpha, - .amdgcn => .amdgcn, - .arc => .arc, - .arceb => .arceb, - .arm => .arm, - .armeb => .armeb, - .avr => .avr, - .bpfeb => .bpfeb, - .bpfel => .bpfel, - .csky => .csky, - .ez80 => .ez80, - .hexagon => .hexagon, - .hppa => .hppa, - .hppa64 => .hppa64, - .kalimba => .kalimba, - .kvx => .kvx, - .lanai => .lanai, - .loongarch32 => .loongarch32, - .loongarch64 => .loongarch64, - .m68k => .m68k, - .m88k => .m88k, - .microblaze => .microblaze, - .microblazeel => .microblazeel, - .mips => .mips, - .mipsel => .mipsel, - .mips64 => .mips64, - .mips64el => .mips64el, - .msp430 => .msp430, - .nvptx => .nvptx, - .nvptx64 => .nvptx64, - .or1k => .or1k, - .powerpc => .powerpc, - .powerpcle => .powerpcle, - .powerpc64 => .powerpc64, - .powerpc64le => .powerpc64le, - .propeller => .propeller, - .riscv32 => .riscv32, - .riscv32be => .riscv32be, - .riscv64 => .riscv64, - .riscv64be => .riscv64be, - .s390x => .s390x, - .sh => .sh, - .sheb => .sheb, - .sparc => .sparc, - .sparc64 => .sparc64, - .spirv32 => .spirv32, - .spirv64 => .spirv64, - .thumb => .thumb, - .thumbeb => .thumbeb, - .ve => .ve, - .wasm32 => .wasm32, - .wasm64 => .wasm64, - .x86_16 => .x86_16, - .x86 => .x86, - .x86_64 => .x86_64, - .xcore => .xcore, - .xtensa => .xtensa, - .xtensaeb => .xtensaeb, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn unwrap(this: @This()) ?std.Target.Cpu.Arch { return switch (this) { - .aarch64 => .aarch64, - .aarch64_be => .aarch64_be, - .alpha => .alpha, - .amdgcn => .amdgcn, - .arc => .arc, - .arceb => .arceb, - .arm => .arm, - .armeb => .armeb, - .avr => .avr, - .bpfeb => .bpfeb, - .bpfel => .bpfel, - .csky => .csky, - .ez80 => .ez80, - .hexagon => .hexagon, - .hppa => .hppa, - .hppa64 => .hppa64, - .kalimba => .kalimba, - .kvx => .kvx, - .lanai => .lanai, - .loongarch32 => .loongarch32, - .loongarch64 => .loongarch64, - .m68k => .m68k, - .m88k => .m88k, - .microblaze => .microblaze, - .microblazeel => .microblazeel, - .mips => .mips, - .mipsel => .mipsel, - .mips64 => .mips64, - .mips64el => .mips64el, - .msp430 => .msp430, - .nvptx => .nvptx, - .nvptx64 => .nvptx64, - .or1k => .or1k, - .powerpc => .powerpc, - .powerpcle => .powerpcle, - .powerpc64 => .powerpc64, - .powerpc64le => .powerpc64le, - .propeller => .propeller, - .riscv32 => .riscv32, - .riscv32be => .riscv32be, - .riscv64 => .riscv64, - .riscv64be => .riscv64be, - .s390x => .s390x, - .sh => .sh, - .sheb => .sheb, - .sparc => .sparc, - .sparc64 => .sparc64, - .spirv32 => .spirv32, - .spirv64 => .spirv64, - .thumb => .thumb, - .thumbeb => .thumbeb, - .ve => .ve, - .wasm32 => .wasm32, - .wasm64 => .wasm64, - .x86_16 => .x86_16, - .x86 => .x86, - .x86_64 => .x86_64, - .xcore => .xcore, - .xtensa => .xtensa, - .xtensaeb => .xtensaeb, - + inline else => |tag| @field(std.Target.Cpu.Arch, @tagName(tag)), .default => null, }; } @@ -2642,106 +2493,13 @@ pub const TargetQuery = struct { pub fn init(x: ?std.Target.Os.Tag) @This() { return switch (x orelse return .default) { - .freestanding => .freestanding, - .other => .other, - .contiki => .contiki, - .fuchsia => .fuchsia, - .hermit => .hermit, - .managarm => .managarm, - .haiku => .haiku, - .hurd => .hurd, - .illumos => .illumos, - .linux => .linux, - .plan9 => .plan9, - .rtems => .rtems, - .serenity => .serenity, - .dragonfly => .dragonfly, - .freebsd => .freebsd, - .netbsd => .netbsd, - .openbsd => .openbsd, - .driverkit => .driverkit, - .ios => .ios, - .maccatalyst => .maccatalyst, - .macos => .macos, - .tvos => .tvos, - .visionos => .visionos, - .watchos => .watchos, - .windows => .windows, - .uefi => .uefi, - .@"3ds" => .@"3ds", - .wiiu => .wiiu, - .@"switch" => .@"switch", - .psx => .psx, - .ps3 => .ps3, - .ps4 => .ps4, - .ps5 => .ps5, - .psp => .psp, - .vita => .vita, - .emscripten => .emscripten, - .wasi => .wasi, - .amdhsa => .amdhsa, - .amdpal => .amdpal, - .cuda => .cuda, - .mesa3d => .mesa3d, - .nvcl => .nvcl, - .opencl => .opencl, - .opengl => .opengl, - .vulkan => .vulkan, - .tios => .tios, - .ashetos => .ashetos, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn unwrap(this: @This()) ?std.Target.Os.Tag { return switch (this) { - .freestanding => .freestanding, - .other => .other, - .contiki => .contiki, - .fuchsia => .fuchsia, - .hermit => .hermit, - .managarm => .managarm, - .haiku => .haiku, - .hurd => .hurd, - .illumos => .illumos, - .linux => .linux, - .plan9 => .plan9, - .rtems => .rtems, - .serenity => .serenity, - .dragonfly => .dragonfly, - .freebsd => .freebsd, - .netbsd => .netbsd, - .openbsd => .openbsd, - .driverkit => .driverkit, - .ios => .ios, - .maccatalyst => .maccatalyst, - .macos => .macos, - .tvos => .tvos, - .visionos => .visionos, - .watchos => .watchos, - .windows => .windows, - .uefi => .uefi, - .@"3ds" => .@"3ds", - .wiiu => .wiiu, - .@"switch" => .@"switch", - .psx => .psx, - .ps3 => .ps3, - .ps4 => .ps4, - .ps5 => .ps5, - .psp => .psp, - .vita => .vita, - .emscripten => .emscripten, - .wasi => .wasi, - .amdhsa => .amdhsa, - .amdpal => .amdpal, - .cuda => .cuda, - .mesa3d => .mesa3d, - .nvcl => .nvcl, - .opencl => .opencl, - .opengl => .opengl, - .vulkan => .vulkan, - .tios => .tios, - .ashetos => .ashetos, - + inline else => |tag| @field(std.Target.Os.Tag, @tagName(tag)), .default => null, }; } @@ -2762,30 +2520,13 @@ pub const TargetQuery = struct { pub fn init(x: ?std.Target.ObjectFormat) @This() { return switch (x orelse return .default) { - .c => .c, - .coff => .coff, - .elf => .elf, - .hex => .hex, - .macho => .macho, - .plan9 => .plan9, - .raw => .raw, - .spirv => .spirv, - .wasm => .wasm, + inline else => |tag| @field(@This(), @tagName(tag)), }; } pub fn unwrap(this: @This()) ?std.Target.ObjectFormat { return switch (this) { - .c => .c, - .coff => .coff, - .elf => .elf, - .hex => .hex, - .macho => .macho, - .plan9 => .plan9, - .raw => .raw, - .spirv => .spirv, - .wasm => .wasm, - + inline else => |tag| @field(std.Target.ObjectFormat, @tagName(tag)), .default => null, }; } @@ -3462,6 +3203,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { .system_integrations = try arena.alloc(SystemIntegration, header.system_integrations_len), .available_options = try arena.alloc(AvailableOption, header.available_options_len), .search_prefixes = try arena.alloc(String, header.search_prefixes_len), + .packages = try arena.alloc(Package, header.packages_len), .extra = try arena.alloc(u32, header.extra_len), .default_step = header.default_step, .generated_files_len = header.generated_files_len, @@ -3475,6 +3217,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { @ptrCast(result.system_integrations), @ptrCast(result.available_options), @ptrCast(result.search_prefixes), + @ptrCast(result.packages), @ptrCast(result.extra), }; try reader.readVecAll(&vecs); diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index ac5dc3fd9330bee03bcbedce9a6c8d15d6df106c..7189ecd3e40c232b7a833a9d0bbb257835baab7a 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -402,8 +402,8 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void { const c_source_files = arena.create(CSourceFiles) catch @panic("OOM"); c_source_files.* = .{ .root = options.root orelse b.path(""), - .files = b.dupeStrings(options.files), - .flags = b.dupeStrings(options.flags), + .files = b.graph.dupeStrings(options.files), + .flags = b.graph.dupeStrings(options.flags), .language = options.language, }; m.link_objects.append(arena, .{ .c_source_files = c_source_files }) catch @panic("OOM"); diff --git a/lib/std/Build/Serialize.zig b/lib/std/Build/Serialize.zig index 8849f7aaeec31bf6093f3ee60ec48ba2376f026d..94092f5f0fc58c1528ff7f779715bf7f52be7e41 100644 --- a/lib/std/Build/Serialize.zig +++ b/lib/std/Build/Serialize.zig @@ -10,7 +10,8 @@ const log = std.log; arena: Allocator, wc: *Configuration.Wip, module_map: std.array_hash_map.Auto(*std.Build.Module, Configuration.Module.Index) = .empty, -package_map: std.array_hash_map.Auto(*std.Build, Configuration.Package.Index) = .empty, +/// Keyed by package hash. +package_map: std.array_hash_map.String(Configuration.Package.Index) = .empty, /// Index corresponds to `Configuration.steps` index. step_map: std.array_hash_map.Auto(*Step, void) = .empty, @@ -21,6 +22,10 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi var s: Serialize = .{ .wc = wc, .arena = arena }; + // Serialize all of the packages first to seed the package_map, which is + // later used in calls to packageFromHash. + try s.addRootPackage(b); + try wc.path_deps.ensureTotalCapacityPrecise(gpa, graph.configure_dependencies.items.len); for ( graph.configure_dependencies.items, @@ -44,10 +49,10 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi .relative => |r| try wc.addString(r.sub_path), }, .pkg = switch (src.lazy_path) { - .src_path => |sp| .init(try s.builderToPackage(sp.owner)), + .src_path => |sp| .init(s.packageFromHash(sp.owner.pkg_hash)), .generated => unreachable, .cwd_relative, .relative => .none, - .dependency => |d| .init(try s.builderToPackage(d.dependency.builder)), + .dependency => |d| .init(s.packageFromHash(d.dependency.builder.pkg_hash)), }, }; } @@ -84,7 +89,7 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi try wc.steps.ensureTotalCapacity(gpa, s.step_map.entries.capacity); wc.steps.appendAssumeCapacity(.{ .name = try wc.addString(step.name), - .owner = try s.builderToPackage(step.owner), + .owner = s.packageFromHash(step.owner.pkg_hash), .deps = deps, .max_rss = .fromBytes(step.max_rss), .extended = @fromBackingInt(@intCast(switch (step.tag) { @@ -168,8 +173,6 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi .linkage = .init(c.linkage), }, .flags3 = .{ - .is_linking_libc = c.is_linking_libc, - .is_linking_libcpp = c.is_linking_libcpp, .version = c.version != null, .compress_debug_sections = c.compress_debug_sections, .initial_memory = c.initial_memory != null, @@ -454,6 +457,13 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi }, else => {}, } + const preopens = try arena.alloc( + Configuration.Step.Run.Preopen, + run.preopens.count(), + ); + for (preopens, run.preopens.keys(), run.preopens.values()) |*dest, name, path| { + dest.* = .{ .name = name, .path = try s.addLazyPath(path) }; + } break :e try wc.addExtraErased(Configuration.Step.Run, .{ .flags = .{ @@ -482,6 +492,7 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi .captured_stdout = run.captured_stdout != null, .captured_stderr = run.captured_stderr != null, .environ_map = run.environ_map != null, + .preopens = run.preopens.count() > 0, }, .flags2 = .{ .expect_stderr_exact = expect_stderr_exact != null, @@ -496,8 +507,7 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi .file_inputs = .{ .slice = try s.initLazyPathList(run.file_inputs.items) }, .args = .{ .slice = try s.initArgsList(run.argv.items) }, .cwd = .{ .value = try s.addOptionalLazyPath(run.cwd) }, - .preopen_names = .{ .slice = try s.initStringList(run.preopens.keys()) }, - .preopen_paths = .{ .slice = try s.initLazyPathList(run.preopens.values()) }, + .preopens = .{ .slice = preopens }, .captured_stdout = .{ .value = if (run.captured_stdout) |cs| .{ .basename = try wc.addString(cs.basename), .generated_file = cs.generated_file, @@ -717,19 +727,64 @@ pub fn packageOptions(b: *std.Build, wc: *Configuration.Wip) Allocator.Error!voi } } -fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index { - if (b.pkg_hash.len == 0) return .root; +fn addRootPackage(s: *Serialize, b: *std.Build) Allocator.Error!void { const arena = s.arena; const wc = s.wc; - const gop = try s.package_map.getOrPut(arena, b); - if (!gop.found_existing) { - gop.value_ptr.* = try wc.addExtra(Configuration.Package, .{ - .hash = try wc.addString(b.pkg_hash), - .dep_prefix = try wc.addString(b.dep_prefix), - .root_path = try wc.addString(try b.root.toString(arena)), - }); - } - return gop.value_ptr.*; + + try wc.packages.append(wc.gpa, .{ + .dep_prefix = .empty, + .hash = .empty, + .root_path = try wc.addString(try b.root.toString(arena)), + .deps = undefined, + }); + + const deps = try arena.alloc(Configuration.Package.Dep, b.available_deps.len); + for (deps, b.available_deps) |*dest, src| dest.* = try s.makePackageDep("", src[0], src[1]); + + wc.packages.items[0].deps = try wc.addExtra(Configuration.Package.Dep.List, .{ + .deps = .{ .slice = deps }, + }); +} + +fn makePackageDep(s: *Serialize, parent_dep_prefix: []const u8, name: []const u8, hash: []const u8) Allocator.Error!Configuration.Package.Dep { + const arena = s.arena; + const wc = s.wc; + + if (s.package_map.get(hash)) |index| return .{ + .name = try wc.addString(name), + .package = index, + }; + + const entry = std.Build.package_map.get(hash) orelse unreachable; + + const dep_prefix = try arena.print("{s}{s}.", .{ parent_dep_prefix, name }); + + const index: Configuration.Package.Index = @fromBackingInt(@intCast(wc.packages.items.len)); + try s.package_map.put(arena, hash, index); + + try wc.packages.append(wc.gpa, .{ + .dep_prefix = try wc.addString(dep_prefix), + .hash = try wc.addString(hash), + .root_path = try wc.addString(entry.build_root), + .deps = undefined, + }); + + const deps = try arena.alloc(Configuration.Package.Dep, entry.deps.len); + for (deps, entry.deps) |*dest, src| dest.* = try s.makePackageDep(dep_prefix, src[0], src[1]); + + wc.packages.items[@backingInt(index)].deps = try wc.addExtra(Configuration.Package.Dep.List, .{ + .deps = .{ .slice = deps }, + }); + + return .{ + .name = try wc.addString(name), + .package = index, + }; +} + +fn packageFromHash(s: *Serialize, pkg_hash: []const u8) Configuration.Package.Index { + if (pkg_hash.len == 0) return .root; + return s.package_map.get(pkg_hash) orelse std.debug.panic("unrecognized package hash: {q}", .{pkg_hash}); } fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.LazyPath.OptionalIndex { @@ -738,7 +793,7 @@ fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuratio .src_path => |src_path| i: { const sub_path = try wc.addString(src_path.sub_path); break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{ - .owner = try s.builderToPackage(src_path.owner), + .owner = s.packageFromHash(src_path.owner.pkg_hash), .sub_path = sub_path, }); }, @@ -766,7 +821,7 @@ fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuratio .dependency => |dependency| i: { const sub_path = try wc.addString(dependency.sub_path); break :i try wc.addExtraErased(Configuration.LazyPath.SourcePath, .{ - .owner = try s.builderToPackage(dependency.dependency.builder), + .owner = s.packageFromHash(dependency.dependency.builder.pkg_hash), .sub_path = sub_path, }); }, @@ -1012,6 +1067,101 @@ fn initArgsList(s: *Serialize, args: []const Step.Run.Arg) ![]const Configuratio .producer = .{ .value = null }, .generated = .{ .value = null }, }, + .enable_darling => |a| .{ + .flags = .{ + .tag = .enable_darling, + .prefix = a.enabled != null, + .suffix = a.disabled != null, + .basename = false, + .path = false, + .producer = false, + .generated = false, + .dep_file = false, + .make_absolute = false, + }, + .prefix = .{ .value = try s.addOptionalString(a.enabled) }, + .suffix = .{ .value = try s.addOptionalString(a.disabled) }, + .basename = .{ .value = null }, + .path = .{ .value = null }, + .producer = .{ .value = null }, + .generated = .{ .value = null }, + }, + .enable_qemu => |a| .{ + .flags = .{ + .tag = .enable_qemu, + .prefix = a.enabled != null, + .suffix = a.disabled != null, + .basename = false, + .path = false, + .producer = false, + .generated = false, + .dep_file = false, + .make_absolute = false, + }, + .prefix = .{ .value = try s.addOptionalString(a.enabled) }, + .suffix = .{ .value = try s.addOptionalString(a.disabled) }, + .basename = .{ .value = null }, + .path = .{ .value = null }, + .producer = .{ .value = null }, + .generated = .{ .value = null }, + }, + .enable_rosetta => |a| .{ + .flags = .{ + .tag = .enable_rosetta, + .prefix = a.enabled != null, + .suffix = a.disabled != null, + .basename = false, + .path = false, + .producer = false, + .generated = false, + .dep_file = false, + .make_absolute = false, + }, + .prefix = .{ .value = try s.addOptionalString(a.enabled) }, + .suffix = .{ .value = try s.addOptionalString(a.disabled) }, + .basename = .{ .value = null }, + .path = .{ .value = null }, + .producer = .{ .value = null }, + .generated = .{ .value = null }, + }, + .enable_wasmtime => |a| .{ + .flags = .{ + .tag = .enable_wasmtime, + .prefix = a.enabled != null, + .suffix = a.disabled != null, + .basename = false, + .path = false, + .producer = false, + .generated = false, + .dep_file = false, + .make_absolute = false, + }, + .prefix = .{ .value = try s.addOptionalString(a.enabled) }, + .suffix = .{ .value = try s.addOptionalString(a.disabled) }, + .basename = .{ .value = null }, + .path = .{ .value = null }, + .producer = .{ .value = null }, + .generated = .{ .value = null }, + }, + .enable_wine => |a| .{ + .flags = .{ + .tag = .enable_wine, + .prefix = a.enabled != null, + .suffix = a.disabled != null, + .basename = false, + .path = false, + .producer = false, + .generated = false, + .dep_file = false, + .make_absolute = false, + }, + .prefix = .{ .value = try s.addOptionalString(a.enabled) }, + .suffix = .{ .value = try s.addOptionalString(a.disabled) }, + .basename = .{ .value = null }, + .path = .{ .value = null }, + .producer = .{ .value = null }, + .generated = .{ .value = null }, + }, }); } return result; @@ -1131,7 +1281,7 @@ fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index { .link_libcpp = .init(m.link_libcpp), .no_builtin = .init(m.no_builtin), }, - .owner = try s.builderToPackage(m.owner), + .owner = s.packageFromHash(m.owner.pkg_hash), .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file), .import_table = .invalid, .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target), diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index cc0ac4e99d52b94973fd6bc5269790deff2898cf..df4da47b01df0ae1bdb0ad19e090437f96063bb7 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -101,7 +101,7 @@ each_lib_rpath: ?bool = null, /// This option overrides the CLI argument passed to `zig build`. build_id: ?std.zig.BuildId = null, -/// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF +/// Create a .eh_frame_hdr section and a PT.GNU_EH_FRAME segment in the ELF /// file. link_eh_frame_hdr: bool = false, link_emit_relocs: bool = false, @@ -220,11 +220,6 @@ expect_errors: ?ExpectedCompileErrors = null, /// `std.math.maxInt(u16)`. Overrides the argument passed to `zig build`. error_limit: ?u32 = null, -/// Computed during make(). -is_linking_libc: bool = false, -/// Computed during make(). -is_linking_libcpp: bool = false, - /// Enables coverage instrumentation that is only useful if you are using third /// party fuzzers that depend on it. Otherwise, slows down the instrumented /// binary with unnecessary function calls. @@ -375,7 +370,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { const graph = owner.graph; const arena = graph.arena; - const name = owner.dupe(options.name); + const name = owner.graph.dupeString(options.name); if (mem.find(u8, name, "/") != null or mem.find(u8, name, "\\") != null) { panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); } @@ -390,7 +385,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { @tagName(options.kind) else owner.fmt("{t} {s}", .{ options.kind, name }), - @tagName(options.root_module.optimize orelse .Debug), + @tagName(options.root_module.optimize orelse .debug), resolved_target.query.zigTriple(arena) catch @panic("OOM"), }); @@ -645,7 +640,7 @@ pub fn producesPdbFile(compile: *Compile) bool { if (target.ofmt == .c) return false; if (compile.use_llvm == false) return false; if (compile.root_module.strip == true or - (compile.root_module.strip == null and compile.root_module.optimize == .ReleaseSmall)) + (compile.root_module.strip == null and compile.root_module.optimize == .small)) { return false; } diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index 9d036dcf2db7b1417c60af507461d8ec647aeb9e..9aeebf1a1096fae7bfb4589e386c953839824f9a 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -27,6 +27,9 @@ pub const Style = union(enum) { /// The configure format supported by CMake. It uses `@FOO@`, `${}` and /// `#cmakedefine` for template substitution. cmake: std.Build.LazyPath, + /// The configure format supported by Meson. It uses `@FOO@`, and + /// `#mesondefine` for template substitution. + meson: std.Build.LazyPath, /// Instead of starting with an input file, start with nothing. blank, /// Start with nothing, like blank, and output a nasm .asm file. @@ -34,7 +37,7 @@ pub const Style = union(enum) { pub fn getPath(style: Style) ?std.Build.LazyPath { switch (style) { - .autoconf_undef, .autoconf_at, .cmake => |s| return s, + .autoconf_undef, .autoconf_at, .cmake, .meson => |s| return s, .blank, .nasm => return null, } } diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index a0fc19f5dc8dc33d5f2ee870bd6210c0172d1bd4..7d271e10e1461606574b96a6966332975b39b706 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -28,7 +28,7 @@ environ_map: ?*EnvMap, /// Named files that will be provided to the parent process. /// See `std.process.Preopens`. -preopens: std.array_hash_map.String(Build.LazyPath), +preopens: std.array_hash_map.Auto(Configuration.String, Build.LazyPath), /// Controls the `NO_COLOR` and `CLICOLOR_FORCE` environment variables. color: Color = .auto, @@ -68,9 +68,11 @@ rename_step_with_output_arg: bool, /// executed binary will not fail the build if the binary cannot be executed /// due to being for a foreign binary to the host system which is running the /// build graph. +/// /// Command-line arguments such as -fqemu and -fwasmtime may affect whether a /// binary is detected as foreign, as well as system configuration such as /// Rosetta (macOS) and binfmt_misc (Linux). +/// /// If this Run step is considered to have side-effects, then this flag does /// nothing. skip_foreign_checks: bool, @@ -149,6 +151,19 @@ pub const Arg = union(enum) { output_directory: *Output, /// The arguments passed after "--" on the "zig build" CLI. passthru, + + enable_darling: ToggleFlags, + enable_qemu: ToggleFlags, + enable_rosetta: ToggleFlags, + enable_wasmtime: ToggleFlags, + enable_wine: ToggleFlags, +}; + +pub const ToggleFlags = struct { + /// The string to pass when enabled, or null to omit the arg. + enabled: ?[]const u8 = null, + /// The string to pass when disabled, or null to omit the arg. + disabled: ?[]const u8 = null, }; pub const DecoratedArtifact = struct { @@ -576,6 +591,46 @@ pub fn addPassthruArgs(run: *Run) void { run.argv.append(arena, .passthru) catch @panic("OOM"); } +/// Appends a custom string to the command line depending on the `-fdarling` +/// value passed to `zig build`. +pub fn addThirdPartyEnabledArgDarling(run: *Run, toggle_flags: ToggleFlags) void { + const graph = run.step.owner.graph; + const arena = graph.arena; + run.argv.append(arena, .{ .enable_darling = toggle_flags }) catch @panic("OOM"); +} + +/// Appends a custom string to the command line depending on the `-fqemu` +/// value passed to `zig build`. +pub fn addThirdPartyEnabledArgQemu(run: *Run, toggle_flags: ToggleFlags) void { + const graph = run.step.owner.graph; + const arena = graph.arena; + run.argv.append(arena, .{ .enable_qemu = toggle_flags }) catch @panic("OOM"); +} + +/// Appends a custom string to the command line depending on the `-frosetta` +/// value passed to `zig build`. +pub fn addThirdPartyEnabledArgRosetta(run: *Run, toggle_flags: ToggleFlags) void { + const graph = run.step.owner.graph; + const arena = graph.arena; + run.argv.append(arena, .{ .enable_rosetta = toggle_flags }) catch @panic("OOM"); +} + +/// Appends a custom string to the command line depending on the `-fwasmtime` +/// value passed to `zig build`. +pub fn addThirdPartyEnabledArgWasmtime(run: *Run, toggle_flags: ToggleFlags) void { + const graph = run.step.owner.graph; + const arena = graph.arena; + run.argv.append(arena, .{ .enable_wasmtime = toggle_flags }) catch @panic("OOM"); +} + +/// Appends a custom string to the command line depending on the `-fwine` +/// value passed to `zig build`. +pub fn addThirdPartyEnabledArgWine(run: *Run, toggle_flags: ToggleFlags) void { + const graph = run.step.owner.graph; + const arena = graph.arena; + run.argv.append(arena, .{ .enable_wine = toggle_flags }) catch @panic("OOM"); +} + pub fn setStdIn(run: *Run, stdin: StdIn) void { switch (stdin) { .lazy_path => |lazy_path| lazy_path.addStepDependencies(&run.step), @@ -624,11 +679,12 @@ pub fn removeEnvironmentVariable(run: *Run, key: []const u8) void { pub fn setPreopen(run: *Run, name: []const u8, resource: Build.LazyPath) void { const graph = run.step.owner.graph; + const wc = &graph.wip_configuration; const arena = graph.arena; resource.addStepDependencies(&run.step); run.preopens.put( arena, - graph.dupeString(name), + wc.addString(name) catch @panic("OOM"), resource.dupe(graph), ) catch @panic("OOM"); } diff --git a/lib/std/Io.zig b/lib/std/Io.zig index a680c9d198583eac1b1969d6e92c8ae1065886c3..ec6afd24f9553e853a1eee5897b6b0f5dd363ff2 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -238,7 +238,7 @@ pub const VTable = struct { netSend: *const fn (?*anyopaque, net.Socket.Handle, []net.OutgoingMessage, net.SendFlags) struct { ?net.Socket.SendError, usize }, netWrite: *const fn (?*anyopaque, dest: net.Socket.Handle, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize, netWriteFile: *const fn (?*anyopaque, net.Socket.Handle, header: []const u8, *Io.File.Reader, Io.Limit) net.Stream.Writer.WriteFileError!usize, - netClose: *const fn (?*anyopaque, handle: []const net.Socket.Handle) void, + netClose: *const fn (?*anyopaque, sockets: []const net.Socket) void, netShutdown: *const fn (?*anyopaque, handle: net.Socket.Handle, how: net.ShutdownHow) net.ShutdownError!void, netInterfaceNameResolve: *const fn (?*anyopaque, *const net.Interface.Name) net.Interface.Name.ResolveError!net.Interface, netInterfaceName: *const fn (?*anyopaque, net.Interface) net.Interface.NameError!net.Interface.Name, @@ -467,6 +467,7 @@ pub const OperateTimeoutError = Cancelable || Timeout.Error || ConcurrentError; /// Performs one `Operation` with provided `timeout`. pub fn operateTimeout(io: Io, operation: Operation, timeout: Timeout) OperateTimeoutError!Operation.Result { + if (timeout == .none) return io.vtable.operate(io.userdata, operation); var storage: [1]Operation.Storage = undefined; var batch: Batch = .init(&storage); batch.addAt(0, operation); @@ -778,10 +779,10 @@ pub const Clock = enum { /// * On Linux, corresponds `CLOCK_BOOTTIME`. /// * On macOS, corresponds to `CLOCK_MONOTONIC_RAW`. boot, - /// Tracks the amount of CPU in user or kernel mode used by the calling + /// Tracks the amount of CPU time in user or kernel mode used by the calling /// process. cpu_process, - /// Tracks the amount of CPU in user or kernel mode used by the calling + /// Tracks the amount of CPU time in user or kernel mode used by the calling /// thread. cpu_thread, @@ -980,6 +981,10 @@ pub const Timestamp = struct { const now_ts = clock.now(io); return t.durationTo(now_ts); } + + pub fn compare(lhs: Timestamp, op: math.CompareOperator, rhs: Timestamp) bool { + return math.compare(lhs.nanoseconds, op, rhs.nanoseconds); + } }; pub const Duration = struct { @@ -1147,6 +1152,7 @@ pub const Duration = struct { /// Declares under what conditions an operation should return `error.Timeout`. pub const Timeout = union(enum) { + /// `.none` will wait forever none, duration: Clock.Duration, deadline: Clock.Timestamp, @@ -2525,7 +2531,7 @@ pub fn lockStderr(io: Io, buffer: []u8, terminal_mode: ?Terminal.Mode) Cancelabl /// Same as `lockStderr` but non-blocking. pub fn tryLockStderr(io: Io, buffer: []u8, terminal_mode: ?Terminal.Mode) Cancelable!?LockedStderr { - const ls = (try io.vtable.tryLockStderr(io.userdata, buffer, terminal_mode)) orelse return null; + const ls = (try io.vtable.tryLockStderr(io.userdata, terminal_mode)) orelse return null; try ls.clear(buffer); return ls; } @@ -3476,9 +3482,9 @@ pub fn failingNetWriteFile(userdata: ?*anyopaque, handle: net.Socket.Handle, hea return error.NetworkDown; } -pub fn unreachableNetClose(userdata: ?*anyopaque, handle: []const net.Socket.Handle) void { +pub fn unreachableNetClose(userdata: ?*anyopaque, sockets: []const net.Socket) void { _ = userdata; - _ = handle; + _ = sockets; unreachable; } diff --git a/lib/std/Io/Dispatch.zig b/lib/std/Io/Dispatch.zig index 438ee0d31b4bb907690c3f355a16d10392b1b60f..e342a0a9f9606bfd6a8dff6cc17e900fba8d2129 100644 --- a/lib/std/Io/Dispatch.zig +++ b/lib/std/Io/Dispatch.zig @@ -580,6 +580,7 @@ pub fn deinit(ev: *Evented) void { ev.stderr_mutex.deinit(); for (&ev.futexes) |*futex| futex.deinit(); ev.exit_semaphore.as_object().release(); + ev.backing_allocator_mutex.deinit(); ev.backing_allocator.free(ev.main_loop_stack[0..main_loop_stack_size]); ev.queue.as_object().release(); } @@ -825,7 +826,7 @@ const Mutex = struct { sleeper: Sleeper = undefined, cancelable: Cancelable, mutex: *Mutex, - node: std.DoublyLinkedList.Node = undefined, + node: std.DoublyLinkedList.Node = .{}, fn add(context: ?*anyopaque) callconv(.c) void { const waiter: *Waiter = @ptrCast(@alignCast(context)); @@ -2781,7 +2782,7 @@ fn realPath(ev: *Evented, fd: c.fd_t, out_buffer: []u8) File.RealPathError!usize else => |err| return unexpectedErrno(err), } } - const n = std.mem.indexOfScalar(u8, &buffer, 0) orelse buffer.len; + const n = std.mem.findScalar(u8, &buffer, 0) orelse buffer.len; if (n > out_buffer.len) return error.NameTooLong; @memcpy(out_buffer[0..n], buffer[0..n]); return n; @@ -2803,7 +2804,7 @@ fn dirRealPathFile( while (true) { if (c.realpath(sub_path_posix, out_buffer.ptr)) |redundant_pointer| { assert(redundant_pointer == out_buffer.ptr); - return std.mem.indexOfScalar(u8, out_buffer, 0) orelse out_buffer.len; + return std.mem.findScalar(u8, out_buffer, 0) orelse out_buffer.len; } const err: c.E = @fromBackingInt(@intCast(c._errno().*)); switch (err) { @@ -3791,7 +3792,7 @@ fn fileRealPath(userdata: ?*anyopaque, file: File, out_buffer: []u8) File.RealPa else => |err| return unexpectedErrno(err), } } - const n = std.mem.indexOfScalar(u8, &buffer, 0) orelse buffer.len; + const n = std.mem.findScalar(u8, &buffer, 0) orelse buffer.len; if (n > out_buffer.len) return error.NameTooLong; @memcpy(out_buffer[0..n], buffer[0..n]); return n; @@ -3897,7 +3898,7 @@ fn fileMemoryMapDestroy(userdata: ?*anyopaque, mm: *File.MemoryMap) void { if (memory.len == 0) return; switch (c.errno(c.munmap(memory.ptr, memory.len))) { .SUCCESS => {}, - else => |err| if (builtin.mode == .Debug) + else => |err| if (builtin.mode == .debug) std.log.err("failed to unmap {d} bytes at {*}: {t}", .{ memory.len, memory.ptr, err }), } mm.* = undefined; @@ -4714,7 +4715,7 @@ fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.Cancelable!void { return ev.yield(.{ .after = ev.timeFromTimeout(timeout) }); }; var waiter: SleepWaiter = .{ - .cancelable = .{ .queue = queue, .cancel = &Futex.Waiter.canceled }, + .cancelable = .{ .queue = queue, .cancel = &SleepWaiter.canceled }, .timer = timer, }; timer.as_object().set_context(&waiter); @@ -4911,10 +4912,10 @@ fn netWriteFileUnavailable( return error.Unimplemented; } -fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void { +fn netClose(userdata: ?*anyopaque, sockets: []const net.Socket) void { const ev: *Evented = @ptrCast(@alignCast(userdata)); _ = ev; - for (handles) |handle| closeFd(handle); + for (sockets) |socket| closeFd(socket.handle); } fn netShutdownUnavailable( diff --git a/lib/std/Io/Kqueue.zig b/lib/std/Io/Kqueue.zig index d34d4132a1a37646303191831a3c050cd579c500..ea8cbb6cad024be2fe987cc3296bd3e70006aab9 100644 --- a/lib/std/Io/Kqueue.zig +++ b/lib/std/Io/Kqueue.zig @@ -1280,10 +1280,10 @@ fn netWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8, @panic("TODO"); } -fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void { +fn netClose(userdata: ?*anyopaque, sockets: []const net.Socket) void { const k: *Kqueue = @ptrCast(@alignCast(userdata)); _ = k; - _ = handles; + _ = sockets; @panic("TODO"); } @@ -1422,6 +1422,7 @@ fn posixBind( .INTR => continue, .CANCELED => return error.Canceled, + .ACCES => return error.AccessDenied, .ADDRINUSE => return error.AddressInUse, .BADF => |err| return errnoBug(err), // File descriptor used after closed. .INVAL => |err| return errnoBug(err), // invalid parameters diff --git a/lib/std/Io/Reader.zig b/lib/std/Io/Reader.zig index 68cae96c836d7cab147c327afd06588c118d784c..966af7879c2488a2b8447f6398aa036a79aba263 100644 --- a/lib/std/Io/Reader.zig +++ b/lib/std/Io/Reader.zig @@ -718,7 +718,7 @@ pub inline fn readSliceEndian( endian: std.builtin.Endian, ) Error!void { try readSliceAll(r, @ptrCast(buffer)); - if (native_endian != endian) for (buffer) |*elem| std.mem.byteSwapAllFields(Elem, elem); + if (native_endian != endian) std.mem.byteSwapAllElements(Elem, buffer); } pub const ReadAllocError = Error || Allocator.Error; @@ -734,8 +734,7 @@ pub inline fn readSliceEndianAlloc( ) ReadAllocError![]Elem { const dest = try allocator.alloc(Elem, len); errdefer allocator.free(dest); - try readSliceAll(r, @ptrCast(dest)); - if (native_endian != endian) for (dest) |*elem| std.mem.byteSwapAllFields(Elem, elem); + try r.readSliceEndian(Elem, dest, endian); return dest; } @@ -1227,8 +1226,7 @@ pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endia .auto => @compileError("ill-defined memory layout"), .@"extern" => { var res: T = undefined; - try r.readSliceAll(std.mem.asBytes(&res)); - if (native_endian != endian) std.mem.byteSwapAllFields(T, &res); + try r.readSliceEndian(T, (&res)[0..1], endian); return res; }, .@"packed" => { diff --git a/lib/std/Io/RwLock.zig b/lib/std/Io/RwLock.zig index 7a445033db6b50da7ab31ee8a6cb7b7f6c3ed438..de9bf86f366314f64ed45877c675dd2cbd9eee4a 100644 --- a/lib/std/Io/RwLock.zig +++ b/lib/std/Io/RwLock.zig @@ -284,8 +284,6 @@ test "concurrent access" { } test "lock canceling" { - if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347 - const io = testing.io; var rl: Io.RwLock = .init; diff --git a/lib/std/Io/Semaphore.zig b/lib/std/Io/Semaphore.zig index 1f486750487ed8cd66c39306998d7434e8cd4df7..8f2137b80220fa26c19173d8a3db1098eb24f570 100644 --- a/lib/std/Io/Semaphore.zig +++ b/lib/std/Io/Semaphore.zig @@ -4,8 +4,6 @@ //! This API supports static initialization and does not require deinitialization. const Semaphore = @This(); -const builtin = @import("builtin"); - const std = @import("../std.zig"); const Io = std.Io; const testing = std.testing; diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index b02453c1e34cacd3f5b8417156a63022d11f8a89..555ff219d308cba7647a791bf770b28b6895c6d1 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -4,7 +4,7 @@ const builtin = @import("builtin"); const native_os = builtin.os.tag; const is_windows = native_os == .windows; const is_darwin = native_os.isDarwin(); -const is_debug = builtin.mode == .Debug; +const is_debug = builtin.mode == .debug; const std = @import("../std.zig"); const Io = std.Io; @@ -440,12 +440,12 @@ pub const UseFchmodat2 = if (have_fchmodat2 and !have_fchmodat_flags) enum { pub const apc_align = @max(default_fn_align, 2); const default_fn_align = switch (builtin.mode) { - .Debug, .ReleaseSafe, .ReleaseFast => switch (builtin.cpu.arch) { + .debug, .safe, .fast => switch (builtin.cpu.arch) { else => |arch| @compileError("Unsupported architecture: " ++ @tagName(arch)), .arm, .thumb => 4, .aarch64, .x86, .x86_64 => 16, }, - .ReleaseSmall => 1, + .small => 1, }; const Runnable = struct { @@ -829,6 +829,7 @@ const Thread = struct { /// Always released when `Status.cancelation` is set to `.parked`. futex_waiter: if (use_parking_futex) ?*parking_futex.Waiter else ?noreturn, unpark_flag: UnparkFlag, + park_tid: if (ParkTid == std.Thread.Id) void else ParkTid, csprng: Csprng, @@ -1220,7 +1221,7 @@ const Thread = struct { parking_futex.removeCanceledWaiter(futex_waiter); } if (need_unpark_flag) setUnparkFlag(&thread.unpark_flag); - unpark(&.{thread.id}, null); + unpark(&.{if (ParkTid == std.Thread.Id) thread.id else thread.park_tid}, null); return false; }, @@ -1749,6 +1750,7 @@ fn worker(t: *Threaded) void { .cancel_protection = .unblocked, .futex_waiter = undefined, .unpark_flag = unpark_flag_init, + .park_tid = if (ParkTid == std.Thread.Id) {} else getParkTid(), .csprng = .uninitialized, }; Thread.current = &thread; @@ -3858,7 +3860,26 @@ fn fileLength(userdata: ?*anyopaque, file: File) File.LengthError!u64 { } } } else if (is_windows) { - // TODO call NtQueryInformationFile and ask for only the size instead of "all" + var io_status_block: windows.IO_STATUS_BLOCK = undefined; + var info: windows.FILE.STANDARD_INFORMATION = undefined; + const syscall: Syscall = try .start(); + while (true) switch (windows.ntdll.NtQueryInformationFile( + file.handle, + &io_status_block, + &info, + @sizeOf(windows.FILE.STANDARD_INFORMATION), + .Standard, + )) { + .SUCCESS => break syscall.finish(), + .INVALID_PARAMETER => |err| return syscall.ntstatusBug(err), + .ACCESS_DENIED => return syscall.fail(error.AccessDenied), + .CANCELLED => { + try syscall.checkCancel(); + continue; + }, + else => |s| return syscall.unexpectedNtstatus(s), + }; + return @as(u64, @bitCast(info.EndOfFile)); } const stat = try fileStat(t, file); @@ -4382,7 +4403,7 @@ fn dirCreateFilePosix( } }; - fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK")); + fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK")); const syscall: Syscall = try .start(); while (true) { @@ -4978,7 +4999,7 @@ fn dirOpenFilePosix( } }; - fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK")); + fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK")); const syscall: Syscall = try .start(); while (true) { @@ -5053,7 +5074,7 @@ pub fn dirOpenFileWtf16( .VALID_FLAGS, .OPEN, .{ - .IO = if (flags.follow_symlinks) .SYNCHRONOUS_NONALERT else .ASYNCHRONOUS, + .IO = .SYNCHRONOUS_NONALERT, .NON_DIRECTORY_FILE = !allow_directory, .OPEN_REPARSE_POINT = !flags.follow_symlinks, }, @@ -6817,7 +6838,7 @@ fn dirRealPathFilePosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, o if (std.c.realpath(sub_path_posix, out_buffer.ptr)) |redundant_pointer| { syscall.finish(); assert(redundant_pointer == out_buffer.ptr); - return std.mem.indexOfScalar(u8, out_buffer, 0) orelse out_buffer.len; + return std.mem.findScalar(u8, out_buffer, 0) orelse out_buffer.len; } const err: posix.E = @fromBackingInt(@intCast(std.c._errno().*)); if (err == .INTR) { @@ -6961,7 +6982,7 @@ fn realPathPosix(fd: posix.fd_t, out_buffer: []u8) File.RealPathError!usize { }, } } - const n = std.mem.indexOfScalar(u8, &sufficient_buffer, 0) orelse sufficient_buffer.len; + const n = std.mem.findScalar(u8, &sufficient_buffer, 0) orelse sufficient_buffer.len; if (n > out_buffer.len) return error.NameTooLong; @memcpy(out_buffer[0..n], sufficient_buffer[0..n]); return n; @@ -7119,9 +7140,10 @@ fn dirDeleteFileWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir. if (builtin.link_libc) return dirDeleteFilePosix(userdata, dir, sub_path); const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; + const wasi = std.os.wasi; const syscall: Syscall = try .start(); while (true) { - const res = std.os.wasi.path_unlink_file(dir.handle, sub_path.ptr, sub_path.len); + const res = wasi.path_unlink_file(dir.handle, sub_path.ptr, sub_path.len); switch (res) { .SUCCESS => { syscall.finish(); @@ -7131,11 +7153,35 @@ fn dirDeleteFileWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir. try syscall.checkCancel(); continue; }, + .ACCES, .PERM => |e| { + const original_error: Dir.DeleteFileError = switch (e) { + .ACCES => error.AccessDenied, + .PERM => error.PermissionDenied, + else => unreachable, + }; + var stat: wasi.filestat_t = undefined; + while (true) { + try syscall.checkCancel(); + switch (wasi.path_filestat_get(dir.handle, .{}, sub_path.ptr, sub_path.len, &stat)) { + .SUCCESS => { + syscall.finish(); + break; + }, + .INTR => continue, + else => { + syscall.finish(); + return original_error; + }, + } + } + if (stat.filetype == .DIRECTORY) + return error.IsDir + else + return original_error; + }, else => |e| { syscall.finish(); switch (e) { - .ACCES => return error.AccessDenied, - .PERM => return error.PermissionDenied, .BUSY => return error.FileBusy, .FAULT => |err| return errnoBug(err), .IO => return error.FileSystem, @@ -8111,7 +8157,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink .{ .DIRECTORY_FILE = false, .NON_DIRECTORY_FILE = false, - .IO = .ASYNCHRONOUS, + .IO = .SYNCHRONOUS_NONALERT, .OPEN_REPARSE_POINT = true, }, null, @@ -8177,7 +8223,7 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(windows.REPARSE_DATA_BUFFER)) = undefined; switch ((try deviceIoControl(&.{ - .file = .{ .handle = result_handle, .flags = .{ .nonblocking = true } }, + .file = .{ .handle = result_handle, .flags = .{ .nonblocking = false } }, .code = .GET_REPARSE_POINT, .out = &reparse_buf, })).u.Status) { @@ -8955,7 +9001,7 @@ fn isCygwinPty(file: File) Io.Cancelable!bool { // The name we get from NtQueryInformationFile will be prefixed with a '\', e.g. \msys-1888ae32e00d56aa-pty0-to-master return (std.mem.startsWith(u16, name_wide, &[_]u16{ '\\', 'm', 's', 'y', 's', '-' }) or std.mem.startsWith(u16, name_wide, &[_]u16{ '\\', 'c', 'y', 'g', 'w', 'i', 'n', '-' })) and - std.mem.indexOf(u16, name_wide, &[_]u16{ '-', 'p', 't', 'y' }) != null; + std.mem.find(u16, name_wide, &[_]u16{ '-', 'p', 't', 'y' }) != null; } fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthError!void { @@ -11184,7 +11230,10 @@ fn fileWriteFileStreaming( var off: std.os.linux.off_t = undefined; const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) { .positional => o: { - const size = file_reader.getSize() catch return 0; + const size = file_reader.getSize() catch |err| switch (err) { + error.Canceled => |e| return e, + else => break :sf, + }; off = std.math.cast(std.os.linux.off_t, file_reader.pos) orelse return error.ReadFailed; break :o .{ &off, @min(@backingInt(limit), size - file_reader.pos, max_count) }; }, @@ -11533,7 +11582,10 @@ fn fileWriteFilePositional( if (file_reader.pos != 0) break :fcf; if (offset != 0) break :fcf; if (limit != .unlimited) break :fcf; - const size = file_reader.getSize() catch break :fcf; + const size = file_reader.getSize() catch |err| switch (err) { + error.Canceled => |e| return e, + else => break :fcf, + }; if (header.len != 0 or reader_buffered.len != 0) { const n = try fileWritePositional(t, file, header, &.{limit.slice(reader_buffered)}, 1, offset); file_reader.interface.toss(n -| header.len); @@ -11725,7 +11777,6 @@ fn nowWasi(clock: Io.Clock) Io.Timestamp { fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.Cancelable!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); - if (timeout == .none) return; if (use_parking_sleep) return parking_sleep.sleep(timeout); if (native_os == .wasi) return sleepWasi(t, timeout); if (@TypeOf(posix.system.clock_nanosleep) != void) return sleepPosix(timeout); @@ -12042,6 +12093,7 @@ fn posixBind( else => |e| { syscall.finish(); switch (e) { + .ACCES => return error.AccessDenied, .ADDRINUSE => return error.AddressInUse, .BADF => |err| return errnoBug(err), // File descriptor used after closed. .INVAL => |err| return errnoBug(err), // invalid parameters @@ -12124,6 +12176,7 @@ fn posixConnectUnix( .NOTDIR => return error.NotDir, .ROFS => return error.ReadOnlyFileSystem, .PERM => return error.PermissionDenied, + .CONNREFUSED => return error.ConnectionRefused, .BADF => |err| return errnoBug(err), // File descriptor used after closed. .CONNABORTED => |err| return errnoBug(err), @@ -13362,13 +13415,13 @@ fn addBuf(v: []posix.iovec_const, i: *iovlen_t, bytes: []const u8) void { i.* += 1; } -fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void { +fn netClose(userdata: ?*anyopaque, sockets: []const net.Socket) void { if (!have_networking) unreachable; const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; - for (handles) |handle| switch (native_os) { - .windows => windows.CloseHandle(handle), - else => closeFd(handle), + for (sockets) |socket| switch (native_os) { + .windows => windows.CloseHandle(socket.handle), + else => closeFd(socket.handle), }; } @@ -13870,9 +13923,14 @@ fn netLookupFallible( var port_buffer: [8]u8 = undefined; const port_c = std.fmt.bufPrintSentinel(&port_buffer, "{d}", .{options.port}, 0) catch unreachable; + const family: i32 = if (options.family) |f| switch (f) { + .ip4 => posix.AF.INET, + .ip6 => posix.AF.INET6, + } else posix.AF.UNSPEC; + const hints: posix.addrinfo = .{ .flags = .{ .CANONNAME = options.canonical_name_buffer != null, .NUMERICSERV = true }, - .family = posix.AF.UNSPEC, + .family = family, .socktype = posix.SOCK.STREAM, .protocol = posix.IPPROTO.TCP, .canonname = null, @@ -15302,8 +15360,7 @@ fn childKillWindows(t: *Threaded, child: *process.Child, exit_code: windows.UINT _ = windows.ntdll.RtlReportSilentProcessExit(handle, @fromBackingInt(@intCast(exit_code))); switch (windows.ntdll.NtTerminateProcess(handle, @fromBackingInt(@intCast(exit_code)))) { .SUCCESS, .PROCESS_IS_TERMINATING => { - const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); - _ = windows.ntdll.NtWaitForSingleObject(handle, .FALSE, &infinite_timeout); + _ = windows.ntdll.NtWaitForSingleObject(handle, .FALSE, null); childCleanupWindows(child); }, .ACCESS_DENIED => { @@ -15326,8 +15383,7 @@ fn childWaitWindows(child: *process.Child) process.Child.WaitError!process.Child const handle = child.id.?; const alertable_syscall: AlertableSyscall = try .start(); - const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); - while (true) switch (windows.ntdll.NtWaitForSingleObject(handle, .TRUE, &infinite_timeout)) { + while (true) switch (windows.ntdll.NtWaitForSingleObject(handle, .TRUE, null)) { windows.NTSTATUS.WAIT_0 => break alertable_syscall.finish(), .USER_APC, .ALERTED, .TIMEOUT => { try alertable_syscall.checkCancel(); @@ -16272,7 +16328,7 @@ fn windowsCreateProcessPathExt( const is_bat_or_cmd = bat_or_cmd: { const app_name = app_buf.items[0..app_name_len]; - const ext_start = std.mem.lastIndexOfScalar(u16, app_name, '.') orelse break :bat_or_cmd false; + const ext_start = std.mem.findScalarLast(u16, app_name, '.') orelse break :bat_or_cmd false; const ext = app_name[ext_start..]; const ext_enum = windowsCreateProcessSupportsExtension(ext) orelse break :bat_or_cmd false; switch (ext_enum) { @@ -16308,7 +16364,7 @@ fn windowsCreateProcessPathExt( // it's treated as an unrecoverable error. Otherwise, it'll be // skipped as normal. const app_name = app_buf.items[0..app_name_len]; - const ext_start = std.mem.lastIndexOfScalar(u16, app_name, '.') orelse break :unappended err; + const ext_start = std.mem.findScalarLast(u16, app_name, '.') orelse break :unappended err; const ext = app_name[ext_start..]; if (windows.eqlIgnoreCaseWtf16(ext, std.unicode.utf8ToUtf16LeStringLiteral(".EXE"))) { return error.UnrecoverableInvalidExe; @@ -17387,6 +17443,7 @@ const use_parking_futex = switch (native_os) { .windows => true, // RtlWaitOnAddress is a userland implementation anyway .netbsd => true, // NetBSD has `futex(2)`, but it's historically been quite buggy. TODO: evaluate whether it's okay to use now. .illumos => true, // Illumos has no futex mechanism + .haiku => true, // Haiku has no futex mechanism else => false, }; const use_parking_sleep = switch (native_os) { @@ -17432,7 +17489,7 @@ const parking_futex = struct { const Waiter = struct { node: std.DoublyLinkedList.Node, address: usize, - tid: std.Thread.Id, + tid: ParkTid, /// `thread_status.cancelation` is `.parked` while the thread is waiting. The single thread /// which atomically updates it (to `.none` or `.canceling`) is responsible for: /// @@ -17473,7 +17530,7 @@ const parking_futex = struct { // Put the threadlocal access outside of the critical section. const opt_thread = Thread.current; - const self_tid = if (opt_thread) |thread| thread.id else std.Thread.getCurrentId(); + const self_tid = getParkTid(); var waiter: Waiter = .{ .node = undefined, // populated by list append @@ -17721,7 +17778,12 @@ const parking_sleep = struct { }, } } + // Uncancelable sleep; we expect not to be manually unparked. + + // On systems where parking the thread requires a one-time setup operation (e.g. creating a + // semaphore), we need to ensure that setup is done before we call `park`. + _ = getParkTid(); var dummy_flag: UnparkFlag = unpark_flag_init; if (park(timeout, null, if (need_unpark_flag) &dummy_flag)) { unreachable; // unexpected unpark @@ -17760,7 +17822,7 @@ const ParkingMutex = struct { /// Never modified once the `Waiter` is in the linked list. next: ?*Waiter, /// Never modified once the `Waiter` is in the linked list. - tid: std.Thread.Id, + tid: ParkTid, }; fn lock(m: *ParkingMutex) void { state: switch (State.unlocked) { // assume 'unlocked' to optimize for uncontended case @@ -17776,7 +17838,7 @@ const ParkingMutex = struct { .locked_once, _ => |last_state| { const old_waiter = last_state.waiter(); - const self_tid = if (Thread.current) |t| t.id else std.Thread.getCurrentId(); + const self_tid = getParkTid(); var waiter: Waiter = .{ .next = old_waiter, .unpark_flag = unpark_flag_init, @@ -17904,9 +17966,36 @@ fn setUnparkFlag(f: *UnparkFlag) void { /// but it seems that someone at Microsoft forgot how big their TIDs are supposed to be. const UnparkTid = switch (native_os) { .windows => usize, + else => ParkTid, +}; + +const ParkTid = switch (native_os) { + .haiku => std.c.sem_id, else => std.Thread.Id, }; +threadlocal var park_sem: std.c.sem_id = -1; + +fn getParkTid() ParkTid { + switch (native_os) { + .haiku => { + if (park_sem == -1) { + park_sem = std.c._kern_create_sem(0, null); + if (park_sem < 0) @panic("_kern_create_sem failed"); + _ = std.c.on_exit_thread(destroyParkSem, null); + } + return park_sem; + }, + else => { + return if (Thread.current) |thread| thread.id else std.Thread.getCurrentId(); + }, + } +} + +fn destroyParkSem(_: ?*anyopaque) callconv(.c) void { + _ = std.c._kern_delete_sem(park_sem); +} + fn park( timeout: Io.Timeout, /// This value has no semantic effect, but may allow the OS to optimize the operation. @@ -17972,6 +18061,27 @@ fn park( } }, .illumos => @panic("TODO: illumos lwp_park"), + .haiku => { + const timeout_flags: u32, const timeout_us = switch (timeout) { + .none => .{ 0, 0 }, + .deadline => |deadline| .{ + if (deadline.clock == .real) std.c.B_ABSOLUTE_TIMEOUT | std.c.B_TIMEOUT_REAL_TIME_BASE else std.c.B_ABSOLUTE_TIMEOUT, + deadline.raw.toMicroseconds(), + }, + .duration => |duration| .{ + if (duration.clock == .real) std.c.B_ABSOLUTE_TIMEOUT | std.c.B_TIMEOUT_REAL_TIME_BASE else std.c.B_ABSOLUTE_TIMEOUT, + nowPosix(duration.clock).addDuration(duration.raw).toMicroseconds(), + }, + }; + while (true) { + switch (std.c._kern_acquire_sem_etc(park_sem, 1, timeout_flags, timeout_us)) { + 0 => return, + std.c.E.B_TIMED_OUT => return error.Timeout, + std.c.E.B_INTERRUPTED => {}, + else => unreachable, + } + } + }, else => comptime unreachable, } } @@ -18014,6 +18124,14 @@ fn unpark(tids: []const UnparkTid, addr_hint: ?*const anyopaque) void { } }, .illumos => @panic("TODO: illumos lwp_unpark"), + .haiku => { + for (tids) |tid| { + switch (std.c._kern_release_sem_etc(tid, 1, 0)) { + 0 => {}, + else => recoverableOsBugDetected(), + } + } + }, else => comptime unreachable, } } @@ -18171,7 +18289,7 @@ fn fileMemoryMapCreate( error.Unseekable, error.Canceled, error.AccessDenied => |e| return e, error.OperationUnsupported => {}, else => { - if (builtin.mode == .Debug) + if (builtin.mode == .debug) std.log.warn("memory mapping failed with {t}, falling back to file operations", .{err}); }, } @@ -18278,7 +18396,7 @@ fn createFileMap( .INVALID_VIEW_SIZE => |status| return windows.statusBug(status), else => |status| return windows.unexpectedStatus(status), } - if (builtin.mode == .Debug) { + if (builtin.mode == .debug) { const page_size = std.heap.pageSize(); const alignment: Alignment = .fromByteUnits(page_size); assert(contents_len == alignment.forward(len)); @@ -18369,7 +18487,7 @@ fn fileMemoryMapDestroy(userdata: ?*anyopaque, mm: *File.MemoryMap) void { switch (posix.errno(posix.system.munmap(memory.ptr, memory.len))) { .SUCCESS => {}, else => |e| { - if (builtin.mode == .Debug) + if (builtin.mode == .debug) std.log.err("failed to unmap {d} bytes at {*}: {t}", .{ memory.len, memory.ptr, e }); }, } @@ -18969,7 +19087,7 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows .{ .DIRECTORY_FILE = options.filter == .dir_only, .NON_DIRECTORY_FILE = options.filter == .non_directory_only, - .IO = if (options.follow_symlinks) .SYNCHRONOUS_NONALERT else .ASYNCHRONOUS, + .IO = .SYNCHRONOUS_NONALERT, .OPEN_REPARSE_POINT = !options.follow_symlinks, }, null, diff --git a/lib/std/Io/Threaded/test.zig b/lib/std/Io/Threaded/test.zig index bb49dbc1b5fbc2e502c0368756d838c39a2e0258..392323de9b15c8674b4af0ea7aea21a5f49d6faf 100644 --- a/lib/std/Io/Threaded/test.zig +++ b/lib/std/Io/Threaded/test.zig @@ -149,8 +149,6 @@ test "async with array return type" { } test "cancel blocked read from pipe" { - if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347 - const global = struct { fn readFromPipe(io: Io, pipe: Io.File) !void { var buf: [1]u8 = undefined; diff --git a/lib/std/Io/Uring.zig b/lib/std/Io/Uring.zig index c2c7e57edff411b2c469519858391f3d1eb0724d..86f5bee4bf69329a21257fe6be0946fb0eb28153 100644 --- a/lib/std/Io/Uring.zig +++ b/lib/std/Io/Uring.zig @@ -1135,8 +1135,9 @@ fn mainIdleEntry() callconv(.naked) void { fn mainIdle( ev: *Evented, - message: *const SwitchMessage, + contexts: *const Io.fiber.Switch, ) callconv(.withStackAlign(.c, @max(@alignOf(Thread), @alignOf(Io.fiber.Context)))) noreturn { + const message: *const SwitchMessage = @fieldParentPtr("contexts", contexts); message.handle(ev); ev.idle(&ev.threads.allocated[0]); ev.yield(@ptrCast(&ev.main_fiber_buffer), .nothing); @@ -1414,8 +1415,9 @@ const AsyncClosure = struct { fn call( closure: *AsyncClosure, - message: *const SwitchMessage, + contexts: *const Io.fiber.Switch, ) callconv(.withStackAlign(.c, @alignOf(AsyncClosure))) noreturn { + const message: *const SwitchMessage = @fieldParentPtr("contexts", contexts); const ev = closure.evented; const fiber = closure.fiber; message.handle(ev); @@ -1779,8 +1781,9 @@ const Group = struct { fn call( closure: *Group.AsyncClosure, - message: *const SwitchMessage, + contexts: *const Io.fiber.Switch, ) callconv(.withStackAlign(.c, @alignOf(Group.AsyncClosure))) noreturn { + const message: *const SwitchMessage = @fieldParentPtr("contexts", contexts); const ev = closure.evented; const fiber = closure.fiber; message.handle(ev); @@ -3558,7 +3561,7 @@ fn dirHardLink( old_sub_path_posix, new_dir.handle, new_sub_path_posix, - if (options.follow_symlinks) 0 else linux.AT.SYMLINK_NOFOLLOW, + if (options.follow_symlinks) linux.AT.SYMLINK_FOLLOW else 0, ); } @@ -3990,7 +3993,7 @@ fn fileHardLink( "", new_dir.handle, new_sub_path_posix, - linux.AT.EMPTY_PATH | @as(u32, if (options.follow_symlinks) 0 else linux.AT.SYMLINK_NOFOLLOW), + linux.AT.EMPTY_PATH | @as(u32, if (options.follow_symlinks) linux.AT.SYMLINK_FOLLOW else 0), ); } @@ -4050,7 +4053,7 @@ fn fileMemoryMapDestroy(userdata: ?*anyopaque, mm: *File.MemoryMap) void { if (memory.len == 0) return; switch (linux.errno(linux.munmap(memory.ptr, memory.len))) { .SUCCESS => {}, - else => |err| if (builtin.mode == .Debug) + else => |err| if (builtin.mode == .debug) std.log.err("failed to unmap {d} bytes at {*}: {t}", .{ memory.len, memory.ptr, err }), } mm.* = undefined; @@ -5186,9 +5189,9 @@ fn netWriteFileUnavailable( return error.Unimplemented; } -fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void { +fn netClose(userdata: ?*anyopaque, sockets: []const net.Socket) void { const ev: *Evented = @ptrCast(@alignCast(userdata)); - for (handles) |handle| ev.close(handle); + for (sockets) |sock| ev.close(sock.handle); } fn netShutdown( @@ -5295,6 +5298,7 @@ fn bind( switch (cancel_region.errno()) { .SUCCESS => return, .INTR, .CANCELED => {}, + .ACCES => return error.AccessDenied, .ADDRINUSE => return error.AddressInUse, .BADF => |err| return errnoBug(err), // File descriptor used after closed. .INVAL => |err| return errnoBug(err), // invalid parameters @@ -5542,6 +5546,8 @@ fn linkat( new_path: [*:0]const u8, flags: u32, ) File.HardLinkError!void { + // allowed flags: https://man7.org/linux/man-pages/man2/linkat.2.html + assert(flags & ~(@as(u32, linux.AT.SYMLINK_FOLLOW | linux.AT.EMPTY_PATH)) == 0); while (true) { const thread = try cancel_region.awaitIoUring(); thread.enqueue().* = .{ diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index ca9564edff39fe329f5114aa2a2fba41c4a6fe02..3006df007d12ce381259dde1e82bc728a02d28f4 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -874,7 +874,7 @@ pub fn splatBytes(w: *Writer, bytes: []const u8, n: usize) Error!usize { } /// Asserts the `buffer` was initialized with a capacity of at least `@sizeOf(T)` bytes. -pub inline fn writeInt(w: *Writer, comptime T: type, value: T, endian: std.builtin.Endian) Error!void { +pub inline fn writeInt(w: *Writer, comptime T: type, value: T, endian: std.lang.Endian) Error!void { var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined; std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian); return w.writeAll(&bytes); @@ -882,7 +882,7 @@ pub inline fn writeInt(w: *Writer, comptime T: type, value: T, endian: std.built /// The function is inline to avoid the dead code in case `endian` is /// comptime-known and matches host endianness. -pub inline fn writeStruct(w: *Writer, value: anytype, endian: std.builtin.Endian) Error!void { +pub inline fn writeStruct(w: *Writer, value: anytype, endian: std.lang.Endian) Error!void { switch (@typeInfo(@TypeOf(value))) { .@"struct" => |info| switch (info.layout) { .auto => @compileError("ill-defined memory layout"), @@ -907,7 +907,7 @@ pub inline fn writeSliceEndian( w: *Writer, Elem: type, slice: []const Elem, - endian: std.builtin.Endian, + endian: std.lang.Endian, ) Error!void { switch (@typeInfo(Elem)) { .@"struct" => |info| comptime assert(info.layout != .auto), @@ -2387,6 +2387,7 @@ pub fn unreachableRebase(w: *Writer, preserve: usize, capacity: usize) Error!voi pub fn fromArrayList(array_list: *ArrayList(u8)) Writer { defer array_list.* = .empty; + array_list.pointer_stability.assertUnlocked(); return .{ .vtable = &.{ .drain = fixedDrain, @@ -2402,6 +2403,7 @@ pub fn toArrayList(w: *Writer) ArrayList(u8) { const result: ArrayList(u8) = .{ .items = w.buffer[0..w.end], .capacity = w.buffer.len, + .pointer_stability = .{}, }; w.buffer = &.{}; w.end = 0; @@ -2651,6 +2653,7 @@ pub const Allocating = struct { const result: std.array_list.Aligned(u8, alignment) = .{ .items = @alignCast(w.buffer[0..w.end]), .capacity = w.buffer.len, + .pointer_stability = .{}, }; w.buffer = &.{}; w.end = 0; @@ -2742,29 +2745,26 @@ pub const Allocating = struct { fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { const a: *Allocating = @fieldParentPtr("writer", w); - const pattern = data[data.len - 1]; - const splat_len = pattern.len * splat; - const start_len = a.writer.end; assert(data.len != 0); - for (data) |bytes| { - a.ensureUnusedCapacity(bytes.len + splat_len + 1) catch return error.WriteFailed; + const count = countSplat(data, splat); + a.ensureUnusedCapacity(count + 1) catch return error.WriteFailed; + for (data[0 .. data.len - 1]) |bytes| { @memcpy(a.writer.buffer[a.writer.end..][0..bytes.len], bytes); a.writer.end += bytes.len; } - if (splat == 0) { - a.writer.end -= pattern.len; - } else switch (pattern.len) { + const pattern = data[data.len - 1]; + switch (pattern.len) { 0 => {}, 1 => { - @memset(a.writer.buffer[a.writer.end..][0 .. splat - 1], pattern[0]); - a.writer.end += splat - 1; + @memset(a.writer.buffer[a.writer.end..][0..splat], pattern[0]); + a.writer.end += splat; }, - else => for (0..splat - 1) |_| { + else => for (0..splat) |_| { @memcpy(a.writer.buffer[a.writer.end..][0..pattern.len], pattern); a.writer.end += pattern.len; }, } - return a.writer.end - start_len; + return count; } fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { @@ -2817,12 +2817,12 @@ pub const Allocating = struct { } test Allocating { - try testAllocating(.fromByteUnits(1)); - try testAllocating(.fromByteUnits(4)); - try testAllocating(.fromByteUnits(8)); - try testAllocating(.fromByteUnits(16)); - try testAllocating(.fromByteUnits(32)); - try testAllocating(.fromByteUnits(64)); + try testAllocating(.@"1"); + try testAllocating(.@"4"); + try testAllocating(.@"8"); + try testAllocating(.@"16"); + try testAllocating(.@"32"); + try testAllocating(.@"64"); } }; diff --git a/lib/std/Io/net.zig b/lib/std/Io/net.zig index a546552cb9c7bb24ced83e88fbae4946f21a7061..c778dcde66f4b773a3d3f95f698c628eacb3f5f1 100644 --- a/lib/std/Io/net.zig +++ b/lib/std/Io/net.zig @@ -198,6 +198,8 @@ pub const IpAddress = union(enum) { } pub const ListenError = error{ + /// The address is protected and the current user does not have permission to bind it. + AccessDenied, /// The address is already taken. Can occur when bound port is 0 but /// all ephemeral ports are already in use. AddressInUse, @@ -254,6 +256,8 @@ pub const IpAddress = union(enum) { } pub const BindError = error{ + /// The address is protected and the current user does not have permission to bind it. + AccessDenied, /// The address is already taken. Can occur when bound port is 0 but /// all ephemeral ports are already in use. AddressInUse, @@ -901,6 +905,7 @@ pub const UnixAddress = struct { ReadOnlyFileSystem, WouldBlock, NetworkDown, + ConnectionRefused, } || Io.Cancelable || Io.UnexpectedError; pub fn connect(ua: *const UnixAddress, io: Io) ConnectError!Stream { @@ -1076,7 +1081,7 @@ pub const Socket = struct { /// Leaves `address` in a valid state. pub fn close(s: *const Socket, io: Io) void { - io.vtable.netClose(io.userdata, (&s.handle)[0..1]); + io.vtable.netClose(io.userdata, s[0..1]); } pub fn closeMany(io: Io, sockets: []const Socket) void { @@ -1253,7 +1258,7 @@ pub const Stream = struct { } pub fn close(s: *const Stream, io: Io) void { - io.vtable.netClose(io.userdata, (&s.socket.handle)[0..1]); + io.vtable.netClose(io.userdata, (&s.socket)[0..1]); } pub fn shutdown(s: *const Stream, io: Io, how: ShutdownHow) ShutdownError!void { diff --git a/lib/std/Io/net/test.zig b/lib/std/Io/net/test.zig index 308dc1a32670e207e72511d0128b634972050e6a..12fa0a846c0b6576e0f0b593bc51290e6f086b14 100644 --- a/lib/std/Io/net/test.zig +++ b/lib/std/Io/net/test.zig @@ -356,8 +356,6 @@ test "decompress compressed DNS name" { } test "cancel accept" { - if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347 - const io = testing.io; const localhost: net.IpAddress = .{ .ip4 = .loopback(0) }; diff --git a/lib/std/Io/test.zig b/lib/std/Io/test.zig index 3d9523da7675c01e8a780e139e886231f1e04617..54d79fceec8e6adebbc4e35867bcea93aa318bf2 100644 --- a/lib/std/Io/test.zig +++ b/lib/std/Io/test.zig @@ -232,8 +232,6 @@ fn count(a: usize, b: usize, result: *usize) void { } test "Group.cancel" { - if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347 - const global = struct { fn sleep(io: Io, result: *usize) Io.Cancelable!void { defer result.* = 1; @@ -326,8 +324,6 @@ test "Group materializes error.Cancel" { } test "Group task receives cancelation unknowingly" { - if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347 - const S = struct { io: Io, err: ?Io.Cancelable!void, diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index 1c49983d54db855297db8fb2d37d6d560a8116d8..b519265a9d6f54a47e210d4672e87a22f588a29d 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -442,7 +442,15 @@ pub const Node = struct { global_progress.ipc_files[slot] = file; storageByIndex(index).setIpcIndex(.{ .slot = slot, .generation = generation }); break; - } else file.close(io); + } else { + // There was no IPC slot available, so we'll drop this node's IPC info and just close + // the fd. To avoid an old `estimated_total_items` or `completed_count` value still + // being rendered for the node, we'll zero that field out (and the user is not allowed + // to change it because they think we're doing IPC). + file.close(io); + @atomicStore(u32, &storageByIndex(index).completed_count, 0, .monotonic); + @atomicStore(u32, &storageByIndex(index).estimated_total_count, 0, .monotonic); + } } pub fn setIpcIndex(node: Node, ipc_index: Ipc.Index) void { @@ -452,7 +460,11 @@ pub const Node = struct { /// Not thread-safe. pub fn takeIpcIndex(node: Node) ?Ipc.Index { const storage = storageByIndex(node.index.unwrap() orelse return null); - assert(storage.estimated_total_count == std.math.maxInt(u32)); + switch (storage.estimated_total_count) { + std.math.maxInt(u32) => {}, // indicates that there is an IPC index in `completed_count` + 0 => return null, // `setIpcFile` failed so we don't have an IPC index for this node + else => unreachable, // not an IPC node + } @atomicStore(u32, &storage.estimated_total_count, 0, .monotonic); return @bitCast(storage.completed_count); } diff --git a/lib/std/Random/RomuTrio.zig b/lib/std/Random/RomuTrio.zig index 9f005bf2f9fac8082eb4e71355dc90c73280d2b9..7352308f0d18eb6ccbe0b506bdfd4138443c89de 100644 --- a/lib/std/Random/RomuTrio.zig +++ b/lib/std/Random/RomuTrio.zig @@ -122,7 +122,6 @@ test fill { } test "buf seeding test" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const buf0: [24]u8 = @bitCast([3]u64{ 16294208416658607535, 13964609475759908645, 4703697494102998476 }); const resulting_state = .{ .x = 16294208416658607535, .y = 13964609475759908645, .z = 4703697494102998476 }; var r = RomuTrio.init(0); diff --git a/lib/std/Random/Xoshiro256.zig b/lib/std/Random/Xoshiro256.zig index 6cb0583d982622b3f7df21b94368b03ddeb80c17..9c1ea9cfec6843cf2b9151ac08cb44aebd810936 100644 --- a/lib/std/Random/Xoshiro256.zig +++ b/lib/std/Random/Xoshiro256.zig @@ -89,8 +89,6 @@ pub fn fill(self: *Xoshiro256, buf: []u8) void { } test "sequence" { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; - var r = Xoshiro256.init(0); const seq1 = [_]u64{ diff --git a/lib/std/Random/benchmark.zig b/lib/std/Random/benchmark.zig index 1e23c933912851a7f539fd17f076b362b73a27ec..59b6c8168045f7e28963e066f54e472e77555f04 100644 --- a/lib/std/Random/benchmark.zig +++ b/lib/std/Random/benchmark.zig @@ -122,7 +122,7 @@ fn usage() void { } fn mode(comptime x: comptime_int) comptime_int { - return if (builtin.mode == .Debug) x / 64 else x; + return if (builtin.mode == .debug) x / 64 else x; } pub fn main(init: std.process.Init) !void { diff --git a/lib/std/Target.zig b/lib/std/Target.zig index e9105c4737318576719795cd67e70e6b05d293e4..6ab6f2c81b1d8de3edee4c53bd7097a3cd3ae123 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -1194,9 +1194,6 @@ pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE { }; } -/// Deprecated; use 'std.zig.Subsystem' instead. To be removed after 0.16.0 is tagged. -pub const SubSystem = std.zig.Subsystem; - pub const Cpu = struct { /// Architecture arch: Arch, @@ -1796,10 +1793,12 @@ pub const Cpu = struct { .x86_64_regcall_v4_win, .x86_64_vectorcall, .x86_64_interrupt, + .x86_64_preserve_none, => &.{.x86_64}, .x86_sysv, .x86_win, + .x86_mingw, .x86_stdcall, .x86_fastcall, .x86_thiscall, @@ -1821,6 +1820,7 @@ pub const Cpu = struct { .aarch64_aapcs_win, .aarch64_vfabi, .aarch64_vfabi_sve, + .aarch64_preserve_none, => &.{ .aarch64, .aarch64_be }, .alpha_osf, @@ -2081,6 +2081,7 @@ pub const Cpu = struct { else => generic(arch), }, .powerpc64 => switch (os.tag) { + .linux, .freebsd => &powerpc.cpu.pwr8, .openbsd => &powerpc.cpu.pwr9, else => generic(arch), }, @@ -2660,12 +2661,26 @@ pub const DynamicLinker = struct { else => return none, }}), - .loongarch64 => initFmt("/lib64/ld-linux-loongarch-{s}.so.1", .{switch (abi) { - .gnu => "lp64d", - .gnuf32 => "lp64f", - .gnusf => "lp64s", - else => return none, - }}), + .loongarch32, + .loongarch64, + => |arch| initFmt("/lib{s}/ld-linux-{s}{s}.so.1", .{ + switch (arch) { + .loongarch32 => "32", + .loongarch64 => "64", + else => unreachable, + }, + switch (arch) { + .loongarch32 => "loongarch-ilp32", + .loongarch64 => "loongarch-lp64", + else => unreachable, + }, + switch (abi) { + .gnu => "d", + .gnuf32 => "f", + .gnusf => "s", + else => return none, + }, + }), .hppa, .m68k, @@ -3069,9 +3084,13 @@ pub fn stackGrowth(target: *const Target) StackGrowth { /// Default signedness of `char` for the native C compiler for this target /// Note that char signedness is implementation-defined and many compilers provide /// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char -pub fn cCharSignedness(target: *const Target) std.builtin.Signedness { +/// Returns `null` if no C ABI is defined for this target. +pub fn cCharSignedness(target: *const Target) ?std.builtin.Signedness { + switch (target.os.tag) { + .opengl => return null, + else => {}, + } if (target.os.tag.isDarwin() or target.os.tag == .windows or target.os.tag == .uefi) return .signed; - return switch (target.cpu.arch) { .aarch64, .aarch64_be, @@ -3117,7 +3136,8 @@ pub const CType = enum { longdouble, }; -pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 { +/// Returns `null` if no C ABI is defined for this target. +pub fn cTypeByteSize(t: *const Target, c_type: CType) ?u16 { return switch (c_type) { .char, .short, @@ -3130,18 +3150,19 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 { .ulonglong, .float, .double, - => @divExact(cTypeBitSize(t, c_type), 8), + => @divExact(cTypeBitSize(t, c_type) orelse return null, 8), - .longdouble => switch (cTypeBitSize(t, c_type)) { + .longdouble => switch (cTypeBitSize(t, c_type) orelse return null) { 64 => 8, - 80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, .longdouble))), + 80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, c_type).?)), 128 => 16, else => unreachable, }, }; } -pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { +/// Returns `null` if no C ABI is defined for this target. +pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 { switch (target.os.tag) { .freestanding, .other, @@ -3462,15 +3483,17 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .longlong, .ulonglong, .longdouble => return 64, }, + .opengl => return null, + .ps3, .contiki, .managarm, - .opengl, => @panic("specify the C integer and float type sizes for this OS"), } } -pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 { +/// Returns `null` if no C ABI is defined for this target. +pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 { // Overrides for unusual alignments switch (target.cpu.arch) { .avr, @@ -3503,7 +3526,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 { // Next-power-of-two-aligned, up to a maximum. return @min( - std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8), + std.math.ceilPowerOfTwoAssert(u16, ((cTypeBitSize(target, c_type) orelse return null) + 7) / 8), @as(u16, switch (target.cpu.arch) { .msp430, .x86_16, @@ -3578,120 +3601,6 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 { ); } -pub fn cTypePreferredAlignment(target: *const Target, c_type: CType) u16 { - // Overrides for unusual alignments - switch (target.cpu.arch) { - .arc, .arceb => switch (c_type) { - .longdouble => return 4, - else => {}, - }, - .avr, - .ez80, - => return 1, - .x86 => switch (target.os.tag) { - .windows, .uefi => switch (c_type) { - .longdouble => switch (target.abi) { - .gnu => return 4, - else => return 8, - }, - else => {}, - }, - else => switch (c_type) { - .longdouble => return 4, - else => {}, - }, - }, - .m68k => switch (c_type) { - .int, .uint, .long, .ulong => return 2, - else => {}, - }, - .wasm32, .wasm64 => switch (target.os.tag) { - .emscripten => switch (c_type) { - .longdouble => return 8, - else => {}, - }, - else => {}, - }, - else => {}, - } - - // Next-power-of-two-aligned, up to a maximum. - return @min( - std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8), - @as(u16, switch (target.cpu.arch) { - .x86_16, - .msp430, - => 2, - - .arc, - .arceb, - .csky, - .kalimba, - .microblaze, - .microblazeel, - .or1k, - .propeller, - .sh, - .sheb, - .xcore, - .xtensa, - .xtensaeb, - => 4, - - .amdgcn, - .arm, - .armeb, - .bpfeb, - .bpfel, - .hexagon, - .hppa, - .lanai, - .m68k, - .m88k, - .mips, - .mipsel, - .nvptx, - .nvptx64, - .s390x, - .sparc, - .thumb, - .thumbeb, - .x86, - => 8, - - .aarch64, - .aarch64_be, - .alpha, - .hppa64, - .kvx, - .loongarch32, - .loongarch64, - .mips64, - .mips64el, - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - .riscv32, - .riscv32be, - .riscv64, - .riscv64be, - .sparc64, - .spirv32, - .spirv64, - .ve, - .wasm32, - .wasm64, - .x86_64, - => 16, - - .avr, - .ez80, - => unreachable, // Handled above. - }), - ); -} - pub fn cMaxIntAlignment(target: *const Target) u16 { return switch (target.cpu.arch) { .avr, @@ -3715,6 +3624,11 @@ pub fn cMaxIntAlignment(target: *const Target) u16 { .xcore, => 4, + .x86 => switch (target.os.tag) { + else => 4, + .uefi, .windows => 8, + }, + .arm, .armeb, .hexagon, @@ -3733,7 +3647,6 @@ pub fn cMaxIntAlignment(target: *const Target) u16 { .sparc, .thumb, .thumbeb, - .x86, .xtensa, .xtensaeb, => 8, @@ -3769,18 +3682,14 @@ pub fn cMaxIntAlignment(target: *const Target) u16 { pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention { return switch (target.cpu.arch) { .x86_64 => switch (target.os.tag) { - .windows, - .uefi, - => .{ .x86_64_win = .{} }, + .windows, .uefi => .{ .x86_64_win = .{} }, else => switch (target.abi) { .gnux32, .muslx32, .x32 => .{ .x86_64_x32 = .{} }, else => .{ .x86_64_sysv = .{} }, }, }, .x86 => switch (target.os.tag) { - .windows, - .uefi, - => .{ .x86_win = .{} }, + .windows, .uefi => if (target.isMinGW()) .{ .x86_mingw = .{} } else .{ .x86_win = .{} }, else => .{ .x86_sysv = .{} }, }, .x86_16 => .{ .x86_16_cdecl = .{} }, diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 6eb76719a55d2787d04f124e58fa8829cbc7e8e9..0cc439d07da7d8a6c0de39a65bf83800ea9b6992 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -639,8 +639,7 @@ const WindowsThreadImpl = struct { } fn join(self: Impl) void { - const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); - switch (windows.ntdll.NtWaitForSingleObject(self.thread.thread_handle, .FALSE, &infinite_timeout)) { + switch (windows.ntdll.NtWaitForSingleObject(self.thread.thread_handle, .FALSE, null)) { windows.NTSTATUS.WAIT_0 => {}, else => |status| windows.unexpectedStatus(status) catch unreachable, } @@ -720,10 +719,9 @@ const PosixThreadImpl = struct { }, .haiku => { var system_info: std.c.system_info = undefined; - const rc = std.c.get_system_info(&system_info); // always returns B_OK - return switch (posix.errno(rc)) { - .SUCCESS => @as(usize, @intCast(system_info.cpu_count)), - else => |err| posix.unexpectedErrno(err), + return switch (std.c.get_system_info(&system_info)) { + 0 => @as(usize, @intCast(system_info.cpu_count)), + else => error.Unexpected, }; }, else => { @@ -1146,6 +1144,13 @@ const LinuxThreadImpl = struct { parent_tid: i32 = undefined, mapped: []align(std.heap.page_size_min) u8, + // On SPARC, the kernel needs to be able to restore the current register window from the + // stack when returning from a syscall. That presents a bit of a problem in `freeAndExit` + // since we're deallocating the stack! The good news is that, since we do not care about + // the contents of the incoming and local registers at that point, we can just tell the + // kernel that our stack is this undefined global buffer. + var sparc_exit_stack: [192]u8 align(16) = undefined; + /// Calls `munmap(mapped.ptr, mapped.len)` then `exit(1)` without touching the stack (which lives in `mapped.ptr`). /// Ported over from musl libc's pthread detached implementation: /// https://github.com/ifduyue/musl/search?q=__unmapself @@ -1365,51 +1370,39 @@ const LinuxThreadImpl = struct { [len] "{r5}" (self.mapped.len), ), .sparc => asm volatile ( - \\ # See sparc64 comments below. - \\ 1: - \\ cmp %%fp, 0 - \\ beq 2f - \\ nop - \\ ba 1b - \\ restore - \\ 2: - \\ mov %%g1, %%o0 // ptr - \\ mov %%g2, %%o1 // len - \\ mov 73, %%g1 // SYS_munmap - \\ t 0x3 // ST_FLUSH_WINDOWS - \\ t 0x10 - \\ mov 1, %%g1 // SYS_exit - \\ mov 0, %%o0 - \\ t 0x10 + \\ // See sparc64 comments below. + \\ t 0x3 // ST_FLUSH_WINDOWS + \\ mov %%g3, %%sp + \\ mov %%g1, %%o0 + \\ mov %%g2, %%o1 + \\ mov 73, %%g1 // SYS_munmap + \\ t 0x10 + \\ mov 1, %%g1 // SYS_exit + \\ mov 0, %%o0 + \\ t 0x10 : : [ptr] "{g1}" (@intFromPtr(self.mapped.ptr)), [len] "{g2}" (self.mapped.len), + [stack] "{g3}" (&sparc_exit_stack), : .{ .memory = true }), .sparc64 => asm volatile ( - \\ # SPARCs really don't like it when active stack frames - \\ # is unmapped (it will result in a segfault), so we - \\ # force-deactivate it by running `restore` until - \\ # all frames are cleared. - \\ 1: - \\ cmp %%fp, 0 - \\ beq 2f - \\ nop - \\ ba 1b - \\ restore - \\ 2: - \\ mov %%g1, %%o0 // ptr - \\ mov %%g2, %%o1 // len - \\ mov 73, %%g1 // SYS_munmap - \\ # Flush register window contents to prevent background - \\ # memory access before unmapping the stack. - \\ flushw - \\ t 0x6d - \\ mov 1, %%g1 // SYS_exit - \\ mov 0, %%o0 - \\ t 0x6d + \\ // Ensure that the kernel only has to flush the current register window. + \\ flushw + \\ // Set up a fake stack for the syscall to restore l/i registers from. Local + \\ // and incoming registers must be treated as effectively garbage past this + \\ // instruction! + \\ sub %%g3, 2047, %%sp + \\ mov %%g1, %%o0 + \\ mov %%g2, %%o1 + \\ mov 73, %%g1 // SYS_munmap + \\ t 0x6d + \\ mov 1, %%g1 // SYS_exit + \\ mov 0, %%o0 + \\ t 0x6d : : [ptr] "{g1}" (@intFromPtr(self.mapped.ptr)), [len] "{g2}" (self.mapped.len), + [stack] "{g3}" (&sparc_exit_stack), : .{ .memory = true }), .loongarch32, .loongarch64 => asm volatile ( \\ ori $a7, $zero, 215 # SYS_munmap diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig index 1dbb8cc043a7fc1354197a89a080af87e2789a48..6c4b1b2346e4cb955cecde24302bb4b15df4df18 100644 --- a/lib/std/Uri.zig +++ b/lib/std/Uri.zig @@ -221,16 +221,16 @@ pub fn parseAfterScheme(scheme: []const u8, text: []const u8) ParseError!Uri { } if (authority.len > start_of_host and authority[start_of_host] == '[') { // IPv6 - end_of_host = std.mem.lastIndexOf(u8, authority, "]") orelse return error.InvalidFormat; + end_of_host = std.mem.findLast(u8, authority, "]") orelse return error.InvalidFormat; end_of_host += 1; - if (std.mem.lastIndexOf(u8, authority, ":")) |index| { + if (std.mem.findLast(u8, authority, ":")) |index| { if (index >= end_of_host) { // if not part of the V6 address field end_of_host = @min(end_of_host, index); uri.port = std.fmt.parseInt(u16, authority[index + 1 ..], 10) catch return error.InvalidPort; } } - } else if (std.mem.lastIndexOf(u8, authority, ":")) |index| { + } else if (std.mem.findLast(u8, authority, ":")) |index| { if (index >= start_of_host) { // if not part of the userinfo field end_of_host = @min(end_of_host, index); uri.port = std.fmt.parseInt(u16, authority[index + 1 ..], 10) catch return error.InvalidPort; @@ -475,7 +475,7 @@ fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Co var aux: Writer = .fixed(aux_buf.*); if (!base.isEmpty()) { base.formatPath(&aux) catch return error.NoSpaceLeft; - aux.end = std.mem.lastIndexOfScalar(u8, aux.buffered(), '/') orelse return remove_dot_segments(new); + aux.end = std.mem.findScalarLast(u8, aux.buffered(), '/') orelse return remove_dot_segments(new); } aux.print("/{s}", .{new}) catch return error.NoSpaceLeft; const merged_path = remove_dot_segments(aux.buffered()); diff --git a/lib/std/array_hash_map.zig b/lib/std/array_hash_map.zig index fd2aa5ebc48b37c335465df7fe6ddf4a0623389b..b688551017f0cb945d67c0fb35d038ec332d7d78 100644 --- a/lib/std/array_hash_map.zig +++ b/lib/std/array_hash_map.zig @@ -13,12 +13,12 @@ const hash_map = @This(); /// /// See `AutoContext` for a description of the hash and equal implementations. pub fn Auto(comptime K: type, comptime V: type) type { - return ArrayHashMap(K, V, AutoContext(K), !autoEqlIsCheap(K)); + return Custom(K, V, AutoContext(K), !autoEqlIsCheap(K)); } /// An `ArrayHashMap` with strings as keys. pub fn String(comptime V: type) type { - return ArrayHashMap([]const u8, V, StringContext, true); + return Custom([]const u8, V, StringContext, true); } pub const StringContext = struct { @@ -2130,7 +2130,7 @@ test "0 sized key and 0 sized value" { test "setKey storehash true" { const gpa = std.testing.allocator; - var map: ArrayHashMap(i32, i32, AutoContext(i32), true) = .empty; + var map: Custom(i32, i32, AutoContext(i32), true) = .empty; defer map.deinit(gpa); try map.put(gpa, 12, 34); @@ -2146,7 +2146,7 @@ test "setKey storehash true" { test "setKey storehash false" { const gpa = std.testing.allocator; - var map: ArrayHashMap(i32, i32, AutoContext(i32), false) = .empty; + var map: Custom(i32, i32, AutoContext(i32), false) = .empty; defer map.deinit(gpa); try map.put(gpa, 12, 34); @@ -2162,7 +2162,7 @@ test "setKey storehash false" { test "setKey storehash false with index" { const gpa = std.testing.allocator; - const T = ArrayHashMap(usize, usize, AutoContext(usize), false); + const T = Custom(usize, usize, AutoContext(usize), false); var map: T = .empty; defer map.deinit(gpa); @@ -2180,9 +2180,9 @@ test "setKey storehash false with index" { test "setKey storehash true with index" { const gpa = std.testing.allocator; - const T = ArrayHashMap(usize, usize, AutoContext(usize), false); + const T = Custom(usize, usize, AutoContext(usize), false); - var map: ArrayHashMap(usize, usize, AutoContext(usize), true) = .empty; + var map: Custom(usize, usize, AutoContext(usize), true) = .empty; defer map.deinit(gpa); for (0..T.linear_scan_max + 1) |i| try map.put(gpa, i, i); diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index 24cc1de8bedc3e15a77335441ae75e696219f521..eefc6a415c2f895f098dbcbaa2b41ddfcb179a69 100644 --- a/lib/std/array_list.zig +++ b/lib/std/array_list.zig @@ -26,8 +26,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// /// Pointers to elements in this slice are invalidated by various /// functions of this ArrayList in accordance with the respective - /// documentation. In all cases, "invalidated" means that the memory - /// has been passed to this allocator's resize or free function. + /// documentation. + /// An invalidated pointer may point either to valid or freed memory. items: Slice, /// How many T values this list can hold without allocating /// additional memory. @@ -35,7 +35,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type allocator: Allocator, /// Used to detect memory safety violations. - pointer_stability: debug.SafetyLock = .{}, + pointer_stability: debug.SafetyLock, pub const Slice = if (alignment) |a| ([]align(a.toByteUnits()) T) else []T; @@ -49,6 +49,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type .items = &[_]T{}, .capacity = 0, .allocator = gpa, + .pointer_stability = .{}, }; } @@ -94,6 +95,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type .items = slice, .capacity = slice.len, .allocator = gpa, + .pointer_stability = .{}, }; } @@ -105,22 +107,28 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type .items = slice, .capacity = slice.len + 1, .allocator = gpa, + .pointer_stability = .{}, }; } /// Initializes an ArrayList with the `items` and `capacity` fields /// of this ArrayList. Empties this ArrayList. pub fn moveToUnmanaged(self: *Self) Aligned(T, alignment) { - self.pointer_stability.assertUnlocked(); const allocator = self.allocator; - const result: Aligned(T, alignment) = .{ .items = self.items, .capacity = self.capacity }; + const result: Aligned(T, alignment) = .{ + .items = self.items, + .capacity = self.capacity, + .pointer_stability = self.pointer_stability, + }; self.* = init(allocator); return result; } /// The caller owns the returned memory. Empties this ArrayList. /// Its capacity is cleared, making `deinit` safe but unnecessary to call. + /// May invalidate element pointers if remapping memory cannot be done in place. pub fn toOwnedSlice(self: *Self) Allocator.Error!Slice { + self.pointer_stability.assertUnlocked(); const allocator = self.allocator; const old_memory = self.allocatedSlice(); @@ -136,6 +144,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type } /// The caller owns the returned memory. Empties this ArrayList. + /// May invalidate element pointers if remapping memory cannot be done in place. pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { // This addition can never overflow because `self.items` can never occupy the whole address space try self.ensureTotalCapacityPrecise(self.items.len + 1); @@ -151,31 +160,31 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type return cloned; } - /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. - /// If `i` is equal to the length of the list this operation is equivalent to append. + /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. + /// If `index` is equal to the length of the list this operation is equivalent to append. /// This operation is O(N). /// Invalidates element pointers if additional memory is needed. + /// Invalidates pre-existing pointers to elements at and after `index`. /// Asserts that the index is in bounds or equal to the length. - pub fn insert(self: *Self, i: usize, item: T) Allocator.Error!void { - const dst = try self.addManyAt(i, 1); + pub fn insert(self: *Self, index: usize, item: T) Allocator.Error!void { + self.pointer_stability.assertUnlocked(); + const dst = try self.addManyAt(index, 1); dst[0] = item; } - /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. - /// If `i` is equal to the length of the list this operation is + /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. + /// If `index` is equal to the length of the list this operation is /// equivalent to appendAssumeCapacity. /// This operation is O(N). + /// Invalidates pre-existing pointers to elements at and after `index`. /// Asserts that there is enough capacity for the new item. /// Asserts that the index is in bounds or equal to the length. - pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); - + pub fn insertAssumeCapacity(self: *Self, index: usize, item: T) void { + self.pointer_stability.assertUnlocked(); assert(self.items.len < self.capacity); self.items.len += 1; - - @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); - self.items[i] = item; + @memmove(self.items[index + 1 .. self.items.len], self.items[index .. self.items.len - 1]); + self.items[index] = item; } /// Add `count` new elements at position `index`, which have @@ -188,12 +197,11 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// Asserts that the index is in bounds or equal to the length. pub fn addManyAt(self: *Self, index: usize, count: usize) Allocator.Error![]T { const new_len = try addOrOom(self.items.len, count); + self.pointer_stability.assertUnlocked(); if (self.capacity >= new_len) return addManyAtAssumeCapacity(self, index, count); - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); // Here we avoid copying allocated but unused bytes by // attempting a resize in place, and falling back to allocating // a new buffer and doing our own copy. With a realloc() call, @@ -225,9 +233,11 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// `undefined` values. Returns a slice pointing to the newly allocated /// elements, which becomes invalid after various `ArrayList` /// operations. + /// Invalidates pre-existing pointers to elements at and after `index`. /// Asserts that there is enough capacity for the new elements. /// Asserts that the index is in bounds or equal to the length. pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { + self.pointer_stability.assertUnlocked(); const new_len = self.items.len + count; assert(self.capacity >= new_len); const to_move = self.items[index..]; @@ -238,7 +248,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type return result; } - /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room. + /// Insert slice `items` at index `index` by moving `list[index .. list.len]` to make room. /// This operation is O(N). /// Invalidates pre-existing pointers to elements at and after `index`. /// Invalidates all pre-existing element pointers if capacity must be @@ -254,7 +264,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type } /// Grows or shrinks the list as necessary. - /// Invalidates element pointers if additional capacity is allocated. + /// Invalidates element pointers if additional capacity is allocated, + /// Invalidates pointers to elements at and above index `start + len` + /// when `len` and `new_items.len` are unequal. /// Asserts that the range is in bounds. pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void { var unmanaged = self.moveToUnmanaged(); @@ -263,7 +275,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type } /// Grows or shrinks the list as necessary. - /// Never invalidates element pointers. + /// Invalidates pointers to elements at and above index `start + len` + /// when `len` and `new_items.len` are unequal. /// Asserts the capacity is enough for additional items. pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void { var unmanaged = self.moveToUnmanaged(); @@ -300,10 +313,12 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// Removes the element at the specified index and returns it. /// The empty slot is filled from the end of the list. + /// Invalidates pointers to the end of the list. /// This operation is O(1). /// This may not preserve item order. Use `orderedRemove` if you need to preserve order. /// Asserts that the index is in bounds. pub fn swapRemove(self: *Self, i: usize) T { + self.pointer_stability.assertUnlocked(); const val = self.items[i]; self.items[i] = self.items[self.items.len - 1]; self.items[self.items.len - 1] = undefined; @@ -353,6 +368,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type @memcpy(self.items[old_len..][0..items.len], items); } + /// Prints a formatted string into this list. + /// Invalidates element pointers if additional memory is needed. pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { const gpa = self.allocator; var unmanaged = self.moveToUnmanaged(); @@ -404,9 +421,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// Invalidates element pointers for the elements `items[new_len..]`. /// Asserts that the new length is less than or equal to the previous length. pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); - + self.pointer_stability.assertUnlocked(); assert(new_len <= self.items.len); @memset(self.items[new_len..], undefined); self.items.len = new_len; @@ -415,8 +430,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// Reduce length to 0. /// Invalidates all element pointers. pub fn clearRetainingCapacity(self: *Self) void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); + self.pointer_stability.assertUnlocked(); @memset(self.items, undefined); self.items.len = 0; } @@ -449,18 +463,15 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// modify the array so that it can hold exactly `new_capacity` items. /// Invalidates element pointers if additional memory is needed. pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) Allocator.Error!void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); - if (@sizeOf(T) == 0) { self.capacity = math.maxInt(usize); return; } if (self.capacity >= new_capacity) return; - + self.pointer_stability.assertUnlocked(); // Here we avoid copying allocated but unused bytes by - // attempting a resize in place, and falling back to allocating + // attempting a remap, and falling back to allocating // a new buffer and doing our own copy. With a realloc() call, // the allocator implementation would pointlessly copy our // extra capacity. @@ -491,7 +502,8 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type } /// Increase length by 1, returning pointer to the new item. - /// The returned pointer becomes invalid when the list resized. + /// Invalidates element pointers if additional memory is needed. + /// The returned pointer may be invalidated by further operations to this list. pub fn addOne(self: *Self) Allocator.Error!*T { // This can never overflow because `self.items` can never occupy the whole address space const newlen = self.items.len + 1; @@ -500,7 +512,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type } /// Increase length by 1, returning pointer to the new item. - /// The returned pointer becomes invalid when the list is resized. + /// The returned pointer may be invalidated by further operations to this list. /// Never invalidates element pointers. /// Asserts that the list can hold one additional item. pub fn addOneAssumeCapacity(self: *Self) *T { @@ -511,8 +523,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// Resize the array, adding `n` new elements, which have `undefined` values. /// The return value is an array pointing to the newly allocated elements. - /// The returned pointer becomes invalid when the list is resized. + /// The returned pointer may be invalidated by further operations to this list. /// Resizes list if `self.capacity` is not large enough. + /// Invalidates element pointers if additional memory is needed. pub fn addManyAsArray(self: *Self, comptime n: usize) Allocator.Error!*[n]T { const prev_len = self.items.len; try self.resize(try addOrOom(self.items.len, n)); @@ -522,7 +535,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// Resize the array, adding `n` new elements, which have `undefined` values. /// The return value is an array pointing to the newly allocated elements. /// Never invalidates element pointers. - /// The returned pointer becomes invalid when the list is resized. + /// The returned pointer may be invalidated by further operations to this list. /// Asserts that the list can hold the additional items. pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { assert(self.items.len + n <= self.capacity); @@ -533,8 +546,9 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// Resize the array, adding `n` new elements, which have `undefined` values. /// The return value is a slice pointing to the newly allocated elements. - /// The returned pointer becomes invalid when the list is resized. + /// The returned pointer may be invalidated by further operations to this list. /// Resizes list if `self.capacity` is not large enough. + /// Invalidates element pointers if additional memory is needed. pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T { const prev_len = self.items.len; try self.resize(try addOrOom(self.items.len, n)); @@ -544,7 +558,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// Resize the array, adding `n` new elements, which have `undefined` values. /// The return value is a slice pointing to the newly allocated elements. /// Never invalidates element pointers. - /// The returned pointer becomes invalid when the list is resized. + /// The returned pointer may be invalidated by further operations to this list. /// Asserts that the list can hold the additional items. pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { assert(self.items.len + n <= self.capacity); @@ -554,11 +568,10 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type } /// Remove and return the last element from the list, or return `null` if list is empty. - /// Invalidates element pointers to the removed element, if any. + /// Invalidates element pointers to the removed element. pub fn pop(self: *Self) ?T { if (self.items.len == 0) return null; - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); + self.pointer_stability.assertUnlocked(); const val = self.items[self.items.len - 1]; self.items[self.items.len - 1] = undefined; self.items.len -= 1; @@ -567,6 +580,7 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// Returns a slice of all the items plus the extra capacity, whose memory /// contents are `undefined`. + /// The returned pointer may be invalidated by further operations to this list. pub fn allocatedSlice(self: Self) Slice { // `items.len` is the length, not the capacity. return self.items.ptr[0..self.capacity]; @@ -576,18 +590,29 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type /// This can be useful for writing directly into an ArrayList. /// Note that such an operation must be followed up with a direct /// modification of `self.items.len`. + /// The returned pointer may be invalidated by further operations to this list. pub fn unusedCapacitySlice(self: Self) []T { return self.allocatedSlice()[self.items.len..]; } - /// Deprecated in favor of `getLast` - pub const getLastOrNull = getLast; + /// Deprecated in favor of `last` + pub const getLastOrNull = last; - /// Returns the last element from the list, or `null` if the list is empty. - pub fn getLast(self: Self) ?T { + /// Returns the last element from the list, or `null` if the list is + /// empty. + /// Never invalidates element pointers. + pub fn last(self: Self) ?T { if (self.items.len == 0) return null; return self.items[self.items.len - 1]; } + + /// Returns a pointer to the last element from the list, or `null` if + /// the list is empty. + /// The returned pointer may be invalidated by further operations to this list. + pub fn lastPtr(self: Self) ?*T { + if (self.items.len == 0) return null; + return &self.items[self.items.len - 1]; + } }; } @@ -613,20 +638,21 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// /// Pointers to elements in this slice are invalidated by various /// functions of this ArrayList in accordance with the respective - /// documentation. In all cases, "invalidated" means that the memory - /// has been passed to an allocator's resize or free function. + /// documentation. + /// An invalidated pointer may point either to valid or freed memory. items: Slice, /// How many T values this list can hold without allocating /// additional memory. capacity: usize, /// Used to detect memory safety violations. - pointer_stability: debug.SafetyLock = .{}, + pointer_stability: debug.SafetyLock, /// An ArrayList containing no elements. pub const empty: Self = .{ .items = &.{}, .capacity = 0, + .pointer_stability = .{}, }; pub const Slice = if (alignment) |a| ([]align(a.toByteUnits()) T) else []T; @@ -652,6 +678,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { return .{ .items = buffer[0..0], .capacity = buffer.len, + .pointer_stability = .{}, }; } @@ -682,7 +709,12 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Convert this list into an analogous memory-managed one. /// The returned list has ownership of the underlying memory. pub fn toManaged(self: *Self, gpa: Allocator) AlignedManaged(T, alignment) { - return .{ .items = self.items, .capacity = self.capacity, .allocator = gpa }; + return .{ + .items = self.items, + .capacity = self.capacity, + .allocator = gpa, + .pointer_stability = self.pointer_stability, + }; } /// ArrayList takes ownership of the passed in slice. @@ -691,6 +723,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { return Self{ .items = slice, .capacity = slice.len, + .pointer_stability = .{}, }; } @@ -700,13 +733,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { return Self{ .items = slice, .capacity = slice.len + 1, + .pointer_stability = .{}, }; } /// The caller owns the returned memory. Empties this ArrayList. /// Its capacity is cleared, making deinit() safe but unnecessary to call. + /// May invalidate element pointers. pub fn toOwnedSlice(self: *Self, gpa: Allocator) Allocator.Error!Slice { const old_memory = self.allocatedSlice(); + self.pointer_stability.assertUnlocked(); if (gpa.remap(old_memory, self.items.len)) |new_items| { self.* = .empty; return new_items; @@ -719,7 +755,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// The caller owns the returned memory. ArrayList becomes empty. + /// May invalidate element pointers. pub fn toOwnedSliceSentinel(self: *Self, gpa: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) { + self.pointer_stability.assertUnlocked(); // This addition can never overflow because `self.items` can never occupy the whole address space. try self.ensureTotalCapacityPrecise(gpa, self.items.len + 1); self.appendAssumeCapacity(sentinel); @@ -732,6 +770,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Its capacity is cleared, making deinit() safe but unnecessary to call. /// /// Asserts what the capacity is equal to the length. + /// Never invalidates element pointers. pub fn toOwnedSliceAssert(self: *Self) Slice { assert(self.items.len == self.capacity); const items = self.items; @@ -741,6 +780,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// The caller owns the returned memory. ArrayList becomes empty. /// Asserts what the capacity is equal to the length + 1. + /// Never invalidates element pointers. pub fn toOwnedSliceSentinelAssert(self: *Self, comptime sentinel: T) SentinelSlice(sentinel) { std.debug.assert(self.items.len + 1 == self.capacity); self.appendAssumeCapacity(sentinel); @@ -755,46 +795,41 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { return cloned; } - /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. - /// If `i` is equal to the length of the list this operation is equivalent to append. + /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. + /// If `index` is equal to the length of the list this operation is equivalent to append. /// This operation is O(N). /// Invalidates element pointers if additional memory is needed. + /// Invalidates pre-existing pointers to elements at and after `index`. /// Asserts that the index is in bounds or equal to the length. - pub fn insert(self: *Self, gpa: Allocator, i: usize, item: T) Allocator.Error!void { - const dst = try self.addManyAt(gpa, i, 1); + pub fn insert(self: *Self, gpa: Allocator, index: usize, item: T) Allocator.Error!void { + self.pointer_stability.assertUnlocked(); + const dst = try self.addManyAt(gpa, index, 1); dst[0] = item; } - /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. - /// - /// If `i` is equal to the length of the list this operation is equivalent to append. - /// + /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. + /// If `index` is equal to the length of the list this operation is + /// equivalent to appendAssumeCapacity. /// This operation is O(N). - /// + /// Invalidates pre-existing pointers to elements at and after `index`. /// Asserts that the list has capacity for one additional item. - /// /// Asserts that the index is in bounds or equal to the length. - pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); - + pub fn insertAssumeCapacity(self: *Self, index: usize, item: T) void { + self.pointer_stability.assertUnlocked(); assert(self.items.len < self.capacity); self.items.len += 1; - - @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); - self.items[i] = item; + @memmove(self.items[index + 1 .. self.items.len], self.items[index .. self.items.len - 1]); + self.items[index] = item; } - /// Insert `item` at index `i`, moving `list[i .. list.len]` to higher indices to make room. - /// - /// If `i` is equal to the length of the list this operation is equivalent to append. - /// + /// Insert `item` at index `index`. Moves `list[index .. list.len]` to higher indices to make room. + /// If `index` is equal to the length of the list this operation is + /// equivalent to appendAssumeCapacity. /// This operation is O(N). - /// + /// Invalidates pre-existing pointers to elements at and after `index`. + /// Asserts that the index is in bounds or equal to the length. /// If the list lacks unused capacity for the additional item, returns /// `error.OutOfMemory`. - /// - /// Asserts that the index is in bounds or equal to the length. pub fn insertBounded(self: *Self, i: usize, item: T) error{OutOfMemory}!void { if (self.capacity - self.items.len == 0) return error.OutOfMemory; return insertAssumeCapacity(self, i, item); @@ -814,21 +849,48 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { index: usize, count: usize, ) Allocator.Error![]T { - var managed = self.toManaged(gpa); - defer self.* = managed.moveToUnmanaged(); - return managed.addManyAt(index, count); + const new_len = try addOrOom(self.items.len, count); + self.pointer_stability.assertUnlocked(); + + if (self.capacity >= new_len) + return addManyAtAssumeCapacity(self, index, count); + + // Here we avoid copying allocated but unused bytes by + // attempting a resize in place, and falling back to allocating + // a new buffer and doing our own copy. With a realloc() call, + // the allocator implementation would pointlessly copy our + // extra capacity. + const new_capacity = Aligned(T, alignment).growCapacity(new_len); + const old_memory = self.allocatedSlice(); + if (gpa.remap(old_memory, new_capacity)) |new_memory| { + self.items.ptr = new_memory.ptr; + self.capacity = new_memory.len; + return addManyAtAssumeCapacity(self, index, count); + } + + // Make a new allocation, avoiding `ensureTotalCapacity` in order + // to avoid extra memory copies. + const new_memory = try gpa.alignedAlloc(T, alignment, new_capacity); + const to_move = self.items[index..]; + @memcpy(new_memory[0..index], self.items[0..index]); + @memcpy(new_memory[index + count ..][0..to_move.len], to_move); + gpa.free(old_memory); + self.items = new_memory[0..new_len]; + self.capacity = new_memory.len; + // The inserted elements at `new_memory[index..][0..count]` have + // already been set to `undefined` by memory allocation. + return new_memory[index..][0..count]; } /// Add `count` new elements at position `index`, which have /// `undefined` values. Returns a slice pointing to the newly allocated /// elements, which becomes invalid after various `ArrayList` /// operations. + /// Invalidates pre-existing pointers to elements at and after `index`. /// Asserts that the list has capacity for the additional items. /// Asserts that the index is in bounds or equal to the length. pub fn addManyAtAssumeCapacity(self: *Self, index: usize, count: usize) []T { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); - + self.pointer_stability.assertUnlocked(); const new_len = self.items.len + count; assert(self.capacity >= new_len); const to_move = self.items[index..]; @@ -843,17 +905,16 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// `undefined` values, returning a slice pointing to the newly /// allocated elements, which becomes invalid after various `ArrayList` /// operations. - /// + /// Invalidates pre-existing pointers to elements at and after `index`. /// If the list lacks unused capacity for the additional items, returns /// `error.OutOfMemory`. - /// /// Asserts that the index is in bounds or equal to the length. pub fn addManyAtBounded(self: *Self, index: usize, count: usize) error{OutOfMemory}![]T { if (self.capacity - self.items.len < count) return error.OutOfMemory; return addManyAtAssumeCapacity(self, index, count); } - /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room. + /// Insert slice `items` at index `index` by moving `list[index .. list.len]` to make room. /// This operation is O(N). /// Invalidates pre-existing pointers to elements at and after `index`. /// Invalidates all pre-existing element pointers if capacity must be @@ -873,7 +934,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { @memcpy(dst, items); } - /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room. + /// Insert slice `items` at index `index` by moving `list[index .. list.len]` to make room. /// This operation is O(N). /// Invalidates pre-existing pointers to elements at and after `index`. /// Asserts that the list has capacity for the additional items. @@ -887,7 +948,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { @memcpy(dst, items); } - /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room. + /// Insert slice `items` at index `index` by moving `list[index .. list.len]` to make room. /// This operation is O(N). /// Invalidates pre-existing pointers to elements at and after `index`. /// If the list lacks unused capacity for the additional items, returns @@ -903,7 +964,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Grows or shrinks the list as necessary. - /// Invalidates element pointers if additional capacity is allocated. + /// Invalidates element pointers if additional capacity is allocated, + /// Invalidates pointers to elements at and above index `start + len` + /// when `len` and `new_items.len` are unequal. /// Asserts that the range is in bounds. pub fn replaceRange( self: *Self, @@ -917,9 +980,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Grows or shrinks the list as necessary. - /// - /// Never invalidates element pointers. - /// + /// Invalidates pointers to elements at and above index `start + len` + /// when `len` and `new_items.len` are unequal. /// Asserts the capacity is enough for additional items. pub fn replaceRangeAssumeCapacity( self: *Self, @@ -928,7 +990,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { new_items: []const T, ) void { std.debug.assert(self.capacity - self.items.len >= new_items.len -| len); - + self.pointer_stability.assertUnlocked(); const tail = self.items[start + len ..]; const vacated = self.items[self.items.len - (len -| new_items.len) ..]; self.items.len = self.items.len - len + new_items.len; @@ -937,10 +999,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { @memset(vacated, undefined); } - /// Grows or shrinks the list as necessary. - /// - /// Never invalidates element pointers. - /// + /// Invalidates pointers to elements at and above index `start + len` + /// when `len` and `new_items.len` are unequal. /// If the unused capacity is insufficient for additional items, /// returns `error.OutOfMemory`. pub fn replaceRangeBounded( @@ -1003,6 +1063,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// /// Invalidates element pointers beyond the first deleted index. pub fn orderedRemoveMany(self: *Self, sorted_indexes: []const usize) void { + self.pointer_stability.assertUnlocked(); if (sorted_indexes.len == 0) return; var shift: usize = 1; for (sorted_indexes[0 .. sorted_indexes.len - 1], sorted_indexes[1..]) |removed, end| { @@ -1025,8 +1086,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// This operation is O(1). /// Asserts that the index is in bounds. pub fn swapRemove(self: *Self, i: usize) T { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); + self.pointer_stability.assertUnlocked(); const val = self.items[i]; self.items[i] = self.items[self.items.len - 1]; self.items[self.items.len - 1] = undefined; @@ -1043,7 +1103,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Append the slice of items to the list. - /// + /// Never invalidates element pointers. /// Asserts that the list can hold the additional items. pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { const old_len = self.items.len; @@ -1054,7 +1114,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Append the slice of items to the list. - /// + /// Never invalidates element pointers. /// If the list lacks unused capacity for the additional items, returns `error.OutOfMemory`. pub fn appendSliceBounded(self: *Self, items: []const T) error{OutOfMemory}!void { if (self.capacity - self.items.len < items.len) return error.OutOfMemory; @@ -1074,7 +1134,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// /// Intended to be used only when `appendSliceAssumeCapacity` would be /// a compile error. - /// + /// Never invalidates element pointers. /// Asserts that the list can hold the additional items. pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { const old_len = self.items.len; @@ -1088,7 +1148,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// /// Intended to be used only when `appendSliceAssumeCapacity` would be /// a compile error. - /// + /// Never invalidates element pointers. /// If the list lacks unused capacity for the additional items, returns /// `error.OutOfMemory`. pub fn appendUnalignedSliceBounded(self: *Self, items: []align(1) const T) error{OutOfMemory}!void { @@ -1096,6 +1156,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { return appendUnalignedSliceAssumeCapacity(self, items); } + /// Prints a formatted string into this list. + /// Invalidates element pointers if additional memory is needed. pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { comptime assert(T == u8); try self.ensureUnusedCapacity(gpa, fmt.len); @@ -1106,6 +1168,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { }; } + /// Prints a formatted string into this list. + /// Asserts that there is enough capacity for the write. + /// Never invalidates element pointers. pub fn printAssumeCapacity(self: *Self, comptime fmt: []const u8, args: anytype) void { comptime assert(T == u8); var w: std.Io.Writer = .fixed(self.unusedCapacitySlice()); @@ -1113,6 +1178,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { self.items.len += w.end; } + /// Prints a formatted string into this list. + /// Returns error.OutOfMemory if additional capacity is needed for the write. + /// Never invalidates element pointers. pub fn printBounded(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { comptime assert(T == u8); var w: std.Io.Writer = .fixed(self.unusedCapacitySlice()); @@ -1188,8 +1256,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Asserts that the new length is less than or equal to the previous length. /// If succeds capacity is guaranteed to be equal to the length. pub fn shrinkAndFreePrecise(self: *Self, gpa: Allocator, new_len: usize) Allocator.Error!void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); + self.pointer_stability.assertUnlocked(); assert(new_len <= self.items.len); if (@sizeOf(T) == 0) { @@ -1243,8 +1310,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Keeps capacity the same. /// Asserts that the new length is less than or equal to the previous length. pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); + self.pointer_stability.assertUnlocked(); assert(new_len <= self.items.len); @memset(self.items[new_len..], undefined); @@ -1254,16 +1320,14 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Reduce length to 0. /// Invalidates all element pointers. pub fn clearRetainingCapacity(self: *Self) void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); + self.pointer_stability.assertUnlocked(); @memset(self.items, undefined); self.items.len = 0; } /// Invalidates all element pointers. pub fn clearAndFree(self: *Self, gpa: Allocator) void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); + self.pointer_stability.assertUnlocked(); gpa.free(self.allocatedSlice()); self.items.len = 0; self.capacity = 0; @@ -1281,8 +1345,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// modify the array so that it can hold exactly `new_capacity` items. /// Invalidates element pointers if additional memory is needed. pub fn ensureTotalCapacityPrecise(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void { - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); + self.pointer_stability.assertUnlocked(); if (@sizeOf(T) == 0) { self.capacity = math.maxInt(usize); @@ -1327,7 +1390,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Increase length by 1, returning pointer to the new item. - /// The returned element pointer becomes invalid when the list is resized. + /// Invalidates element pointers if additional memory is needed. + /// The returned pointer may be invalidated by further operations to this list. pub fn addOne(self: *Self, gpa: Allocator) Allocator.Error!*T { // This can never overflow because `self.items` can never occupy the whole address space const newlen = self.items.len + 1; @@ -1336,11 +1400,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Increase length by 1, returning pointer to the new item. - /// /// Never invalidates element pointers. - /// - /// The returned element pointer becomes invalid when the list is resized. - /// + /// The returned pointer may be invalidated by further operations to this list. /// Asserts that the list can hold one additional item. pub fn addOneAssumeCapacity(self: *Self) *T { assert(self.items.len < self.capacity); @@ -1350,11 +1411,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Increase length by 1, returning pointer to the new item. - /// /// Never invalidates element pointers. - /// - /// The returned element pointer becomes invalid when the list is resized. - /// + /// The returned pointer may be invalidated by further operations to this list. /// If the list lacks unused capacity for the additional item, returns `error.OutOfMemory`. pub fn addOneBounded(self: *Self) error{OutOfMemory}!*T { if (self.capacity - self.items.len < 1) return error.OutOfMemory; @@ -1362,8 +1420,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Resize the array, adding `n` new elements, which have `undefined` values. + /// Invalidates element pointers if additional memory is required. /// The return value is an array pointing to the newly allocated elements. - /// The returned pointer becomes invalid when the list is resized. + /// The returned pointer may be invalidated by further operations to this list. pub fn addManyAsArray(self: *Self, gpa: Allocator, comptime n: usize) Allocator.Error!*[n]T { const prev_len = self.items.len; try self.resize(gpa, try addOrOom(self.items.len, n)); @@ -1371,13 +1430,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Resize the array, adding `n` new elements, which have `undefined` values. - /// /// The return value is an array pointing to the newly allocated elements. - /// /// Never invalidates element pointers. - /// - /// The returned pointer becomes invalid when the list is resized. - /// + /// The returned pointer may be invalidated by further operations to this list. /// Asserts that the list can hold the additional items. pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { assert(self.items.len + n <= self.capacity); @@ -1387,13 +1442,9 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { } /// Resize the array, adding `n` new elements, which have `undefined` values. - /// /// The return value is an array pointing to the newly allocated elements. - /// /// Never invalidates element pointers. - /// - /// The returned pointer becomes invalid when the list is resized. - /// + /// The returned pointer may be invalidated by further operations to this list. /// If the list lacks unused capacity for the additional items, returns /// `error.OutOfMemory`. pub fn addManyAsArrayBounded(self: *Self, comptime n: usize) error{OutOfMemory}!*[n]T { @@ -1403,7 +1454,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Resize the array, adding `n` new elements, which have `undefined` values. /// The return value is a slice pointing to the newly allocated elements. - /// The returned pointer becomes invalid when the list is resized. + /// The returned pointer may be invalidated by further operations to this list. /// Resizes list if `self.capacity` is not large enough. pub fn addManyAsSlice(self: *Self, gpa: Allocator, n: usize) Allocator.Error![]T { const prev_len = self.items.len; @@ -1413,10 +1464,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Resizes the array, adding `n` new elements, which have `undefined` /// values, returning a slice pointing to the newly allocated elements. - /// - /// Never invalidates element pointers. The returned pointer becomes - /// invalid when the list is resized. - /// + /// Never invalidates element pointers. + /// The returned pointer may be invalidated by further operations to this list. /// Asserts that the list can hold the additional items. pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { assert(self.items.len + n <= self.capacity); @@ -1427,10 +1476,8 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Resizes the array, adding `n` new elements, which have `undefined` /// values, returning a slice pointing to the newly allocated elements. - /// - /// Never invalidates element pointers. The returned pointer becomes - /// invalid when the list is resized. - /// + /// Never invalidates element pointers. + /// The returned pointer may be invalidated by further operations to this list. /// If the list lacks unused capacity for the additional items, returns /// `error.OutOfMemory`. pub fn addManyAsSliceBounded(self: *Self, n: usize) error{OutOfMemory}![]T { @@ -1443,8 +1490,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Invalidates pointers to last element. pub fn pop(self: *Self) ?T { if (self.items.len == 0) return null; - self.pointer_stability.lock(); - defer self.pointer_stability.unlock(); + self.pointer_stability.assertUnlocked(); const val = self.items[self.items.len - 1]; self.items[self.items.len - 1] = undefined; @@ -1454,6 +1500,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// Returns a slice of all the items plus the extra capacity, whose memory /// contents are `undefined`. + /// The returned pointer may be invalidated by further operations to this list. pub fn allocatedSlice(self: Self) Slice { return self.items.ptr[0..self.capacity]; } @@ -1462,19 +1509,22 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type { /// This can be useful for writing directly into an ArrayList. /// Note that such an operation must be followed up with a direct /// modification of `self.items.len`. + /// The returned pointer may be invalidated by further operations to this list. pub fn unusedCapacitySlice(self: Self) []T { return self.allocatedSlice()[self.items.len..]; } - /// Deprecated in favor of `last`. - pub fn getLast(self: Self) ?T { + /// Returns the last element from the list, or `null` if the list is + /// empty. + pub fn last(self: Self) ?T { if (self.items.len == 0) return null; return self.items[self.items.len - 1]; } /// Returns a pointer to the last element from the list, or `null` if /// the list is empty. - pub fn last(self: Self) ?*T { + /// The returned pointer may be invalidated by further operations to this list. + pub fn lastPtr(self: Self) ?*T { if (self.items.len == 0) return null; return &self.items[self.items.len - 1]; } @@ -2441,6 +2491,10 @@ test "Managed(u0)" { count += 1; } try testing.expectEqual(count, 3); + + const ownedSlice = try list.toOwnedSlice(); + defer a.free(ownedSlice); + try testing.expectEqualSlices(u0, ownedSlice, &.{ 0, 0, 0 }); } test "Managed(?u32).pop()" { @@ -2469,7 +2523,7 @@ test "last" { try testing.expectEqual(list.last(), null); try list.append(a, 2); - try testing.expectEqual(list.last().?.*, 2); + try testing.expectEqual(list.last().?, 2); } test "return OutOfMemory when capacity would exceed maximum usize integer value" { @@ -2481,6 +2535,7 @@ test "return OutOfMemory when capacity would exceed maximum usize integer value" var list: ArrayList(u32) = .{ .items = undefined, .capacity = math.maxInt(usize) - 1, + .pointer_stability = .{}, }; list.items.len = math.maxInt(usize) - 1; @@ -2499,6 +2554,7 @@ test "return OutOfMemory when capacity would exceed maximum usize integer value" .items = undefined, .capacity = math.maxInt(usize) - 1, .allocator = a, + .pointer_stability = .{}, }; list.items.len = math.maxInt(usize) - 1; diff --git a/lib/std/ascii.zig b/lib/std/ascii.zig index e346e87eb6805c0328d909a1709223c628db5858..90fce8cb531c90659dccabb235b00c46e06bdfa1 100644 --- a/lib/std/ascii.zig +++ b/lib/std/ascii.zig @@ -511,11 +511,11 @@ pub const HexEscape = struct { }; /// Replaces non-ASCII bytes with hex escapes. -pub fn hexEscape(bytes: []const u8, case: std.fmt.Case) std.fmt.Alt(HexEscape, HexEscape.format) { - return .{ .data = .{ .bytes = bytes, .charset = switch (case) { +pub fn hexEscape(bytes: []const u8, case: std.fmt.Case) HexEscape { + return .{ .bytes = bytes, .charset = switch (case) { .lower => HexEscape.lower_charset, .upper => HexEscape.upper_charset, - } } }; + } }; } test hexEscape { diff --git a/lib/std/bit_set.zig b/lib/std/bit_set.zig index b7920e20124d4e04f78662a14861ed7f9f6ae711..1a31e3b1a50b55cb8f26aa63789c1a04e9f6bc84 100644 --- a/lib/std/bit_set.zig +++ b/lib/std/bit_set.zig @@ -1707,8 +1707,6 @@ fn testStaticBitSet(comptime Set: type) !void { } test Integer { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - try testStaticBitSet(Integer(0)); try testStaticBitSet(Integer(1)); try testStaticBitSet(Integer(2)); diff --git a/lib/std/c.zig b/lib/std/c.zig index c6a3739972ca0f4b105d9f8168f7e329f15ff184..7bc7f126591cf84614510be5f7da50deef095641 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -2821,13 +2821,14 @@ pub const SIG = switch (native_os) { } pub const POLL: SIG = .IO; + pub const IOT: SIG = .ABRT; + pub const CLD: SIG = .CHLD; HUP = 1, INT = 2, QUIT = 3, ILL = 4, TRAP = 5, - IOT = 6, ABRT = 6, EMT = 7, FPE = 8, @@ -2840,7 +2841,6 @@ pub const SIG = switch (native_os) { TERM = 15, USR1 = 16, USR2 = 17, - CLD = 18, CHLD = 18, PWR = 19, WINCH = 20, @@ -2991,6 +2991,7 @@ pub const SIG = switch (native_os) { pub const UNBLOCK = 2; pub const SETMASK = 3; + pub const IO: SIG = .POLL; pub const IOT: SIG = .ABRT; HUP = 1, @@ -9736,6 +9737,7 @@ pub const SS = switch (native_os) { pub const EV = switch (native_os) { .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => struct { + // https://github.com/apple-oss-distributions/xnu/blob/main/bsd/sys/event.h /// add event to kq (implies enable) pub const ADD = 0x0001; /// delete event from kq @@ -9771,11 +9773,14 @@ pub const EV = switch (native_os) { pub const FLAG0 = 0x1000; /// filter-specific flag pub const FLAG1 = 0x2000; - /// EOF detected + /// EOF detected (return value) pub const EOF = 0x8000; - /// error, data contains errno + /// error, data contains errno (return value) pub const ERROR = 0x4000; + /// use poll(2) semantics for EVFILT.READ pub const POLL = FLAG0; + /// on input, filter should actively return in the presence of OOB on the descriptor + /// on output, indicates the presence of OOB data on the descriptor pub const OOBAND = FLAG1; }, .dragonfly => struct { @@ -9818,6 +9823,7 @@ pub const EV = switch (native_os) { pub const EOF = 0x8000; }, .freebsd => struct { + // https://cgit.freebsd.org/src/tree/sys/sys/event.h /// add event to kq (implies enable) pub const ADD = 0x0001; /// delete event from kq @@ -9826,12 +9832,14 @@ pub const EV = switch (native_os) { pub const ENABLE = 0x0004; /// disable event (not reported) pub const DISABLE = 0x0008; + /// enable _ONESHOT and force trigger + pub const FORCEONESHOT = 0x0100; + /// do not update the udata field + pub const KEEPUDATA = 0x0200; /// only report one occurrence pub const ONESHOT = 0x0010; /// clear event state after reporting pub const CLEAR = 0x0020; - /// error, event data contains errno - pub const ERROR = 0x4000; /// force immediate event output /// ... with or without ERROR /// ... use KEVENT_FLAG_ERROR_EVENTS @@ -9839,6 +9847,18 @@ pub const EV = switch (native_os) { pub const RECEIPT = 0x0040; /// disable event after reporting pub const DISPATCH = 0x0080; + /// reserved by system + pub const SYSFLAGS = 0xF000; + /// note should be dropped + pub const DROP = 0x1000; + /// filter-specific flag 1 + pub const FLAG1 = 0x2000; + /// filter-specific flag 2 + pub const FLAG2 = 0x4000; + /// EOF detected (return value) + pub const EOF = 0x8000; + /// error, event data contains errno (return value) + pub const ERROR = 0x4000; }, .openbsd => struct { pub const ADD = 0x0001; @@ -9962,6 +9982,7 @@ pub const EVFILT = switch (native_os) { pub const EMPTY = 9; }, .freebsd => struct { + // https://cgit.freebsd.org/src/tree/sys/sys/event.h pub const READ = -1; pub const WRITE = -2; /// attached to aio requests @@ -9978,12 +9999,18 @@ pub const EVFILT = switch (native_os) { pub const PROCDESC = -8; /// Filesystem events pub const FS = -9; + /// attached to lio requests pub const LIO = -10; /// User events pub const USER = -11; /// Sendfile events pub const SENDFILE = -12; + /// empty send socket buf pub const EMPTY = -13; + /// attached to struct prison + pub const JAIL = -14; + /// attached to jail descriptors + pub const JAILDESC = -15; }, .openbsd => struct { pub const READ = -1; @@ -10002,6 +10029,7 @@ pub const EVFILT = switch (native_os) { pub const NOTE = switch (native_os) { .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => struct { + // https://github.com/apple-oss-distributions/xnu/blob/main/bsd/sys/event.h /// On input, TRIGGER causes the event to be triggered for output. pub const TRIGGER = 0x01000000; /// ignore input fflags @@ -10033,7 +10061,7 @@ pub const NOTE = switch (native_os) { pub const RENAME = 0x00000020; /// vnode access was revoked pub const REVOKE = 0x00000040; - /// No specific vnode event: to test for EVFILT_READ activation + /// No specific vnode event: to test for EVFILT_READ activation pub const NONE = 0x00000080; /// vnode was unlocked by flock(2) pub const FUNLOCK = 0x00000100; @@ -10045,7 +10073,7 @@ pub const NOTE = switch (native_os) { pub const EXEC = 0x20000000; /// shared with EVFILT_SIGNAL pub const SIGNAL = 0x08000000; - /// exit status to be returned, valid for child process only + /// exit status to be returned, valid for child process only pub const EXITSTATUS = 0x04000000; /// provide details on reasons for exit pub const EXIT_DETAIL = 0x02000000; @@ -10056,11 +10084,11 @@ pub const NOTE = switch (native_os) { pub const EXIT_DECRYPTFAIL = 0x00010000; pub const EXIT_MEMORY = 0x00020000; pub const EXIT_CSERROR = 0x00040000; - /// will react on memory pressure + /// will react on memory pressure pub const VM_PRESSURE = 0x80000000; - /// will quit on memory pressure, possibly after cleaning up dirty state + /// will quit on memory pressure, possibly after cleaning up dirty state pub const VM_PRESSURE_TERMINATE = 0x40000000; - /// will quit immediately on memory pressure + /// will quit immediately on memory pressure pub const VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000; /// there was an error pub const VM_ERROR = 0x10000000; @@ -10078,6 +10106,9 @@ pub const NOTE = switch (native_os) { pub const CRITICAL = 0x00000020; /// system does maximum timer coalescing pub const BACKGROUND = 0x00000040; + /// with ABSOLUTE: causes the timer to continue to tick across sleep, still uses gettimeofday epoch + /// with MACHTIME and ABSOLUTE: uses mach continuous time epoch + /// without ABSOLUTE: continues to tick across sleep pub const MACH_CONTINUOUS_TIME = 0x00000080; /// data is mach absolute time units pub const MACHTIME = 0x00000100; @@ -11237,31 +11268,30 @@ pub const signalfd_siginfo = illumos.signalfd_siginfo; pub const taskid_t = illumos.taskid_t; pub const zoneid_t = illumos.zoneid_t; +pub const B_ABSOLUTE_TIMEOUT = haiku.B_ABSOLUTE_TIMEOUT; +pub const B_OS_NAME_LENGTH = haiku.B_OS_NAME_LENGTH; +pub const B_TIMEOUT_REAL_TIME_BASE = haiku.B_TIMEOUT_REAL_TIME_BASE; pub const DirEnt = haiku.DirEnt; -pub const _get_next_area_info = haiku._get_next_area_info; -pub const _get_next_image_info = haiku._get_next_image_info; -pub const _get_team_info = haiku._get_team_info; -pub const _kern_get_current_team = haiku._kern_get_current_team; +pub const _kern_acquire_sem_etc = haiku._kern_acquire_sem_etc; +pub const _kern_create_sem = haiku._kern_create_sem; +pub const _kern_delete_sem = haiku._kern_delete_sem; pub const _kern_open_dir = haiku._kern_open_dir; pub const _kern_read_dir = haiku._kern_read_dir; pub const _kern_read_stat = haiku._kern_read_stat; +pub const _kern_release_sem_etc = haiku._kern_release_sem_etc; pub const _kern_rewind_dir = haiku._kern_rewind_dir; -pub const readv_pos = haiku.readv_pos; -pub const writev_pos = haiku.writev_pos; pub const area_id = haiku.area_id; -pub const area_info = haiku.area_info; -pub const directory_which = haiku.directory_which; -pub const find_directory = haiku.find_directory; pub const find_thread = haiku.find_thread; pub const get_system_info = haiku.get_system_info; -pub const image_info = haiku.image_info; +pub const on_exit_thread = haiku.on_exit_thread; pub const port_id = haiku.port_id; +pub const readv_pos = haiku.readv_pos; pub const sem_id = haiku.sem_id; pub const status_t = haiku.status_t; pub const system_info = haiku.system_info; pub const team_id = haiku.team_id; -pub const team_info = haiku.team_info; pub const thread_id = haiku.thread_id; +pub const writev_pos = haiku.writev_pos; pub const AUTH = openbsd.AUTH; pub const BI = openbsd.BI; diff --git a/lib/std/c/darwin/dispatch.zig b/lib/std/c/darwin/dispatch.zig index 770eadf7170f915d877d3d079c7d13b9585ae0a1..5a00b856192b64e786daad59cada13eca06b6ec7 100644 --- a/lib/std/c/darwin/dispatch.zig +++ b/lib/std/c/darwin/dispatch.zig @@ -44,8 +44,8 @@ pub const once_t = enum(isize) { once_f(predicate, context, function); } else asm volatile ("" ::: .{ .memory = true }); switch (builtin.mode) { - .Debug, .ReleaseSafe => {}, - .ReleaseFast, .ReleaseSmall => if (predicate.* != .done) unreachable, + .debug, .safe => {}, + .fast, .small => if (predicate.* != .done) unreachable, } } }; diff --git a/lib/std/c/haiku.zig b/lib/std/c/haiku.zig index dd599ca83735d3c470859cd5c59c73a167983e27..dd8bb8abf621324ba3ff2c9765f17524e30624c6 100644 --- a/lib/std/c/haiku.zig +++ b/lib/std/c/haiku.zig @@ -1,15 +1,8 @@ const std = @import("../std.zig"); -const assert = std.debug.assert; const builtin = @import("builtin"); -const maxInt = std.math.maxInt; -const iovec = std.posix.iovec; -const iovec_const = std.posix.iovec_const; -const socklen_t = std.c.socklen_t; +const assert = std.debug.assert; const fd_t = std.c.fd_t; const off_t = std.c.off_t; -const PATH_MAX = std.c.PATH_MAX; -const uid_t = std.c.uid_t; -const gid_t = std.c.gid_t; const dev_t = std.c.dev_t; const ino_t = std.c.ino_t; @@ -17,53 +10,28 @@ comptime { assert(builtin.os.tag == .haiku); // Prevent access of std.c symbols on wrong OS. } -pub extern "root" fn _errnop() *i32; -pub extern "root" fn find_directory(which: directory_which, volume: i32, createIt: bool, path_ptr: [*]u8, length: i32) u64; -pub extern "root" fn find_thread(thread_name: ?*anyopaque) i32; -pub extern "root" fn get_system_info(system_info: *system_info) usize; -pub extern "root" fn _get_team_info(team: i32, team_info: *team_info, size: usize) i32; -pub extern "root" fn _get_next_area_info(team: i32, cookie: *i64, area_info: *area_info, size: usize) i32; -pub extern "root" fn _get_next_image_info(team: i32, cookie: *i32, image_info: *image_info, size: usize) i32; -pub extern "root" fn _kern_get_current_team() team_id; +pub const B_OS_NAME_LENGTH = 32; +pub const B_ABSOLUTE_TIMEOUT = 0x10; +pub const B_TIMEOUT_REAL_TIME_BASE = 0x40; + +pub extern "root" fn _kern_create_sem(count: c_int, name: ?[*:0]const u8) sem_id; +pub extern "root" fn _kern_delete_sem(id: sem_id) status_t; +pub extern "root" fn _kern_acquire_sem_etc(id: sem_id, count: u32, flags: u32, timeout: i64) status_t; +pub extern "root" fn _kern_release_sem_etc(id: sem_id, count: u32, flags: u32) status_t; pub extern "root" fn _kern_open_dir(fd: fd_t, path: [*:0]const u8) fd_t; pub extern "root" fn _kern_read_dir(fd: fd_t, buffer: [*]u8, bufferSize: usize, maxCount: u32) isize; pub extern "root" fn _kern_rewind_dir(fd: fd_t) status_t; pub extern "root" fn _kern_read_stat(fd: fd_t, path: [*:0]const u8, traverseLink: bool, stat: *std.c.Stat, statSize: usize) status_t; + +pub extern "root" fn on_exit_thread(callback: *const fn (?*anyopaque) callconv(.c) void, data: ?*anyopaque) status_t; +pub extern "root" fn find_thread(name: ?[*:0]const u8) thread_id; +pub extern "root" fn get_system_info(info: *system_info) status_t; + +pub extern "root" fn _errnop() *i32; + pub extern "root" fn readv_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec, count: i32) isize; pub extern "root" fn writev_pos(fd: fd_t, pos: off_t, vec: [*]const std.c.iovec_const, count: i32) isize; -pub const area_info = extern struct { - area: u32, - name: [32]u8, - size: usize, - lock: u32, - protection: u32, - team_id: i32, - ram_size: u32, - copy_count: u32, - in_count: u32, - out_count: u32, - address: *anyopaque, -}; - -pub const image_info = extern struct { - id: u32, - image_type: u32, - sequence: i32, - init_order: i32, - init_routine: *anyopaque, - term_routine: *anyopaque, - device: i32, - node: i64, - name: [PATH_MAX]u8, - text: *anyopaque, - data: *anyopaque, - text_size: i32, - data_size: i32, - api_version: i32, - abi: i32, -}; - pub const system_info = extern struct { boot_time: i64, cpu_count: u32, @@ -86,31 +54,12 @@ pub const system_info = extern struct { max_teams: u32, used_teams: u32, kernel_name: [256]u8, - kernel_build_date: [32]u8, - kernel_build_time: [32]u8, + kernel_build_date: [B_OS_NAME_LENGTH]u8, + kernel_build_time: [B_OS_NAME_LENGTH]u8, kernel_version: i64, abi: u32, }; -pub const team_info = extern struct { - team_id: i32, - thread_count: i32, - image_count: i32, - area_count: i32, - debugger_nub_thread: i32, - debugger_nub_port: i32, - argc: i32, - args: [64]u8, - uid: uid_t, - gid: gid_t, -}; - -pub const directory_which = enum(i32) { - B_USER_SETTINGS_DIRECTORY = 0xbbe, - - _, -}; - pub const area_id = i32; pub const port_id = i32; pub const sem_id = i32; diff --git a/lib/std/compress/flate/Compress.zig b/lib/std/compress/flate/Compress.zig index 23ca2cb634a086080d49ddede293691046f13b4c..167bddd1b6923b2dd22fa2267c38c6e5118f8c39 100644 --- a/lib/std/compress/flate/Compress.zig +++ b/lib/std/compress/flate/Compress.zig @@ -738,7 +738,7 @@ fn matchAndAddHash(c: *Compress, i: usize, h: Hash, gt: u16, max_chain: u16, goo fn clenHlen(freqs: [19]u16) u4 { // Note that the first four codes (16, 17, 18, and 0) are always present. - if (builtin.mode != .ReleaseSmall and (std.simd.suggestVectorLength(u16) orelse 1) >= 8) { + if (builtin.mode != .small and (std.simd.suggestVectorLength(u16) orelse 1) >= 8) { const V = @Vector(16, u16); const hlen_mul: V = comptime m: { var hlen_mul: [16]u16 = undefined; diff --git a/lib/std/compress/flate/token.zig b/lib/std/compress/flate/token.zig index 3c0866896d2cd966e3bd23fdd82cecfa54761fc8..de84f045e83d7296a079326a78dc95fc29b04c1b 100644 --- a/lib/std/compress/flate/token.zig +++ b/lib/std/compress/flate/token.zig @@ -57,9 +57,9 @@ const fixed_dist = blk: { }; // All paramters of codes can be derived matchematically, however some are faster to -// do via lookup table. For ReleaseSmall, we do all mathematically to save space. -pub const LenCode = if (builtin.mode != .ReleaseSmall) LookupLenCode else ShortLenCode; -pub const DistCode = if (builtin.mode != .ReleaseSmall) LookupDistCode else ShortDistCode; +// do via lookup table. For -Osmall, we do all mathematically to save space. +pub const LenCode = if (builtin.mode != .small) LookupLenCode else ShortLenCode; +pub const DistCode = if (builtin.mode != .small) LookupDistCode else ShortDistCode; const ShortLenCode = ShortCode(u8, u2, u3, true); const ShortDistCode = ShortCode(u15, u1, u4, false); /// For length and distance codes, they having this format. diff --git a/lib/std/crypto/25519/field.zig b/lib/std/crypto/25519/field.zig index d10f92550a5877b7dfde918a2e9718af948569bb..1c707815872a62d57417f04d572d7d6006110aac 100644 --- a/lib/std/crypto/25519/field.zig +++ b/lib/std/crypto/25519/field.zig @@ -7,8 +7,8 @@ const NotSquareError = crypto.errors.NotSquareError; // Inline conditionally, when it can result in large code generation. const bloaty_inline: std.builtin.CallingConvention = switch (builtin.mode) { - .ReleaseSafe, .ReleaseFast => .@"inline", - .Debug, .ReleaseSmall => .auto, + .safe, .fast => .@"inline", + .debug, .small => .auto, }; pub const Fe = struct { diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig index 33502074f661d86b2b6778361e85ab89172242d9..974c486b1bf13a5a4a8bf7a7a9be7c37451d0267 100644 --- a/lib/std/crypto/Certificate.zig +++ b/lib/std/crypto/Certificate.zig @@ -175,6 +175,8 @@ pub const GeneralNameTag = enum(u5) { _, }; +const net = @import("../Io/net.zig"); + pub const Parsed = struct { certificate: Certificate, issuer_slice: Slice, @@ -315,6 +317,7 @@ pub const Parsed = struct { // what to check. Otherwise, only the common name is checked. const subject_alt_name = parsed_subject.subjectAltName(); if (subject_alt_name.len == 0) { + // note: checkIpAddress is intentionally omitted, as it is not permitted in the common name field anyway. if (checkHostName(host_name, parsed_subject.commonName())) { return; } else { @@ -332,6 +335,10 @@ pub const Parsed = struct { const dns_name = subject_alt_name[general_name.slice.start..general_name.slice.end]; if (checkHostName(host_name, dns_name)) return; }, + .iPAddress => { + const ip_address = subject_alt_name[general_name.slice.start..general_name.slice.end]; + if (checkIpAddress(host_name, ip_address)) return; + }, else => {}, } } @@ -376,6 +383,22 @@ pub const Parsed = struct { return false; } + + // Check IP address according to RFC 5280 §4.2.1.6. + fn checkIpAddress(host_name: []const u8, ip_address: []const u8) bool { + switch (ip_address.len) { + 4 => { + // port is irrelevant to SAN matching, so 0 is a harmless placeholder. + const address = net.Ip4Address.parse(host_name, 0) catch return false; + return mem.eql(u8, &address.bytes, ip_address); + }, + 16 => { + const address = net.Ip6Address.parse(host_name, 0) catch return false; + return mem.eql(u8, &address.bytes, ip_address); + }, + else => return false, // a malformed certificate, neither 4 nor 16 octets + } + } }; test "Parsed.checkHostName RFC 6125 compliance" { @@ -417,6 +440,39 @@ test "Parsed.checkHostName RFC 6125 compliance" { try expectEqual(false, Parsed.checkHostName("example.com", "*.")); } +test "Parsed.checkIpAddress RFC 5280 4.2.1.6 compliance" { + const expectEqual = std.testing.expectEqual; + + // Exact match positive tests + try expectEqual(true, Parsed.checkIpAddress("127.0.0.1", &[4]u8{ 127, 0, 0, 1 })); + try expectEqual(true, Parsed.checkIpAddress("0:0:0:0:0:0:0:1", &[16]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 })); + + // Mismatches should not pass + try expectEqual(false, Parsed.checkIpAddress("1.2.3.4", &[4]u8{ 5, 6, 7, 8 })); + try expectEqual(false, Parsed.checkIpAddress("0:0:0:0:0:0:0:1", &[16]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 })); + + // IPv6: the hostname may be in short-form and should match the exact 16 octets specified in the SAN + try expectEqual(true, Parsed.checkIpAddress("::1", &[16]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 })); + + // IPv6: do not match when using DNS64 / NAT64 (i.e. 64:ff9b::/96) + // the RFC requires exact octet matches, so this is likely surprising and wrong. The decision here is to fail-safe out of an abundance of caution. + // The test assertions are included not to harden on this behavior, but to show that this use-case was considered. + // This check may become more lenient in the future if a valid use-case is found. + try expectEqual(false, Parsed.checkIpAddress("64:ff9b::192.0.2.10", &[4]u8{ 192, 0, 2, 10 })); + try expectEqual(false, Parsed.checkIpAddress("::ffff:127.0.0.1", &[4]u8{ 127, 0, 0, 1 })); + + // Malformed SAN lengths (not 4 or 16 octets) never match. + try expectEqual(false, Parsed.checkIpAddress("127.0.0", &[_]u8{ 127, 0, 0 })); + try expectEqual(false, Parsed.checkIpAddress("127.0.0.1.0", &[_]u8{ 127, 0, 0, 1, 0 })); + + // A non-parseable host_name never matches. + try expectEqual(false, Parsed.checkIpAddress("not-an-ip", &[4]u8{ 127, 0, 0, 1 })); + + // Edge cases - empty strings + try expectEqual(false, Parsed.checkIpAddress("", "")); + try expectEqual(false, Parsed.checkIpAddress("127.0.0.1", "")); +} + pub const ParseError = der.Element.ParseError || ParseVersionError || ParseTimeError || ParseEnumError || ParseBitStringError; pub fn parse(cert: Certificate) ParseError!Parsed { @@ -793,7 +849,7 @@ fn verifyRsa( inline 128, 256, 384, 512 => |modulus_len| { const public_key = rsa.PublicKey.fromBytes(exponent, modulus) catch return error.CertificateSignatureInvalid; - rsa.PKCS1v1_5Signature.verify(modulus_len, sig[0..modulus_len].*, msg, public_key, Hash) catch + rsa.PKCS1v1_5Signature.verify(modulus_len, sig[0..modulus_len], msg, public_key, Hash) catch return error.CertificateSignatureInvalid; }, else => return error.CertificateSignatureUnsupportedBitCount, @@ -983,7 +1039,7 @@ pub const rsa = struct { pub fn concatVerify( comptime modulus_len: usize, - sig: [modulus_len]u8, + sig: *const [modulus_len]u8, msg: []const []const u8, public_key: PublicKey, comptime Hash: type, @@ -1092,9 +1148,9 @@ pub const rsa = struct { } var m_p_buf: [8 + Hash.digest_length + Hash.digest_length]u8 = undefined; var m_p = m_p_buf[0 .. 8 + Hash.digest_length + sLen]; - std.mem.copyForwards(u8, m_p, @as(*const [8]u8, &@splat(0))); - std.mem.copyForwards(u8, m_p[8..], &mHash); - std.mem.copyForwards(u8, m_p[(8 + Hash.digest_length)..], salt); + @memmove(m_p[0..8], @as(*const [8]u8, &@splat(0))); + @memmove(m_p[8..][0..Hash.digest_length], &mHash); + @memmove(m_p[(8 + Hash.digest_length)..], salt); // 13. Let H' = Hash(M'), an octet string of length hLen. var h_p: [Hash.digest_length]u8 = undefined; @@ -1136,7 +1192,7 @@ pub const rsa = struct { pub fn verify( comptime modulus_len: usize, - sig: [modulus_len]u8, + sig: *const [modulus_len]u8, msg: []const u8, public_key: PublicKey, comptime Hash: type, @@ -1146,7 +1202,7 @@ pub const rsa = struct { pub fn concatVerify( comptime modulus_len: usize, - sig: [modulus_len]u8, + sig: *const [modulus_len]u8, msg: []const []const u8, public_key: PublicKey, comptime Hash: type, @@ -1187,6 +1243,11 @@ pub const rsa = struct { // DigestInfo value (see the notes below) and let tLen be the length // in octets of T. const hash_der: []const u8 = &switch (Hash) { + crypto.hash.Md5 => .{ + 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, + 0x04, 0x10, + }, crypto.hash.Sha1 => .{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, @@ -1211,7 +1272,17 @@ pub const rsa = struct { 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40, }, - else => @compileError("unreachable"), + crypto.hash.sha3.Sha3_256 => .{ + 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, + 0x00, 0x04, 0x20, + }, + crypto.hash.sha3.Sha3_512 => .{ + 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a, 0x05, + 0x00, 0x04, 0x40, + }, + else => comptime unreachable, }; em_index -= hash_der.len; @memcpy(em[em_index..][0..hash_der.len], hash_der); @@ -1292,8 +1363,8 @@ pub const rsa = struct { const EncryptError = error{MessageTooLong}; - fn encrypt(comptime modulus_len: usize, msg: [modulus_len]u8, public_key: PublicKey) EncryptError![modulus_len]u8 { - const m = Fe.fromBytes(public_key.n, &msg, .big) catch return error.MessageTooLong; + fn encrypt(comptime modulus_len: usize, msg: *const [modulus_len]u8, public_key: PublicKey) EncryptError![modulus_len]u8 { + const m = Fe.fromBytes(public_key.n, msg, .big) catch return error.MessageTooLong; const e = public_key.n.powPublic(m, public_key.e) catch unreachable; var res: [modulus_len]u8 = undefined; e.toBytes(&res, .big) catch unreachable; diff --git a/lib/std/crypto/aes.zig b/lib/std/crypto/aes.zig index acf3a72e1fd2616a6074f896c3cf53da02364c48..54d1bd0dc8474d9eb299ca823864fdc9a1a001ea 100644 --- a/lib/std/crypto/aes.zig +++ b/lib/std/crypto/aes.zig @@ -6,9 +6,9 @@ const has_aesni = builtin.cpu.has(.x86, .aes); const has_avx = builtin.cpu.has(.x86, .avx); const has_armaes = builtin.cpu.has(.aarch64, .aes); // C backend doesn't currently support passing vectors to inline asm. -const impl = if (builtin.cpu.arch == .x86_64 and builtin.zig_backend != .stage2_c and has_aesni and has_avx) impl: { +const impl = if (builtin.cpu.arch == .x86_64 and has_aesni and has_avx) impl: { break :impl @import("aes/aesni.zig"); -} else if (builtin.cpu.arch == .aarch64 and builtin.zig_backend != .stage2_c and has_armaes) impl: { +} else if (builtin.cpu.arch == .aarch64 and (builtin.zig_backend != .stage2_c or !builtin.os.tag.isDarwin()) and has_armaes) impl: { break :impl @import("aes/armcrypto.zig"); } else impl: { break :impl @import("aes/soft.zig"); diff --git a/lib/std/crypto/aes_ocb.zig b/lib/std/crypto/aes_ocb.zig index 36e2aaa84cbb852ab0dc8b20ccf4aca8ecfea710..5c3af0615112822c58c892fa373150e23050dfcc 100644 --- a/lib/std/crypto/aes_ocb.zig +++ b/lib/std/crypto/aes_ocb.zig @@ -262,8 +262,6 @@ const hexToBytes = std.fmt.hexToBytes; const testing = std.testing; test "AesOcb test vector 1" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; @@ -281,8 +279,6 @@ test "AesOcb test vector 1" { } test "AesOcb test vector 2" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; @@ -303,8 +299,6 @@ test "AesOcb test vector 2" { } test "AesOcb test vector 3" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; @@ -329,8 +323,6 @@ test "AesOcb test vector 3" { } test "AesOcb test vector 4" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; @@ -356,8 +348,6 @@ test "AesOcb test vector 4" { } test "AesOcb in-place encryption-decryption" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var k: [Aes128Ocb.key_length]u8 = undefined; var nonce: [Aes128Ocb.nonce_length]u8 = undefined; var tag: [Aes128Ocb.tag_length]u8 = undefined; diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index ef19aac818b764604ed562d2d6832170f4ed91f9..014a7d3558e1a2cd0d3131be834261d97416b613 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -454,8 +454,8 @@ fn benchmarkPwhash( const strHash = ty.strHash; const strHashFnInfo = @typeInfo(@TypeOf(strHash)).@"fn"; - const needs_io = strHashFnInfo.params.len == 4 and strHashFnInfo.params[3].type == std.Io; - const needs_salt = strHashFnInfo.params.len == 4 and strHashFnInfo.params[3].type != std.Io; + const needs_io = strHashFnInfo.param_types.len == 4 and strHashFnInfo.param_types[3].? == std.Io; + const needs_salt = strHashFnInfo.param_types.len == 4 and strHashFnInfo.param_types[3].? != std.Io; const salt: [16]u8 = @splat(0); const start = benchTime(io); @@ -493,7 +493,7 @@ fn usage() void { } fn mode(comptime x: comptime_int) comptime_int { - return if (builtin.mode == .Debug) x / 64 else x; + return if (builtin.mode == .debug) x / 64 else x; } pub fn main(init: std.process.Init) !void { diff --git a/lib/std/crypto/ecdsa.zig b/lib/std/crypto/ecdsa.zig index b111b8e52a706b7b869a8091747934291912eff6..77e0349341168fd3d6e0b68979d95cf45753bc4f 100644 --- a/lib/std/crypto/ecdsa.zig +++ b/lib/std/crypto/ecdsa.zig @@ -1,4 +1,3 @@ -const builtin = @import("builtin"); const std = @import("std"); const crypto = std.crypto; const fmt = std.fmt; @@ -25,14 +24,17 @@ pub const EcdsaSecp256k1Sha256 = Ecdsa(crypto.ecc.Secp256k1, crypto.hash.sha2.Sh pub const EcdsaSecp256k1Sha256oSha256 = Ecdsa(crypto.ecc.Secp256k1, crypto.hash.composition.Sha256oSha256); /// Elliptic Curve Digital Signature Algorithm (ECDSA). -pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { - const Prf = switch (Hash) { +pub fn Ecdsa(comptime C: type, comptime H: type) type { + const Prf = switch (H) { sha3.Shake128 => sha3.KMac128, sha3.Shake256 => sha3.KMac256, - else => crypto.auth.hmac.Hmac(Hash), + else => crypto.auth.hmac.Hmac(H), }; return struct { + pub const Curve = C; + pub const Hash = H; + /// Length (in bytes) of optional random bytes, for non-deterministic signatures. pub const noise_length = Curve.scalar.encoded_length; @@ -415,8 +417,6 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { } test "Basic operations over EcdsaP384Sha384" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = EcdsaP384Sha384; const kp = Scheme.KeyPair.generate(io); @@ -432,8 +432,6 @@ test "Basic operations over EcdsaP384Sha384" { } test "Basic operations over Secp256k1" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = EcdsaSecp256k1Sha256oSha256; const kp = Scheme.KeyPair.generate(io); @@ -449,8 +447,6 @@ test "Basic operations over Secp256k1" { } test "Basic operations over EcdsaP384Sha256" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256); const kp = Scheme.KeyPair.generate(io); @@ -466,8 +462,6 @@ test "Basic operations over EcdsaP384Sha256" { } test "Verifying a existing signature with EcdsaP384Sha256" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256); // zig fmt: off const sk_bytes = [_]u8{ @@ -503,8 +497,6 @@ test "Verifying a existing signature with EcdsaP384Sha256" { } test "Prehashed message operations" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = EcdsaP256Sha256; @@ -539,8 +531,6 @@ const TestVector = struct { }; test "Test vectors from Project Wycheproof - EcdsaP256Sha256 valid" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const vectors: []const TestVector = &.{ // well-formed DER encoding -> expected valid .{ .key = "042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e", .msg = "313233343030", .sig = "304402202ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e1802204cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76" }, @@ -711,8 +701,6 @@ test "Test vectors from Project Wycheproof - EcdsaP256Sha256 valid" { } test "Test vectors from Project Wycheproof - EcdsaP256Sha256 invalid" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const vectors: []const TestVector = &.{ // S encoded with negative sign -> expected invalid .{ .key = "042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e", .msg = "313233343030", .sig = "304402202ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e180220b329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847db" }, @@ -1026,8 +1014,6 @@ test "Test vectors from Project Wycheproof - EcdsaP256Sha256 invalid" { } test "Test vectors from Project Wycheproof - EcdsaP384Sha384 valid" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const vectors: []const TestVector = &.{ // canonical sign-bit padding on R; canonical sign-bit padding on S -> expected valid .{ .key = "0429bdb76d5fa741bfd70233cb3a66cc7d44beb3b0663d92a8136650478bcefb61ef182e155a54345a5e8e5e88f064e5bc9a525ab7f764dad3dae1468c2b419f3b62b9ba917d5e8c4fb1ec47404a3fc76474b2713081be9db4c00e043ada9fc4a3", .msg = "4d7367", .sig = "3066023100d7143a836608b25599a7f28dec6635494c2992ad1e2bbeecb7ef601a9c01746e710ce0d9c48accb38a79ede5b9638f3402310080f9e165e8c61035bf8aa7b5533960e46dd0e211c904a064edb6de41f797c0eae4e327612ee3f816f4157272bb4fabc9" }, @@ -1243,8 +1229,6 @@ test "Test vectors from Project Wycheproof - EcdsaP384Sha384 valid" { } test "Test vectors from Project Wycheproof - EcdsaP384Sha384 invalid" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const vectors: []const TestVector = &.{ // S encoded with negative sign -> expected invalid .{ .key = "042da57dda1089276a543f9ffdac0bff0d976cad71eb7280e7d9bfd9fee4bdb2f20f47ff888274389772d98cc5752138aa4b6d054d69dcf3e25ec49df870715e34883b1836197d76f8ad962e78f6571bbc7407b0d6091f9e4d88f014274406174f", .msg = "313233343030", .sig = "3064023012b30abef6b5476fe6b612ae557c0425661e26b44b1bfe19daf2ca28e3113083ba8e4ae4cc45a0320abd3394f1c548d70230e7bf25603e2d07076ff30b7a2abec473da8b11c572b35fc631991d5de62ddca7525aaba89325dfd04fecc47bff426f82" }, @@ -1631,8 +1615,6 @@ fn tvTry(comptime Scheme: type, vector: TestVector) !void { } test "Sec1 encoding/decoding" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const io = testing.io; const Scheme = EcdsaP384Sha384; const kp = Scheme.KeyPair.generate(io); diff --git a/lib/std/crypto/ff.zig b/lib/std/crypto/ff.zig index bf9584dfa3ad033652130705937972171370669c..c59dc92c61d66a457aabd11175f9ee0c5f83e582 100644 --- a/lib/std/crypto/ff.zig +++ b/lib/std/crypto/ff.zig @@ -966,8 +966,6 @@ const ct_unprotected = struct { }; test "finite field arithmetic" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const M = Modulus(256); const m = try M.fromPrimitive(u256, 3429938563481314093726330772853735541133072814650493833233); var x = try M.Fe.fromPrimitive(u256, m, 80169837251094269539116136208111827396136208141182357733); @@ -1066,8 +1064,6 @@ test "finite field arithmetic" { } fn testCt(ct_: anytype) !void { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const l0: Limb = 0; const l1: Limb = 1; try testing.expectEqual(l1, ct_.select(true, l1, l0)); diff --git a/lib/std/crypto/ghash_polyval.zig b/lib/std/crypto/ghash_polyval.zig index 9f648c3fb34048f703f0346f96ea543d901a5d94..2ae68da1d654ee0a1ff33390637c5240a3f26aae 100644 --- a/lib/std/crypto/ghash_polyval.zig +++ b/lib/std/crypto/ghash_polyval.zig @@ -30,7 +30,7 @@ fn Hash(comptime endian: std.builtin.Endian, comptime shift_key: bool) type { pub const mac_length = 16; pub const key_length = 16; - const pc_count = if (builtin.mode != .ReleaseSmall) 16 else 2; + const pc_count = if (builtin.mode != .small) 16 else 2; const agg_4_threshold = 22; const agg_8_threshold = 84; const agg_16_threshold = 328; @@ -61,7 +61,7 @@ fn Hash(comptime endian: std.builtin.Endian, comptime shift_key: bool) type { hx[0] = h; hx[1] = reduce(clsq128(hx[0])); // h^2 - if (builtin.mode != .ReleaseSmall) { + if (builtin.mode != .small) { hx[2] = reduce(clmul128(hx[1], h)); // h^3 hx[3] = reduce(clsq128(hx[1])); // h^4 = h^2^2 if (block_count >= agg_8_threshold) { @@ -303,7 +303,7 @@ fn Hash(comptime endian: std.builtin.Endian, comptime shift_key: bool) type { var i: usize = 0; - if (builtin.mode != .ReleaseSmall and msg.len >= agg_16_threshold * block_length) { + if (builtin.mode != .small and msg.len >= agg_16_threshold * block_length) { // 16-blocks aggregated reduction while (i + 256 <= msg.len) : (i += 256) { var u = clmul128(acc ^ mem.readInt(u128, msg[i..][0..16], endian), st.hx[15 - 0]); @@ -313,7 +313,7 @@ fn Hash(comptime endian: std.builtin.Endian, comptime shift_key: bool) type { } acc = reduce(u); } - } else if (builtin.mode != .ReleaseSmall and msg.len >= agg_8_threshold * block_length) { + } else if (builtin.mode != .small and msg.len >= agg_8_threshold * block_length) { // 8-blocks aggregated reduction while (i + 128 <= msg.len) : (i += 128) { var u = clmul128(acc ^ mem.readInt(u128, msg[i..][0..16], endian), st.hx[7 - 0]); @@ -323,7 +323,7 @@ fn Hash(comptime endian: std.builtin.Endian, comptime shift_key: bool) type { } acc = reduce(u); } - } else if (builtin.mode != .ReleaseSmall and msg.len >= agg_4_threshold * block_length) { + } else if (builtin.mode != .small and msg.len >= agg_4_threshold * block_length) { // 4-blocks aggregated reduction while (i + 64 <= msg.len) : (i += 64) { var u = clmul128(acc ^ mem.readInt(u128, msg[i..][0..16], endian), st.hx[3 - 0]); diff --git a/lib/std/crypto/kangarootwelve.zig b/lib/std/crypto/kangarootwelve.zig index f43ae24c69172b000b2f7d4b420f03f93f505e64..b71d3c093d2fe980eb94781bbdb87705eb5c6f27 100644 --- a/lib/std/crypto/kangarootwelve.zig +++ b/lib/std/crypto/kangarootwelve.zig @@ -885,7 +885,7 @@ fn ktMultiThreaded( var select_outstanding: usize = 0; var select: Select = .init(io, select_buf); - defer select.cancel(); + defer select.cancelDiscard(); var batches_spawned: usize = 0; var next_to_process: usize = 0; @@ -1398,7 +1398,7 @@ test "KT128 sequential and parallel produce same output for many random lengths" var prng = std.Random.DefaultPrng.init(std.testing.random_seed); const random = prng.random(); - const num_tests = if (builtin.mode == .Debug) 10 else 1000; + const num_tests = if (builtin.mode == .debug) 10 else 1000; const max_length = 250000; for (0..num_tests) |_| { diff --git a/lib/std/crypto/keccak_p.zig b/lib/std/crypto/keccak_p.zig index 6aa2345aed5550d1d3a320887a8d99e4d115f277..b707833e2d7a5a56cc8c38cd989ff6bee5a9b0a1 100644 --- a/lib/std/crypto/keccak_p.zig +++ b/lib/std/crypto/keccak_p.zig @@ -202,7 +202,7 @@ pub fn State(comptime f: u11, comptime capacity: u11, comptime rounds: u5) type // In debug mode, track transitions to prevent insecure ones. const Op = enum { uninitialized, initialized, updated, absorb, squeeze }; - const TransitionTracker = if (mode == .Debug) struct { + const TransitionTracker = if (mode == .debug) struct { op: Op = .uninitialized, fn to(tracker: *@This(), next_op: Op) void { @@ -294,7 +294,7 @@ pub fn State(comptime f: u11, comptime capacity: u11, comptime rounds: u5) type /// Permute the state pub fn permute(self: *Self) void { - if (mode == .Debug) { + if (mode == .debug) { if (self.transition.op == .absorb and self.offset > 0) { @panic("cannot permute with pending input - call fillBlock() or pad() instead"); } diff --git a/lib/std/crypto/pcurves/p256/p256_64.zig b/lib/std/crypto/pcurves/p256/p256_64.zig index e79d51814e28ae67719c50354e4fe1c0a7061697..8cc9016ed38957ae5cd6647141dd0909dc3b90c3 100644 --- a/lib/std/crypto/pcurves/p256/p256_64.zig +++ b/lib/std/crypto/pcurves/p256/p256_64.zig @@ -110,7 +110,7 @@ fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { /// out1: [0x0 ~> 0xffffffffffffffff] /// out2: [0x0 ~> 0xffffffffffffffff] fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x = @as(u128, arg1) * @as(u128, arg2); out1.* = @as(u64, @truncate(x)); @@ -129,7 +129,7 @@ fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const mask = 0 -% @as(u64, arg1); out1.* = (mask & arg3) | ((~mask) & arg2); @@ -145,7 +145,7 @@ fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { /// 0 ≤ eval out1 < m /// pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -437,7 +437,7 @@ pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -730,7 +730,7 @@ pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEl /// 0 ≤ eval out1 < m /// pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -783,7 +783,7 @@ pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -826,7 +826,7 @@ pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -869,7 +869,7 @@ pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[0]); var x2: u64 = undefined; @@ -1022,7 +1022,7 @@ pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDo /// 0 ≤ eval out1 < m /// pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -1297,7 +1297,7 @@ pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDoma /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] pub fn nonzero(out1: *u64, arg1: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3])))); out1.* = x1; @@ -1315,7 +1315,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0])); @@ -1343,7 +1343,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[3]); const x2 = (arg1[2]); @@ -1452,7 +1452,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (@as(u64, (arg1[31])) << 56); const x2 = (@as(u64, (arg1[30])) << 48); @@ -1527,7 +1527,7 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void { /// 0 ≤ eval out1 < m /// pub fn setOne(out1: *MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = @as(u64, 0x1); out1[1] = 0xffffffff00000000; @@ -1544,7 +1544,7 @@ pub fn setOne(out1: *MontgomeryDomainFieldElement) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn msat(out1: *[5]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xffffffffffffffff; out1[1] = 0xffffffff; @@ -1582,7 +1582,7 @@ pub fn msat(out1: *[5]u64) void { /// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[4]u64, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: [4]u64, arg5: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -1816,7 +1816,7 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[ /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstepPrecomp(out1: *[4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0x67ffffffb8000000; out1[1] = 0xc000000038000000; diff --git a/lib/std/crypto/pcurves/p256/p256_scalar_64.zig b/lib/std/crypto/pcurves/p256/p256_scalar_64.zig index c549831b20e3260874f8c97179394b044b291741..db350196a4ca66f7624a39569b2d7e3296745821 100644 --- a/lib/std/crypto/pcurves/p256/p256_scalar_64.zig +++ b/lib/std/crypto/pcurves/p256/p256_scalar_64.zig @@ -110,7 +110,7 @@ fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { /// out1: [0x0 ~> 0xffffffffffffffff] /// out2: [0x0 ~> 0xffffffffffffffff] fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x = @as(u128, arg1) * @as(u128, arg2); out1.* = @as(u64, @truncate(x)); @@ -129,7 +129,7 @@ fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const mask = 0 -% @as(u64, arg1); out1.* = (mask & arg3) | ((~mask) & arg2); @@ -145,7 +145,7 @@ fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { /// 0 ≤ eval out1 < m /// pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -485,7 +485,7 @@ pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -826,7 +826,7 @@ pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEl /// 0 ≤ eval out1 < m /// pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -879,7 +879,7 @@ pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -922,7 +922,7 @@ pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -965,7 +965,7 @@ pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[0]); var x2: u64 = undefined; @@ -1178,7 +1178,7 @@ pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDo /// 0 ≤ eval out1 < m /// pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -1501,7 +1501,7 @@ pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDoma /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] pub fn nonzero(out1: *u64, arg1: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3])))); out1.* = x1; @@ -1519,7 +1519,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0])); @@ -1547,7 +1547,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[3]); const x2 = (arg1[2]); @@ -1656,7 +1656,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (@as(u64, (arg1[31])) << 56); const x2 = (@as(u64, (arg1[30])) << 48); @@ -1731,7 +1731,7 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void { /// 0 ≤ eval out1 < m /// pub fn setOne(out1: *MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xc46353d039cdaaf; out1[1] = 0x4319055258e8617b; @@ -1748,7 +1748,7 @@ pub fn setOne(out1: *MontgomeryDomainFieldElement) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn msat(out1: *[5]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xf3b9cac2fc632551; out1[1] = 0xbce6faada7179e84; @@ -1786,7 +1786,7 @@ pub fn msat(out1: *[5]u64) void { /// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[4]u64, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: [4]u64, arg5: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -2020,7 +2020,7 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[ /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstepPrecomp(out1: *[4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xd739262fb7fcfbb5; out1[1] = 0x8ac6f75d20074414; diff --git a/lib/std/crypto/pcurves/p384.zig b/lib/std/crypto/pcurves/p384.zig index 8bc0ec36f2d64e3c6d73e5d782b6df143c6a859f..7b97bf92b1b5ab138659e1348822d06885017fc5 100644 --- a/lib/std/crypto/pcurves/p384.zig +++ b/lib/std/crypto/pcurves/p384.zig @@ -56,7 +56,7 @@ pub const P384 = struct { } /// Create a point from serialized affine coordinates. - pub fn fromSerializedAffineCoordinates(xs: [48]u8, ys: [48]u8, endian: std.builtin.Endian) (NonCanonicalError || EncodingError)!P384 { + pub fn fromSerializedAffineCoordinates(xs: [48]u8, ys: [48]u8, endian: std.lang.Endian) (NonCanonicalError || EncodingError)!P384 { const x = try Fe.fromBytes(xs, endian); const y = try Fe.fromBytes(ys, endian); return fromAffineCoordinates(.{ .x = x, .y = y }); @@ -395,7 +395,7 @@ pub const P384 = struct { /// Multiply an elliptic curve point by a scalar. /// Return error.IdentityElement if the result is the identity element. - pub fn mul(p: P384, s_: [48]u8, endian: std.builtin.Endian) IdentityElementError!P384 { + pub fn mul(p: P384, s_: [48]u8, endian: std.lang.Endian) IdentityElementError!P384 { const s = if (endian == .little) s_ else Fe.orderSwap(s_); if (p.is_base) { return pcMul16(&basePointPc, s, false); @@ -407,7 +407,7 @@ pub const P384 = struct { /// Multiply an elliptic curve point by a *PUBLIC* scalar *IN VARIABLE TIME* /// This can be used for signature verification. - pub fn mulPublic(p: P384, s_: [48]u8, endian: std.builtin.Endian) IdentityElementError!P384 { + pub fn mulPublic(p: P384, s_: [48]u8, endian: std.lang.Endian) IdentityElementError!P384 { const s = if (endian == .little) s_ else Fe.orderSwap(s_); if (p.is_base) { return pcMul16(&basePointPc, s, true); @@ -419,7 +419,7 @@ pub const P384 = struct { /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME* /// This can be used for signature verification. - pub fn mulDoubleBasePublic(p1: P384, s1_: [48]u8, p2: P384, s2_: [48]u8, endian: std.builtin.Endian) IdentityElementError!P384 { + pub fn mulDoubleBasePublic(p1: P384, s1_: [48]u8, p2: P384, s2_: [48]u8, endian: std.lang.Endian) IdentityElementError!P384 { const s1 = if (endian == .little) s1_ else Fe.orderSwap(s1_); const s2 = if (endian == .little) s2_ else Fe.orderSwap(s2_); try p1.rejectIdentity(); @@ -478,7 +478,5 @@ pub const AffineCoordinates = struct { }; test { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; - _ = @import("tests/p384.zig"); } diff --git a/lib/std/crypto/pcurves/p384/p384_64.zig b/lib/std/crypto/pcurves/p384/p384_64.zig index d6f33028f73e744e048bb764b588bc7379868845..99d9dc82b2ba99d26de4c324c5c3ac239846a47a 100644 --- a/lib/std/crypto/pcurves/p384/p384_64.zig +++ b/lib/std/crypto/pcurves/p384/p384_64.zig @@ -79,7 +79,7 @@ fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { /// out1: [0x0 ~> 0xffffffffffffffff] /// out2: [0x0 ~> 0xffffffffffffffff] fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x = @as(u128, arg1) * @as(u128, arg2); out1.* = @as(u64, @truncate(x)); @@ -98,7 +98,7 @@ fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const mask = 0 -% @as(u64, arg1); out1.* = (mask & arg3) | ((~mask) & arg2); @@ -114,7 +114,7 @@ fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { /// 0 ≤ eval out1 < m /// pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -834,7 +834,7 @@ pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -1555,7 +1555,7 @@ pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEl /// 0 ≤ eval out1 < m /// pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -1626,7 +1626,7 @@ pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -1683,7 +1683,7 @@ pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -1740,7 +1740,7 @@ pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[0]); var x2: u64 = undefined; @@ -2225,7 +2225,7 @@ pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDo /// 0 ≤ eval out1 < m /// pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -2862,7 +2862,7 @@ pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDoma /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] pub fn nonzero(out1: *u64, arg1: [6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | ((arg1[3]) | ((arg1[4]) | (arg1[5])))))); out1.* = x1; @@ -2880,7 +2880,7 @@ pub fn nonzero(out1: *u64, arg1: [6]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn selectznz(out1: *[6]u64, arg1: u1, arg2: [6]u64, arg3: [6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0])); @@ -2914,7 +2914,7 @@ pub fn selectznz(out1: *[6]u64, arg1: u1, arg2: [6]u64, arg3: [6]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] pub fn toBytes(out1: *[48]u8, arg1: [6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[5]); const x2 = (arg1[4]); @@ -3069,7 +3069,7 @@ pub fn toBytes(out1: *[48]u8, arg1: [6]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn fromBytes(out1: *[6]u64, arg1: [48]u8) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (@as(u64, (arg1[47])) << 56); const x2 = (@as(u64, (arg1[46])) << 48); @@ -3176,7 +3176,7 @@ pub fn fromBytes(out1: *[6]u64, arg1: [48]u8) void { /// 0 ≤ eval out1 < m /// pub fn setOne(out1: *MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xffffffff00000001; out1[1] = 0xffffffff; @@ -3195,7 +3195,7 @@ pub fn setOne(out1: *MontgomeryDomainFieldElement) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn msat(out1: *[7]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xffffffff; out1[1] = 0xffffffff00000000; @@ -3235,7 +3235,7 @@ pub fn msat(out1: *[7]u64) void { /// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstep(out1: *u64, out2: *[7]u64, out3: *[7]u64, out4: *[6]u64, out5: *[6]u64, arg1: u64, arg2: [7]u64, arg3: [7]u64, arg4: [6]u64, arg5: [6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -3561,7 +3561,7 @@ pub fn divstep(out1: *u64, out2: *[7]u64, out3: *[7]u64, out4: *[6]u64, out5: *[ /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstepPrecomp(out1: *[6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xfff69400fff18fff; out1[1] = 0x2b7feffffd3ff; diff --git a/lib/std/crypto/pcurves/p384/p384_scalar_64.zig b/lib/std/crypto/pcurves/p384/p384_scalar_64.zig index 74f7e7813fed2a5bc0c685d5f9ba85e478ed3ce0..0b618e615442dfccd128b264029302205c286ecd 100644 --- a/lib/std/crypto/pcurves/p384/p384_scalar_64.zig +++ b/lib/std/crypto/pcurves/p384/p384_scalar_64.zig @@ -79,7 +79,7 @@ fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { /// out1: [0x0 ~> 0xffffffffffffffff] /// out2: [0x0 ~> 0xffffffffffffffff] fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x = @as(u128, arg1) * @as(u128, arg2); out1.* = @as(u64, @truncate(x)); @@ -98,7 +98,7 @@ fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const mask = 0 -% @as(u64, arg1); out1.* = (mask & arg3) | ((~mask) & arg2); @@ -114,7 +114,7 @@ fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { /// 0 ≤ eval out1 < m /// pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -834,7 +834,7 @@ pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -1555,7 +1555,7 @@ pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEl /// 0 ≤ eval out1 < m /// pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -1626,7 +1626,7 @@ pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -1683,7 +1683,7 @@ pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -1740,7 +1740,7 @@ pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[0]); var x2: u64 = undefined; @@ -2225,7 +2225,7 @@ pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDo /// 0 ≤ eval out1 < m /// pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -2916,7 +2916,7 @@ pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDoma /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] pub fn nonzero(out1: *u64, arg1: [6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | ((arg1[3]) | ((arg1[4]) | (arg1[5])))))); out1.* = x1; @@ -2934,7 +2934,7 @@ pub fn nonzero(out1: *u64, arg1: [6]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn selectznz(out1: *[6]u64, arg1: u1, arg2: [6]u64, arg3: [6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0])); @@ -2968,7 +2968,7 @@ pub fn selectznz(out1: *[6]u64, arg1: u1, arg2: [6]u64, arg3: [6]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] pub fn toBytes(out1: *[48]u8, arg1: [6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[5]); const x2 = (arg1[4]); @@ -3123,7 +3123,7 @@ pub fn toBytes(out1: *[48]u8, arg1: [6]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn fromBytes(out1: *[6]u64, arg1: [48]u8) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (@as(u64, (arg1[47])) << 56); const x2 = (@as(u64, (arg1[46])) << 48); @@ -3230,7 +3230,7 @@ pub fn fromBytes(out1: *[6]u64, arg1: [48]u8) void { /// 0 ≤ eval out1 < m /// pub fn setOne(out1: *MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0x1313e695333ad68d; out1[1] = 0xa7e5f24db74f5885; @@ -3249,7 +3249,7 @@ pub fn setOne(out1: *MontgomeryDomainFieldElement) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn msat(out1: *[7]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xecec196accc52973; out1[1] = 0x581a0db248b0a77a; @@ -3289,7 +3289,7 @@ pub fn msat(out1: *[7]u64) void { /// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstep(out1: *u64, out2: *[7]u64, out3: *[7]u64, out4: *[6]u64, out5: *[6]u64, arg1: u64, arg2: [7]u64, arg3: [7]u64, arg4: [6]u64, arg5: [6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -3615,7 +3615,7 @@ pub fn divstep(out1: *u64, out2: *[7]u64, out3: *[7]u64, out4: *[6]u64, out5: *[ /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstepPrecomp(out1: *[6]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0x49589ae0e6045b6a; out1[1] = 0x3c9a5352870040ed; diff --git a/lib/std/crypto/pcurves/secp256k1.zig b/lib/std/crypto/pcurves/secp256k1.zig index 9ce8b944ebbffc071bcdd3be90fa47463525289e..3c36b9b2ed49d45dc1a13c0d9aab2a69d6dd3398 100644 --- a/lib/std/crypto/pcurves/secp256k1.zig +++ b/lib/std/crypto/pcurves/secp256k1.zig @@ -51,7 +51,7 @@ pub const Secp256k1 = struct { }; /// Compute r1 and r2 so that k = r1 + r2*lambda (mod L). - pub fn splitScalar(s: [32]u8, endian: std.builtin.Endian) NonCanonicalError!SplitScalar { + pub fn splitScalar(s: [32]u8, endian: std.lang.Endian) NonCanonicalError!SplitScalar { const b1_neg_s = comptime s: { var buf: [32]u8 = undefined; mem.writeInt(u256, &buf, 303414439467246543595250775667605759171, .little); @@ -109,7 +109,7 @@ pub const Secp256k1 = struct { } /// Create a point from serialized affine coordinates. - pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: std.builtin.Endian) (NonCanonicalError || EncodingError)!Secp256k1 { + pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: std.lang.Endian) (NonCanonicalError || EncodingError)!Secp256k1 { const x = try Fe.fromBytes(xs, endian); const y = try Fe.fromBytes(ys, endian); return fromAffineCoordinates(.{ .x = x, .y = y }); @@ -423,7 +423,7 @@ pub const Secp256k1 = struct { /// Multiply an elliptic curve point by a scalar. /// Return error.IdentityElement if the result is the identity element. - pub fn mul(p: Secp256k1, s_: [32]u8, endian: std.builtin.Endian) IdentityElementError!Secp256k1 { + pub fn mul(p: Secp256k1, s_: [32]u8, endian: std.lang.Endian) IdentityElementError!Secp256k1 { const s = if (endian == .little) s_ else Fe.orderSwap(s_); if (p.is_base) { return pcMul16(&basePointPc, s, false); @@ -435,7 +435,7 @@ pub const Secp256k1 = struct { /// Multiply an elliptic curve point by a *PUBLIC* scalar *IN VARIABLE TIME* /// This can be used for signature verification. - pub fn mulPublic(p: Secp256k1, s_: [32]u8, endian: std.builtin.Endian) (IdentityElementError || NonCanonicalError)!Secp256k1 { + pub fn mulPublic(p: Secp256k1, s_: [32]u8, endian: std.lang.Endian) (IdentityElementError || NonCanonicalError)!Secp256k1 { const s = if (endian == .little) s_ else Fe.orderSwap(s_); const zero = comptime scalar.Scalar.zero.toBytes(.little); if (mem.eql(u8, &zero, &s)) { @@ -497,7 +497,7 @@ pub const Secp256k1 = struct { /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME* /// This can be used for signature verification. - pub fn mulDoubleBasePublic(p1: Secp256k1, s1_: [32]u8, p2: Secp256k1, s2_: [32]u8, endian: std.builtin.Endian) IdentityElementError!Secp256k1 { + pub fn mulDoubleBasePublic(p1: Secp256k1, s1_: [32]u8, p2: Secp256k1, s2_: [32]u8, endian: std.lang.Endian) IdentityElementError!Secp256k1 { const s1 = if (endian == .little) s1_ else Fe.orderSwap(s1_); const s2 = if (endian == .little) s2_ else Fe.orderSwap(s2_); try p1.rejectIdentity(); @@ -556,7 +556,5 @@ pub const AffineCoordinates = struct { }; test { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; - _ = @import("tests/secp256k1.zig"); } diff --git a/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig b/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig index 547da19bea45f80db08cd2bc1d5172265cecd72a..8decda2f2525f288583ced40b12c7413862ebf6d 100644 --- a/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig +++ b/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig @@ -79,7 +79,7 @@ fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { /// out1: [0x0 ~> 0xffffffffffffffff] /// out2: [0x0 ~> 0xffffffffffffffff] fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x = @as(u128, arg1) * @as(u128, arg2); out1.* = @as(u64, @truncate(x)); @@ -98,7 +98,7 @@ fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const mask = 0 -% @as(u64, arg1); out1.* = (mask & arg3) | ((~mask) & arg2); @@ -114,7 +114,7 @@ fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { /// 0 ≤ eval out1 < m /// pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -454,7 +454,7 @@ pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -795,7 +795,7 @@ pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEl /// 0 ≤ eval out1 < m /// pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -848,7 +848,7 @@ pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -891,7 +891,7 @@ pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -934,7 +934,7 @@ pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[0]); var x2: u64 = undefined; @@ -1167,7 +1167,7 @@ pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDo /// 0 ≤ eval out1 < m /// pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -1430,7 +1430,7 @@ pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDoma /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] pub fn nonzero(out1: *u64, arg1: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3])))); out1.* = x1; @@ -1448,7 +1448,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0])); @@ -1476,7 +1476,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[3]); const x2 = (arg1[2]); @@ -1585,7 +1585,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (@as(u64, (arg1[31])) << 56); const x2 = (@as(u64, (arg1[30])) << 48); @@ -1660,7 +1660,7 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void { /// 0 ≤ eval out1 < m /// pub fn setOne(out1: *MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0x1000003d1; out1[1] = 0x0; @@ -1677,7 +1677,7 @@ pub fn setOne(out1: *MontgomeryDomainFieldElement) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn msat(out1: *[5]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xfffffffefffffc2f; out1[1] = 0xffffffffffffffff; @@ -1715,7 +1715,7 @@ pub fn msat(out1: *[5]u64) void { /// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[4]u64, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: [4]u64, arg5: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -1949,7 +1949,7 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[ /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstepPrecomp(out1: *[4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xf201a41831525e0a; out1[1] = 0x9953f9ddcd648d85; diff --git a/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig b/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig index 71e6f1baba7bd6107d85097e2ce297402f4a475a..09bfc15a10d44970b38d7f51b802a28cb908afe5 100644 --- a/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig +++ b/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig @@ -79,7 +79,7 @@ fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { /// out1: [0x0 ~> 0xffffffffffffffff] /// out2: [0x0 ~> 0xffffffffffffffff] fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x = @as(u128, arg1) * @as(u128, arg2); out1.* = @as(u64, @truncate(x)); @@ -98,7 +98,7 @@ fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const mask = 0 -% @as(u64, arg1); out1.* = (mask & arg3) | ((~mask) & arg2); @@ -114,7 +114,7 @@ fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { /// 0 ≤ eval out1 < m /// pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -454,7 +454,7 @@ pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -795,7 +795,7 @@ pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEl /// 0 ≤ eval out1 < m /// pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -848,7 +848,7 @@ pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -891,7 +891,7 @@ pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -934,7 +934,7 @@ pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldEleme /// 0 ≤ eval out1 < m /// pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[0]); var x2: u64 = undefined; @@ -1167,7 +1167,7 @@ pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDo /// 0 ≤ eval out1 < m /// pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[1]); const x2 = (arg1[2]); @@ -1490,7 +1490,7 @@ pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDoma /// Output Bounds: /// out1: [0x0 ~> 0xffffffffffffffff] pub fn nonzero(out1: *u64, arg1: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3])))); out1.* = x1; @@ -1508,7 +1508,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0])); @@ -1536,7 +1536,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (arg1[3]); const x2 = (arg1[2]); @@ -1645,7 +1645,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); const x1 = (@as(u64, (arg1[31])) << 56); const x2 = (@as(u64, (arg1[30])) << 48); @@ -1720,7 +1720,7 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void { /// 0 ≤ eval out1 < m /// pub fn setOne(out1: *MontgomeryDomainFieldElement) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0x402da1732fc9bebf; out1[1] = 0x4551231950b75fc4; @@ -1737,7 +1737,7 @@ pub fn setOne(out1: *MontgomeryDomainFieldElement) void { /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn msat(out1: *[5]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xbfd25e8cd0364141; out1[1] = 0xbaaedce6af48a03b; @@ -1775,7 +1775,7 @@ pub fn msat(out1: *[5]u64) void { /// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] /// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[4]u64, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: [4]u64, arg5: [4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); var x1: u64 = undefined; var x2: u1 = undefined; @@ -2009,7 +2009,7 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[ /// Output Bounds: /// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] pub fn divstepPrecomp(out1: *[4]u64) void { - @setRuntimeSafety(mode == .Debug); + @setRuntimeSafety(mode == .debug); out1[0] = 0xd7431a4d2b9cb4e9; out1[1] = 0xab67d35a32d9c503; diff --git a/lib/std/crypto/tls/Client.zig b/lib/std/crypto/tls/Client.zig index 1eb3aca852c0fb6025ee35dcf7cee896606af4df..0fbb28661ac560b14aa17f90bda007cbea574191 100644 --- a/lib/std/crypto/tls/Client.zig +++ b/lib/std/crypto/tls/Client.zig @@ -1588,7 +1588,7 @@ const CertificatePublicKey = struct { inline 128, 256, 384, 512 => |modulus_len| { const key: PublicKey = try .fromBytes(exponent, modulus); const sig = RsaSignature.fromBytes(modulus_len, encoded_sig); - try RsaSignature.concatVerify(modulus_len, sig, msg, key, Hash); + try RsaSignature.concatVerify(modulus_len, &sig, msg, key, Hash); }, else => return error.TlsBadRsaSignatureBitCount, } diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 9a83de8e1061d603b3e82c80d6e84cc8a640441b..59a8dcd9eae1cf7ba40a1e5e9c50a683186c322c 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -151,6 +151,10 @@ pub fn FullPanic(comptime panicFn: fn ([]const u8, ?usize) noreturn) type { @branchHint(.cold); call("invalid error code", @returnAddress()); } + pub fn unexpectedErrorCode(err: anyerror) noreturn { + @branchHint(.cold); + std.debug.panicExtra(@returnAddress(), "unexpected error code, found error.{s}", .{@errorName(err)}); + } pub fn integerOutOfBounds() noreturn { @branchHint(.cold); call("integer does not fit in destination type", @returnAddress()); @@ -207,6 +211,10 @@ pub fn FullPanic(comptime panicFn: fn ([]const u8, ?usize) noreturn) type { @branchHint(.cold); call("'noreturn' function returned", @returnAddress()); } + pub fn loadUninstantiableType() noreturn { + @branchHint(.cold); + call("attempt to load uninstantiable type", @returnAddress()); + } }; } @@ -237,13 +245,12 @@ pub const Symbol = struct { }; }; -/// Deprecated because it returns the optimization mode of the standard -/// library, when the caller probably wants to use the optimization mode of -/// their own module. -pub const runtime_safety = switch (builtin.mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, -}; +/// Deprecated in favor of `std.lang.Optimize.runtimeSafety`, to be removed after 0.18.0 +/// +/// Returns whether the standard library has safety checks enabled. Callsites +/// likely would rather know whether their own module's optimization mode +/// (found via `@import("builtin").optimize`) has safety checks enabled. +pub const runtime_safety = builtin.mode.runtimeSafety(); /// Whether we can unwind the stack on this target, allowing capturing and/or printing the current /// stack trace. It is still legal to call `captureCurrentStackTrace`, `writeCurrentStackTrace`, and @@ -257,7 +264,7 @@ pub const sys_can_stack_trace = switch (builtin.cpu.arch) { // because Emscripten's implementation is very slow. .wasm32, .wasm64, - => native_os == .emscripten and builtin.mode == .Debug, + => native_os == .emscripten and builtin.mode == .debug, // `@returnAddress()` is unsupported in LLVM 21. .bpfel, @@ -419,16 +426,16 @@ pub const CpuContextPtr = if (cpu_context.Native == noreturn) noreturn else *con /// Invokes detectable illegal behavior when `ok` is `false`. /// -/// In Debug and ReleaseSafe modes, calls to this function are always +/// In debug and safe modes, calls to this function are always /// generated, and the `unreachable` statement triggers a panic. /// -/// In ReleaseFast and ReleaseSmall modes, calls to this function are optimized +/// In fast and small modes, calls to this function are optimized /// away, and in fact the optimizer is able to use the assertion in its /// heuristics. /// /// Inside a test block, it is best to use the `testing` module rather than /// this function, because this function may not detect a test failure in -/// ReleaseFast and ReleaseSmall mode. Outside of a test block, this assert +/// fast and small mode. Outside of a test block, this assert /// function is the correct function to use. pub fn assert(ok: bool) void { @disableInstrumentation(); @@ -1760,7 +1767,7 @@ test "manage resources correctly" { /// In release mode, it is size 0 and all methods are no-ops. /// This is a pre-made type with default settings. /// For more advanced usage, see `ConfigurableTrace`. -pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .Debug); +pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .debug); pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize, comptime is_enabled: bool) type { return struct { diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 75b6d71f2d488fdf24fd53c96bab1fa5d8bb4573..2d6e2204a340effe84ef4d2c00f1b87ea5cc1a5c 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -450,6 +450,7 @@ fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void { unit_header.format, endian, address_size, + version, )) orelse continue; switch (die_obj.tag_id) { @@ -485,6 +486,7 @@ fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void { unit_header.format, endian, address_size, + version, )) orelse return bad(); } else if (this_die_obj.getAttr(AT.specification)) |_| { const after_die_offset = fr.seek; @@ -500,6 +502,7 @@ fn scanAllFunctions(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!void { unit_header.format, endian, address_size, + version, )) orelse return bad(); } else { break :x null; @@ -611,6 +614,7 @@ fn scanAllCompileUnits(di: *Dwarf, gpa: Allocator, endian: Endian) ScanError!voi unit_header.format, endian, address_size, + version, )) orelse return bad(); if (compile_unit_die.tag_id != DW.TAG.compile_unit) return bad(); @@ -931,6 +935,7 @@ fn parseDie( format: Format, endian: Endian, addr_size_bytes: u8, + version: u16, ) ScanError!?Die { const abbrev_code = try fr.takeLeb128(u64); if (abbrev_code == 0) return null; @@ -939,7 +944,7 @@ fn parseDie( const attrs = attrs_buf[0..table_entry.attrs.len]; for (attrs, table_entry.attrs) |*result_attr, attr| result_attr.* = .{ .id = attr.id, - .value = try parseFormValue(fr, attr.form_id, format, endian, addr_size_bytes, attr.payload), + .value = try parseFormValue(fr, attr.form_id, format, endian, addr_size_bytes, attr.payload, version), }; return .{ .tag_id = table_entry.tag_id, @@ -1042,7 +1047,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit: for (try directories.addManyAsSlice(gpa, directories_count)) |*e| { e.* = .{ .path = &.{} }; for (dir_ent_fmt_buf[0..directory_entry_format_count]) |ent_fmt| { - const form_value = try parseFormValue(&fr, ent_fmt.form_code, unit_header.format, endian, addr_size_bytes, null); + const form_value = try parseFormValue(&fr, ent_fmt.form_code, unit_header.format, endian, addr_size_bytes, null, version); switch (ent_fmt.content_type_code) { DW.LNCT.path => e.path = try form_value.getString(d.*), DW.LNCT.directory_index => e.dir_index = try form_value.getUInt(u32), @@ -1074,7 +1079,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, endian: Endian, compile_unit: for (try file_entries.addManyAsSlice(gpa, file_names_count)) |*e| { e.* = .{ .path = &.{} }; for (file_ent_fmt_buf[0..file_name_entry_format_count]) |ent_fmt| { - const form_value = try parseFormValue(&fr, ent_fmt.form_code, unit_header.format, endian, addr_size_bytes, null); + const form_value = try parseFormValue(&fr, ent_fmt.form_code, unit_header.format, endian, addr_size_bytes, null, version); switch (ent_fmt.content_type_code) { DW.LNCT.path => e.path = try form_value.getString(d.*), DW.LNCT.directory_index => e.dir_index = try form_value.getUInt(u32), @@ -1285,6 +1290,7 @@ fn parseFormValue( endian: Endian, addr_size_bytes: u8, implicit_const: ?i64, + version: u16, ) ScanError!FormValue { return switch (form_id) { // DWARF5.pdf page 213: the size of this value is encoded in the @@ -1319,7 +1325,12 @@ fn parseFormValue( FORM.ref8 => .{ .ref = try r.takeInt(u64, endian) }, FORM.ref_udata => .{ .ref = try r.takeLeb128(u64) }, - FORM.ref_addr => .{ .ref_addr = try readFormatSizedInt(r, format, endian) }, + FORM.ref_addr => .{ + .ref_addr = switch (version) { + 2 => try readAddress(r, endian, addr_size_bytes), + else => try readFormatSizedInt(r, format, endian), + }, + }, FORM.ref_sig8 => .{ .ref = try r.takeInt(u64, endian) }, FORM.string => .{ .string = try r.takeSentinel(0) }, @@ -1330,7 +1341,7 @@ fn parseFormValue( FORM.strx4 => .{ .strx = try r.takeInt(u32, endian) }, FORM.strx => .{ .strx = try r.takeLeb128(usize) }, FORM.line_strp => .{ .line_strp = try readFormatSizedInt(r, format, endian) }, - FORM.indirect => parseFormValue(r, try r.takeLeb128(u64), format, endian, addr_size_bytes, implicit_const), + FORM.indirect => parseFormValue(r, try r.takeLeb128(u64), format, endian, addr_size_bytes, implicit_const, version), FORM.implicit_const => .{ .sdata = implicit_const orelse return bad() }, FORM.loclistx => .{ .loclistx = try r.takeLeb128(u64) }, FORM.rnglistx => .{ .rnglistx = try r.takeLeb128(u64) }, diff --git a/lib/std/debug/MachOFile.zig b/lib/std/debug/MachOFile.zig index 158e908183715fd06876b1191d4cad0cf2cd5301..220876105ec527ba88a3e3b8fb02353741ff3055 100644 --- a/lib/std/debug/MachOFile.zig +++ b/lib/std/debug/MachOFile.zig @@ -2,6 +2,8 @@ mapped_memory: []align(std.heap.page_size_min) const u8, symbols: []const Symbol, strings: []const u8, text_vmaddr: u64, +uuid: ?Uuid, +adjacent_dsym: ?DsymFile, /// Key is index into `strings` of the file path. ofiles: std.array_hash_map.Auto(u32, Error!OFile), @@ -16,6 +18,7 @@ pub const Error = error{ }; pub fn deinit(mf: *MachOFile, gpa: Allocator) void { + if (mf.adjacent_dsym) |*dsym| dsym.deinit(gpa); for (mf.ofiles.values()) |*maybe_of| { const of = &(maybe_of.* catch continue); posix.munmap(of.mapped_memory); @@ -36,48 +39,7 @@ pub fn load(gpa: Allocator, io: Io, path: []const u8, arch: std.Target.Cpu.Arch) const all_mapped_memory = try mapDebugInfoFile(io, path); errdefer posix.munmap(all_mapped_memory); - // In most cases, the file we just mapped is a Mach-O binary. However, it could be a "universal - // binary": a simple file format which contains Mach-O binaries for multiple targets. For - // instance, `/usr/lib/dyld` is currently distributed as a universal binary containing images - // for both ARM64 macOS and x86_64 macOS. - if (all_mapped_memory.len < 4) return error.InvalidMachO; - const magic = std.mem.readInt(u32, all_mapped_memory.ptr[0..4], .little); - - // The contents of a Mach-O file, which may or may not be the whole of `all_mapped_memory`. - const mapped_macho = switch (magic) { - macho.MH_MAGIC_64 => all_mapped_memory, - - macho.FAT_CIGAM => mapped_macho: { - // This is the universal binary format (aka a "fat binary"). - var fat_r: Io.Reader = .fixed(all_mapped_memory); - const hdr = fat_r.takeStruct(macho.fat_header, .big) catch |err| switch (err) { - error.ReadFailed => unreachable, - error.EndOfStream => return error.InvalidMachO, - }; - const want_cpu_type = switch (arch) { - .x86_64 => macho.CPU_TYPE_X86_64, - .aarch64 => macho.CPU_TYPE_ARM64, - else => unreachable, - }; - for (0..hdr.nfat_arch) |_| { - const fat_arch = fat_r.takeStruct(macho.fat_arch, .big) catch |err| switch (err) { - error.ReadFailed => unreachable, - error.EndOfStream => return error.InvalidMachO, - }; - if (fat_arch.cputype != want_cpu_type) continue; - if (fat_arch.offset + fat_arch.size > all_mapped_memory.len) return error.InvalidMachO; - break :mapped_macho all_mapped_memory[fat_arch.offset..][0..fat_arch.size]; - } - // `arch` was not present in the fat binary. - return error.MissingDebugInfo; - }, - - // Even on modern 64-bit targets, this format doesn't seem to be too extensively used. It - // will be fairly easy to add support here if necessary; it's very similar to above. - macho.FAT_CIGAM_64 => return error.UnsupportedDebugInfo, - - else => return error.InvalidMachO, - }; + const mapped_macho = try selectMachOSlice(all_mapped_memory, arch); var r: Io.Reader = .fixed(mapped_macho); const hdr = r.takeStruct(macho.mach_header_64, .little) catch |err| switch (err) { @@ -88,21 +50,26 @@ pub fn load(gpa: Allocator, io: Io, path: []const u8, arch: std.Target.Cpu.Arch) if (hdr.magic != macho.MH_MAGIC_64) return error.InvalidMachO; - const symtab: macho.symtab_command, const text_vmaddr: u64 = lcs: { + const symtab: macho.symtab_command, const text_vmaddr: u64, const uuid: ?Uuid = lcs: { var it: macho.LoadCommandIterator = try .init(&hdr, mapped_macho[@sizeOf(macho.mach_header_64)..]); var symtab: ?macho.symtab_command = null; var text_vmaddr: ?u64 = null; + var uuid: ?Uuid = null; while (try it.next()) |cmd| switch (cmd.hdr.cmd) { .SYMTAB => symtab = cmd.cast(macho.symtab_command) orelse return error.InvalidMachO, .SEGMENT_64 => if (cmd.cast(macho.segment_command_64)) |seg_cmd| { if (!mem.eql(u8, seg_cmd.segName(), "__TEXT")) continue; text_vmaddr = seg_cmd.vmaddr; }, + .UUID => if (cmd.cast(macho.uuid_command)) |uuid_cmd| { + uuid = uuid_cmd.uuid; + }, else => {}, }; break :lcs .{ symtab orelse return error.MissingDebugInfo, text_vmaddr orelse return error.MissingDebugInfo, + uuid, }; }; @@ -253,15 +220,27 @@ pub fn load(gpa: Allocator, io: Io, path: []const u8, arch: std.Target.Cpu.Arch) // This sort is so that we can binary search later. mem.sort(Symbol, symbols_slice, {}, Symbol.addressLessThan); + const adjacent_dsym = if (uuid) |expected_uuid| + try loadAdjacentDsym(gpa, io, path, arch, expected_uuid) + else + null; + return .{ .mapped_memory = all_mapped_memory, .symbols = symbols_slice, .strings = strings, .ofiles = .empty, .text_vmaddr = text_vmaddr, + .uuid = uuid, + .adjacent_dsym = adjacent_dsym, }; } + pub fn getDwarfForAddress(mf: *MachOFile, gpa: Allocator, io: Io, vaddr: u64) !struct { *Dwarf, u64 } { + if (mf.adjacent_dsym) |*dsym| { + return .{ &dsym.dwarf, vaddr }; + } + const symbol = Symbol.find(mf.symbols, vaddr) orelse return error.MissingDebugInfo; if (symbol.ofile == Symbol.unknown_ofile) return error.MissingDebugInfo; @@ -324,6 +303,16 @@ const OFile = struct { }; }; +const DsymFile = struct { + mapped_memory: []align(std.heap.page_size_min) const u8, + dwarf: Dwarf, + + fn deinit(df: *DsymFile, gpa: Allocator) void { + df.dwarf.deinit(gpa); + posix.munmap(df.mapped_memory); + } +}; + const Symbol = struct { strx: u32, addr: u64, @@ -394,6 +383,74 @@ fn appendStabSymbol( } } +fn loadAdjacentDsym( + gpa: Allocator, + io: Io, + binary_path: []const u8, + arch: std.Target.Cpu.Arch, + uuid: Uuid, +) Error!?DsymFile { + const s = std.fs.path.sep_str; + const dsym_path = try std.fmt.allocPrint( + gpa, + "{s}.dSYM" ++ s ++ "Contents" ++ s ++ "Resources" ++ s ++ "DWARF" ++ s ++ "{s}", + .{ binary_path, std.fs.path.basename(binary_path) }, + ); + defer gpa.free(dsym_path); + return loadDsymFile(gpa, io, dsym_path, arch, uuid) catch |err| switch (err) { + error.MissingDebugInfo, + error.InvalidMachO, + error.InvalidDwarf, + error.UnsupportedDebugInfo, + error.ReadFailed, + => null, + error.OutOfMemory => |e| return e, + }; +} + +fn loadDsymFile( + gpa: Allocator, + io: Io, + path: []const u8, + arch: std.Target.Cpu.Arch, + expected_uuid: Uuid, +) Error!DsymFile { + const all_mapped_memory = try mapDebugInfoFile(io, path); + errdefer posix.munmap(all_mapped_memory); + const mapped_macho = try selectMachOSlice(all_mapped_memory, arch); + + var r: Io.Reader = .fixed(mapped_macho); + const hdr = r.takeStruct(macho.mach_header_64, .little) catch |err| switch (err) { + error.ReadFailed => unreachable, + error.EndOfStream => return error.InvalidMachO, + }; + if (hdr.magic != macho.MH_MAGIC_64) return error.InvalidMachO; + if (hdr.filetype != macho.MH_DSYM) return error.MissingDebugInfo; + + var uuid: ?Uuid = null; + var dwarf_sections: ?[]align(1) const macho.section_64 = null; + + var it: macho.LoadCommandIterator = try .init(&hdr, mapped_macho[@sizeOf(macho.mach_header_64)..]); + while (try it.next()) |lc| switch (lc.hdr.cmd) { + .SEGMENT_64 => if (lc.cast(macho.segment_command_64)) |seg_cmd| { + if (!mem.eql(u8, "__DWARF", seg_cmd.segName())) continue; + dwarf_sections = lc.getSections(); + }, + .UUID => if (lc.cast(macho.uuid_command)) |uuid_cmd| { + uuid = uuid_cmd.uuid; + }, + else => {}, + }; + + const actual_uuid = uuid orelse return error.MissingDebugInfo; + if (!mem.eql(u8, &actual_uuid, &expected_uuid)) return error.MissingDebugInfo; + + return .{ + .mapped_memory = all_mapped_memory, + .dwarf = try loadDwarfFromSections(gpa, mapped_macho, dwarf_sections orelse return error.MissingDebugInfo), + }; +} + fn loadOFile(gpa: Allocator, io: Io, o_file_name: []const u8) !OFile { const all_mapped_memory, const mapped_ofile = map: { const open_paren = paren: { @@ -497,19 +554,38 @@ fn loadOFile(gpa: Allocator, io: Io, o_file_name: []const u8) !OFile { gop.key_ptr.* = @intCast(sym_index); } + const dwarf = try loadDwarfFromSections(gpa, mapped_ofile, seg_cmd.getSections()); + + return .{ + .mapped_memory = all_mapped_memory, + .dwarf = dwarf, + .strtab = strtab, + .symtab_raw = symtab_raw, + .symbols_by_name = symbols_by_name.move(), + }; +} + +fn loadDwarfFromSections( + gpa: Allocator, + mapped_macho: []const u8, + section_headers: []align(1) const macho.section_64, +) !Dwarf { var sections: Dwarf.SectionArray = @splat(null); - for (seg_cmd.getSections()) |sect_raw| { + for (section_headers) |sect_raw| { var sect = sect_raw; if (builtin.cpu.arch.endian() != .little) std.mem.byteSwapAllFields(macho.section_64, §); if (!std.mem.eql(u8, "__DWARF", sect.segName())) continue; - const section_index: usize = inline for (@typeInfo(Dwarf.Section.Id).@"enum".field_names, 0..) |section_name, i| { - if (mem.eql(u8, "__" ++ section_name, sect.sectName())) break i; + const section_index: usize = inline for (@typeInfo(Dwarf.Section.Id).@"enum".field_names, 0..) |field_name, i| { + const section_name_long = "__" ++ field_name; + // Some dwarf section names don't fit in the `sectname` buffer, so they are truncated. + const section_name_trunc = section_name_long[0..@min(section_name_long.len, sect.sectname.len)]; + if (mem.eql(u8, section_name_trunc, sect.sectName())) break i; } else continue; - if (mapped_ofile.len < sect.offset + sect.size) return error.InvalidMachO; - const section_bytes = mapped_ofile[sect.offset..][0..sect.size]; + if (mapped_macho.len < sect.offset + sect.size) return error.InvalidMachO; + const section_bytes = mapped_macho[sect.offset..][0..sect.size]; sections[section_index] = .{ .data = section_bytes, .owned = false, @@ -539,13 +615,56 @@ fn loadOFile(gpa: Allocator, io: Io, o_file_name: []const u8) !OFile { => |e| return e, }; - return .{ - .mapped_memory = all_mapped_memory, - .dwarf = dwarf, - .strtab = strtab, - .symtab_raw = symtab_raw, - .symbols_by_name = symbols_by_name.move(), + return dwarf; +} + +fn selectMachOSlice( + all_mapped_memory: []align(std.heap.page_size_min) const u8, + arch: std.Target.Cpu.Arch, +) Error![]const u8 { + // In most cases, the file we just mapped is a Mach-O binary. However, it could be a "universal + // binary": a simple file format which contains Mach-O binaries for multiple targets. For + // instance, `/usr/lib/dyld` is currently distributed as a universal binary containing images + // for both ARM64 macOS and x86_64 macOS. + if (all_mapped_memory.len < 4) return error.InvalidMachO; + const magic = std.mem.readInt(u32, all_mapped_memory.ptr[0..4], .little); + + // The contents of a Mach-O file, which may or may not be the whole of `all_mapped_memory`. + const mapped_macho = switch (magic) { + macho.MH_MAGIC_64 => all_mapped_memory, + + macho.FAT_CIGAM => mapped_macho: { + // This is the universal binary format (aka a "fat binary"). + var fat_r: Io.Reader = .fixed(all_mapped_memory); + const hdr = fat_r.takeStruct(macho.fat_header, .big) catch |err| switch (err) { + error.ReadFailed => unreachable, + error.EndOfStream => return error.InvalidMachO, + }; + const want_cpu_type = switch (arch) { + .x86_64 => macho.CPU_TYPE_X86_64, + .aarch64 => macho.CPU_TYPE_ARM64, + else => unreachable, + }; + for (0..hdr.nfat_arch) |_| { + const fat_arch = fat_r.takeStruct(macho.fat_arch, .big) catch |err| switch (err) { + error.ReadFailed => unreachable, + error.EndOfStream => return error.InvalidMachO, + }; + if (fat_arch.cputype != want_cpu_type) continue; + if (fat_arch.offset + fat_arch.size > all_mapped_memory.len) return error.InvalidMachO; + break :mapped_macho all_mapped_memory[fat_arch.offset..][0..fat_arch.size]; + } + // `arch` was not present in the fat binary. + return error.MissingDebugInfo; + }, + + // Even on modern 64-bit targets, this format doesn't seem to be too extensively used. It + // will be fairly easy to add support here if necessary; it's very similar to above. + macho.FAT_CIGAM_64 => return error.UnsupportedDebugInfo, + + else => return error.InvalidMachO, }; + return mapped_macho; } /// Uses `mmap` to map the file at `path` into memory. @@ -583,4 +702,5 @@ const testing = std.testing; const builtin = @import("builtin"); +const Uuid = @FieldType(macho.uuid_command, "uuid"); const MachOFile = @This(); diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 7a81b4cba894fd238d72e5e1c74cdc3df8ae176a..398a3f95a8933d489f67e3c9958084f2ed4e5660 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -428,6 +428,9 @@ fn findModule(si: *SelfInfo, gpa: Allocator, io: Io, address: usize, lock: enum // Rebuild module list with the exclusive lock. { errdefer si.rwlock.unlock(io); + if (si.unwind_cache) |cache| { + @memset(cache, .empty); + } for (si.modules.items) |*mod| { unwind: { const u = &(mod.unwind orelse break :unwind catch break :unwind); @@ -515,7 +518,7 @@ const DlIterContext = struct { for (info.phdr[0..info.phnum]) |phdr| { if (phdr.type != .LOAD) continue; try context.si.ranges.append(gpa, .{ - // Overflowing addition handles VSDOs having p_vaddr = 0xffffffffff700000 + // Overflowing addition handles VSDOs having vaddr = 0xffffffffff700000 .start = info.addr +% phdr.vaddr, .len = phdr.memsz, .module_index = module_index, diff --git a/lib/std/debug/cpu_context.zig b/lib/std/debug/cpu_context.zig index 36be9fe60e0ebe084ab2e045702bc91628ff9bf6..ab90b9b2c27e374ef56148334eb83fcc13d6ba75 100644 --- a/lib/std/debug/cpu_context.zig +++ b/lib/std/debug/cpu_context.zig @@ -2020,6 +2020,8 @@ const signal_ucontext_t = switch (native_os) { .mips64el, .or1k, .s390x, + .sh, + .sheb, .x86, .x86_64, .xtensa, diff --git a/lib/std/debug/no_panic.zig b/lib/std/debug/no_panic.zig index f24317b9b7d66ae9076df3d4790cfa88d47e1a26..772fb7e496c44a4bf9f566ff17d49826b319cceb 100644 --- a/lib/std/debug/no_panic.zig +++ b/lib/std/debug/no_panic.zig @@ -65,6 +65,11 @@ pub fn invalidErrorCode() noreturn { @trap(); } +pub fn unexpectedErrorCode(_: anyerror) noreturn { + @branchHint(.cold); + @trap(); +} + pub fn integerOutOfBounds() noreturn { @branchHint(.cold); @trap(); @@ -134,3 +139,8 @@ pub fn noreturnReturned() noreturn { @branchHint(.cold); @trap(); } + +pub fn loadUninstantiableType() noreturn { + @branchHint(.cold); + @trap(); +} diff --git a/lib/std/debug/simple_panic.zig b/lib/std/debug/simple_panic.zig index a5a09fa1162e75cf9aad5a69a1bfcd3a3e1845d9..8453aadbb985766f749199c0bac617cb858afe04 100644 --- a/lib/std/debug/simple_panic.zig +++ b/lib/std/debug/simple_panic.zig @@ -20,109 +20,144 @@ pub fn call(msg: []const u8, ra: ?usize) noreturn { } pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn { + @branchHint(.cold); _ = found; call("sentinel mismatch", null); } pub fn unwrapError(err: anyerror) noreturn { + @branchHint(.cold); _ = &err; call("attempt to unwrap error", null); } pub fn outOfBounds(index: usize, len: usize) noreturn { + @branchHint(.cold); _ = index; _ = len; call("index out of bounds", null); } pub fn startGreaterThanEnd(start: usize, end: usize) noreturn { + @branchHint(.cold); _ = start; _ = end; call("start index is larger than end index", null); } pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn { + @branchHint(.cold); _ = accessed; call("access of inactive union field", null); } pub fn sliceCastLenRemainder(src_len: usize) noreturn { + @branchHint(.cold); _ = src_len; call("slice length does not divide exactly into destination elements", null); } pub fn reachedUnreachable() noreturn { + @branchHint(.cold); call("reached unreachable code", null); } pub fn unwrapNull() noreturn { + @branchHint(.cold); call("attempt to use null value", null); } pub fn castToNull() noreturn { + @branchHint(.cold); call("cast causes pointer to be null", null); } pub fn incorrectAlignment() noreturn { + @branchHint(.cold); call("incorrect alignment", null); } pub fn invalidErrorCode() noreturn { + @branchHint(.cold); call("invalid error code", null); } +pub fn unexpectedErrorCode(err: anyerror) noreturn { + @branchHint(.cold); + _ = err; + call("unexpected error code", null); +} + pub fn integerOutOfBounds() noreturn { + @branchHint(.cold); call("integer does not fit in destination type", null); } pub fn integerOverflow() noreturn { + @branchHint(.cold); call("integer overflow", null); } pub fn shlOverflow() noreturn { + @branchHint(.cold); call("left shift overflowed bits", null); } pub fn shrOverflow() noreturn { + @branchHint(.cold); call("right shift overflowed bits", null); } pub fn divideByZero() noreturn { + @branchHint(.cold); call("division by zero", null); } pub fn exactDivisionRemainder() noreturn { + @branchHint(.cold); call("exact division produced remainder", null); } pub fn integerPartOutOfBounds() noreturn { + @branchHint(.cold); call("integer part of floating point value out of bounds", null); } pub fn corruptSwitch() noreturn { + @branchHint(.cold); call("switch on corrupt value", null); } pub fn shiftRhsTooBig() noreturn { + @branchHint(.cold); call("shift amount is greater than the type size", null); } pub fn invalidEnumValue() noreturn { + @branchHint(.cold); call("invalid enum value", null); } pub fn forLenMismatch() noreturn { + @branchHint(.cold); call("for loop over objects with non-equal lengths", null); } pub fn copyLenMismatch() noreturn { + @branchHint(.cold); call("source and destination have non-equal lengths", null); } pub fn memcpyAlias() noreturn { + @branchHint(.cold); call("@memcpy arguments alias", null); } pub fn noreturnReturned() noreturn { + @branchHint(.cold); call("'noreturn' function returned", null); } + +pub fn loadUninstantiableType() noreturn { + call("attempt to load uninstantiable type", null); +} diff --git a/lib/std/deque.zig b/lib/std/deque.zig index c21e1b86567f9f84b9e7078fb751f178b193e5e9..ec40c9d1dbc9eb4b20a3025d22508a90d0a2acec 100644 --- a/lib/std/deque.zig +++ b/lib/std/deque.zig @@ -696,7 +696,7 @@ fn fuzzAgainstArrayList(_: void, smith: *std.testing.Smith) anyerror!void { try q.ensureTotalCapacityPrecise(q_gpa, q.len + growth); }, } - try testing.expectEqual(l.getLast(), q.back()); + try testing.expectEqual(l.last(), q.back()); try testing.expectEqual( if (l.items.len > 0) l.items[0] else null, q.front(), diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index 0161644439803e7fc6dd4fbb1c1610235d97b5e0..98bcafb88b16504cfab619d8407675b5014fd6e9 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -103,7 +103,7 @@ pub fn get_DYNAMIC() ?[*]const elf.Dyn { pub fn linkmap_iterator() error{InvalidExe}!LinkMap.Iterator { const _DYNAMIC = get_DYNAMIC() orelse { - // No PT_DYNAMIC means this is a statically-linked non-PIE program. + // No PT.DYNAMIC means this is a statically-linked non-PIE program. return .{ .current = null }; }; @@ -261,10 +261,10 @@ pub const ElfDynLib = struct { i += 1; ph_addr += eh.e_phentsize; }) { - const ph = @as(*elf.Phdr, @ptrFromInt(ph_addr)); - switch (ph.p_type) { - elf.PT_LOAD => virt_addr_end = @max(virt_addr_end, ph.p_vaddr + ph.p_memsz), - elf.PT_DYNAMIC => maybe_dynv = @as([*]usize, @ptrFromInt(elf_addr + ph.p_offset)), + const ph = @as(*elf.ElfN.Phdr, @ptrFromInt(ph_addr)); + switch (ph.type) { + .LOAD => virt_addr_end = @max(virt_addr_end, ph.vaddr + ph.memsz), + .DYNAMIC => maybe_dynv = @as([*]usize, @ptrFromInt(elf_addr + ph.offset)), else => {}, } } @@ -292,23 +292,23 @@ pub const ElfDynLib = struct { i += 1; ph_addr += eh.e_phentsize; }) { - const ph = @as(*elf.Phdr, @ptrFromInt(ph_addr)); - switch (ph.p_type) { - elf.PT_LOAD => { + const ph = @as(*elf.ElfN.Phdr, @ptrFromInt(ph_addr)); + switch (ph.type) { + .LOAD => { // The VirtAddr may not be page-aligned; in such case there will be // extra nonsense mapped before/after the VirtAddr,MemSiz - const aligned_addr = (base + ph.p_vaddr) & ~(@as(usize, page_size) - 1); - const extra_bytes = (base + ph.p_vaddr) - aligned_addr; - const extended_memsz = mem.alignForward(usize, ph.p_memsz + extra_bytes, page_size); + const aligned_addr = (base + ph.vaddr) & ~(@as(usize, page_size) - 1); + const extra_bytes = (base + ph.vaddr) - aligned_addr; + const extended_memsz = mem.alignForward(usize, ph.memsz + extra_bytes, page_size); const ptr = @as([*]align(std.heap.page_size_min) u8, @ptrFromInt(aligned_addr)); - const prot = elfToProt(ph.p_flags); + const prot = elfToProt(ph.flags); _ = try posix.mmap( ptr, extended_memsz, prot, .{ .TYPE = .PRIVATE, .FIXED = true }, file.handle, - ph.p_offset - extra_bytes, + ph.offset - extra_bytes, ); }, else => {}, @@ -517,11 +517,11 @@ pub const ElfDynLib = struct { return null; } - fn elfToProt(elf_prot: u64) posix.PROT { + fn elfToProt(elf_prot: elf.PF) posix.PROT { return .{ - .READ = (elf_prot & elf.PF_R) != 0, - .WRITE = (elf_prot & elf.PF_W) != 0, - .EXEC = (elf_prot & elf.PF_X) != 0, + .READ = elf_prot.R, + .WRITE = elf_prot.W, + .EXEC = elf_prot.X, }; } }; diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 294bde804cae719605bd9af7e65299a5b7185a05..e4e905cea761ff6cbfbc81bcbd2fc44fdc8704ad 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -290,47 +290,6 @@ pub const VER_FLG_BASE = 1; /// Weak version identifier pub const VER_FLG_WEAK = 2; -/// Deprecated, use `@intFromEnum(std.elf.PT.NULL)` -pub const PT_NULL = @backingInt(std.elf.PT.NULL); -/// Deprecated, use `@intFromEnum(std.elf.PT.LOAD)` -pub const PT_LOAD = @backingInt(std.elf.PT.LOAD); -/// Deprecated, use `@intFromEnum(std.elf.PT.DYNAMIC)` -pub const PT_DYNAMIC = @backingInt(std.elf.PT.DYNAMIC); -/// Deprecated, use `@intFromEnum(std.elf.PT.INTERP)` -pub const PT_INTERP = @backingInt(std.elf.PT.INTERP); -/// Deprecated, use `@intFromEnum(std.elf.PT.NOTE)` -pub const PT_NOTE = @backingInt(std.elf.PT.NOTE); -/// Deprecated, use `@intFromEnum(std.elf.PT.SHLIB)` -pub const PT_SHLIB = @backingInt(std.elf.PT.SHLIB); -/// Deprecated, use `@intFromEnum(std.elf.PT.PHDR)` -pub const PT_PHDR = @backingInt(std.elf.PT.PHDR); -/// Deprecated, use `@intFromEnum(std.elf.PT.TLS)` -pub const PT_TLS = @backingInt(std.elf.PT.TLS); -/// Deprecated, use `std.elf.PT.NUM`. -pub const PT_NUM = PT.NUM; -/// Deprecated, use `@intFromEnum(std.elf.PT.LOOS)` -pub const PT_LOOS = @backingInt(std.elf.PT.LOOS); -/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_EH_FRAME)` -pub const PT_GNU_EH_FRAME = @backingInt(std.elf.PT.GNU_EH_FRAME); -/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_STACK)` -pub const PT_GNU_STACK = @backingInt(std.elf.PT.GNU_STACK); -/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_RELRO)` -pub const PT_GNU_RELRO = @backingInt(std.elf.PT.GNU_RELRO); -/// Deprecated, use `@intFromEnum(std.elf.PT.LOSUNW)` -pub const PT_LOSUNW = @backingInt(std.elf.PT.LOSUNW); -/// Deprecated, use `@intFromEnum(std.elf.PT.SUNWBSS)` -pub const PT_SUNWBSS = @backingInt(std.elf.PT.SUNWBSS); -/// Deprecated, use `@intFromEnum(std.elf.PT.SUNWSTACK)` -pub const PT_SUNWSTACK = @backingInt(std.elf.PT.SUNWSTACK); -/// Deprecated, use `@intFromEnum(std.elf.PT.HISUNW)` -pub const PT_HISUNW = @backingInt(std.elf.PT.HISUNW); -/// Deprecated, use `@intFromEnum(std.elf.PT.HIOS)` -pub const PT_HIOS = @backingInt(std.elf.PT.HIOS); -/// Deprecated, use `@intFromEnum(std.elf.PT.LOPROC)` -pub const PT_LOPROC = @backingInt(std.elf.PT.LOPROC); -/// Deprecated, use `@intFromEnum(std.elf.PT.HIPROC)` -pub const PT_HIPROC = @backingInt(std.elf.PT.HIPROC); - pub const PN_XNUM = 0xffff; /// Deprecated, use `@intFromEnum(std.elf.SHT.NULL)` @@ -848,11 +807,11 @@ pub const ProgramHeaderIterator = struct { file_reader: *Io.File.Reader, index: usize = 0, - pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr { + pub fn next(it: *ProgramHeaderIterator) !?Elf64.Phdr { if (it.index >= it.phnum) return null; defer it.index += 1; - const size: u64 = if (it.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); + const size: u64 = if (it.is_64) @sizeOf(Elf64.Phdr) else @sizeOf(Elf32.Phdr); const offset = it.phoff + size * it.index; try it.file_reader.seekTo(offset); @@ -869,11 +828,11 @@ pub const ProgramHeaderBufferIterator = struct { buf: []const u8, index: usize = 0, - pub fn next(it: *ProgramHeaderBufferIterator) !?Elf64_Phdr { + pub fn next(it: *ProgramHeaderBufferIterator) !?Elf64.Phdr { if (it.index >= it.phnum) return null; defer it.index += 1; - const size: usize = if (it.is_64) @sizeOf(Elf64_Phdr) else @sizeOf(Elf32_Phdr); + const size: usize = if (it.is_64) @sizeOf(Elf64.Phdr) else @sizeOf(Elf32.Phdr); const offset = @as(usize, @intCast(it.phoff)) + size * it.index; var reader = Io.Reader.fixed(it.buf[offset..]); @@ -881,22 +840,22 @@ pub const ProgramHeaderBufferIterator = struct { } }; -pub fn takeProgramHeader(reader: *Io.Reader, is_64: bool, endian: Endian) !Elf64_Phdr { +pub fn takeProgramHeader(reader: *Io.Reader, is_64: bool, endian: Endian) !Elf64.Phdr { if (is_64) { - const phdr = try reader.takeStruct(Elf64_Phdr, endian); + const phdr = try reader.takeStruct(Elf64.Phdr, endian); return phdr; } - const phdr = try reader.takeStruct(Elf32_Phdr, endian); + const phdr = try reader.takeStruct(Elf32.Phdr, endian); return .{ - .p_type = phdr.p_type, - .p_offset = phdr.p_offset, - .p_vaddr = phdr.p_vaddr, - .p_paddr = phdr.p_paddr, - .p_filesz = phdr.p_filesz, - .p_memsz = phdr.p_memsz, - .p_flags = phdr.p_flags, - .p_align = phdr.p_align, + .type = phdr.type, + .offset = phdr.offset, + .vaddr = phdr.vaddr, + .paddr = phdr.paddr, + .filesz = phdr.filesz, + .memsz = phdr.memsz, + .flags = phdr.flags, + .@"align" = phdr.@"align", }; } @@ -1276,28 +1235,6 @@ pub const Elf64_Ehdr = extern struct { e_shnum: Half, e_shstrndx: Half, }; -/// Deprecated, use `std.elf.Elf32.Phdr` -pub const Elf32_Phdr = extern struct { - p_type: Word, - p_offset: Elf32_Off, - p_vaddr: Elf32_Addr, - p_paddr: Elf32_Addr, - p_filesz: Word, - p_memsz: Word, - p_flags: Word, - p_align: Word, -}; -/// Deprecated, use `std.elf.Elf64.Phdr` -pub const Elf64_Phdr = extern struct { - p_type: Word, - p_flags: Word, - p_offset: Elf64_Off, - p_vaddr: Elf64_Addr, - p_paddr: Elf64_Addr, - p_filesz: Elf64_Xword, - p_memsz: Elf64_Xword, - p_align: Elf64_Xword, -}; /// Deprecated, use `std.elf.Elf32.Shdr` pub const Elf32_Shdr = extern struct { sh_name: Word, @@ -1568,12 +1505,6 @@ pub const Ehdr = switch (@sizeOf(usize)) { 8 => Elf64_Ehdr, else => @compileError("expected pointer size of 32 or 64"), }; -/// Deprecated, use `std.elf.ElfN.Phdr` -pub const Phdr = switch (@sizeOf(usize)) { - 4 => Elf32_Phdr, - 8 => Elf64_Phdr, - else => @compileError("expected pointer size of 32 or 64"), -}; pub const Dyn = switch (@sizeOf(usize)) { 4 => Elf32_Dyn, 8 => Elf64_Dyn, @@ -3272,12 +3203,12 @@ pub const ar_hdr = extern struct { ar_fmag: [2]u8, pub fn date(self: ar_hdr) std.fmt.ParseIntError!u64 { - const value = mem.trimEnd(u8, &self.ar_date, &[_]u8{0x20}); + const value = mem.trimEnd(u8, &self.ar_date, " "); return std.fmt.parseInt(u64, value, 10); } pub fn size(self: ar_hdr) std.fmt.ParseIntError!u32 { - const value = mem.trimEnd(u8, &self.ar_size, &[_]u8{0x20}); + const value = mem.trimEnd(u8, &self.ar_size, " "); return std.fmt.parseInt(u32, value, 10); } @@ -3311,7 +3242,7 @@ pub const ar_hdr = extern struct { pub fn nameOffset(self: ar_hdr) std.fmt.ParseIntError!?u32 { const value = &self.ar_name; if (value[0] != '/') return null; - const trimmed = mem.trimEnd(u8, value, &[_]u8{0x20}); + const trimmed = mem.trimEnd(u8, value, " "); return try std.fmt.parseInt(u32, trimmed[1..], 10); } }; @@ -3319,7 +3250,7 @@ pub const ar_hdr = extern struct { fn genSpecialMemberName(comptime name: []const u8) *const [16]u8 { assert(name.len <= 16); const padding = 16 - name.len; - return name ++ @as([padding]u8, @splat(0x20)); + return name ++ @as([padding]u8, @splat(' ')); } // Archive files start with the ARMAG identifying string. Then follows a diff --git a/lib/std/enums.zig b/lib/std/enums.zig index 551cf71fcdd1c757b0e8a7db34fa11a93692a835..0f7439e00961485c4ce57f8a2a6286f6a2b9c818 100644 --- a/lib/std/enums.zig +++ b/lib/std/enums.zig @@ -33,7 +33,8 @@ pub fn fromInt(comptime E: type, integer: anytype) ?E { pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type { @setEvalBranchQuota(@typeInfo(E).@"enum".field_names.len + eval_branch_quota_cushion); const default_ptr: ?*const anyopaque = if (field_default) |d| @ptrCast(&d) else null; - return @Struct(.auto, null, std.meta.fieldNames(E), &@splat(Data), &@splat(.{ .default_value_ptr = default_ptr })); + const field_names = @typeInfo(E).@"enum".field_names; + return @Struct(.auto, null, field_names, &@splat(Data), &@splat(.{ .default_value_ptr = default_ptr })); } /// Looks up the supplied field values in the given enum type. @@ -454,7 +455,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { } } } else { - inline for (std.meta.fieldNames(E)) |field_name| { + inline for (@typeInfo(E).@"enum".field_names) |field_name| { const key = @field(E, field_name); if (@field(init_values, field_name)) |*v| { const i = comptime Indexer.indexOf(key); diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 92e04955ed48a2628f78ae040326c3a853f88b11..0c3dba4a7a95ff9a68f8d9f64d082c35565134a7 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -261,7 +261,7 @@ test printInt { /// Converts values in the range [0, 100) to a base 10 string. pub fn digits2(value: u8) [2]u8 { - if (builtin.mode == .ReleaseSmall) { + if (builtin.mode == .small) { return .{ @intCast('0' + value / 10), @intCast('0' + value % 10) }; } else { return "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"[value * 2 ..][0..2].*; @@ -924,7 +924,7 @@ test "enum" { // test very large enum to verify ct branch quota is large enough // TODO: https://github.com/ziglang/zig/issues/15609 - if (!((builtin.cpu.arch == .wasm32) and builtin.mode == .Debug)) { + if (!((builtin.cpu.arch == .wasm32) and builtin.mode == .debug)) { try expectFmt("enum: .INVALID_FUNCTION\n", "enum: {}\n", .{std.os.windows.Win32Error.INVALID_FUNCTION}); } @@ -1082,8 +1082,6 @@ test "float.libc.sanity" { } test "union" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const TU = union(enum) { float: f32, int: u32, diff --git a/lib/std/fmt/float.zig b/lib/std/fmt/float.zig index 44a71f90f42c47b608d6db65b1b7a59243680507..e055959825832e1889d6d2c0fb6cfd131d06d50b 100644 --- a/lib/std/fmt/float.zig +++ b/lib/std/fmt/float.zig @@ -65,7 +65,7 @@ pub fn render(buf: []u8, value: anytype, options: Options) Error![]const u8 { const DT = if (@bitSizeOf(T) <= 64) u64 else u128; const tables = switch (DT) { - u64 => if (@import("builtin").mode == .ReleaseSmall) &Backend64_TablesSmall else &Backend64_TablesFull, + u64 => if (builtin.mode == .small) &Backend64_TablesSmall else &Backend64_TablesFull, u128 => &Backend128_Tables, else => unreachable, }; diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index 7eede9c715f6121e9bff5151cb40fd59615f592d..d5b7f751acf77f6a4b98951f8039bbbf4c20b752 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -1830,7 +1830,7 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons /// pointer address range of `path`, even if it is length zero. pub fn extension(path: []const u8) []const u8 { const filename = basename(path); - const index = mem.lastIndexOfScalar(u8, filename, '.') orelse return path[path.len..]; + const index = mem.findScalarLast(u8, filename, '.') orelse return path[path.len..]; if (index == 0) return path[path.len..]; return filename[index..]; } @@ -1887,8 +1887,8 @@ test extension { /// - "hello/world/lib" ⇒ "lib" pub fn stem(path: []const u8) []const u8 { const filename = basename(path); - const index = mem.lastIndexOfScalar(u8, filename, '.') orelse return filename[0..]; - if (index == 0) return path; + const index = mem.findScalarLast(u8, filename, '.') orelse return filename; + if (index == 0) return filename; return filename[0..index]; } @@ -1904,8 +1904,14 @@ test stem { try testStem("hello...", "hello.."); try testStem("hello.", "hello"); try testStem("/hello.", "hello"); + try testStem("hello/world/.gitignore", ".gitignore"); + try testStem("/.gitignore", ".gitignore"); try testStem(".gitignore", ".gitignore"); + try testStem(".gitignore/", ".gitignore"); + try testStem("hello/world/.image.png", ".image"); + try testStem("/.image.png", ".image"); try testStem(".image.png", ".image"); + try testStem(".image.png/", ".image"); try testStem("file.ext", "file"); try testStem("file.ext.", "file.ext"); try testStem("a.b.c", "a.b"); diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index bf16a7c216b4f9087195c7a98160e6b765687960..981bc75d442a3688f43224d4dfe278c03ea3f5a8 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -758,6 +758,43 @@ test "readFileAlloc" { ); } +test "file operations with follow_symlinks=false" { + const io = testing.io; + + var tmp_dir = tmpDir(.{}); + defer tmp_dir.cleanup(); + + const contents = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n"; + try tmp_dir.dir.writeFile(io, .{ + .sub_path = "test_file", + .data = contents, + }); + + // Without lock + { + var file = try tmp_dir.dir.openFile(io, "test_file", .{ .follow_symlinks = false }); + defer file.close(io); + + var file_reader = file.reader(io, &.{}); + const actual_contents = try file_reader.interface.allocRemaining(testing.allocator, .unlimited); + defer testing.allocator.free(actual_contents); + + try std.testing.expectEqualSlices(u8, contents, actual_contents); + } + + // With lock + { + var file = try tmp_dir.dir.openFile(io, "test_file", .{ .follow_symlinks = false, .lock = .exclusive }); + defer file.close(io); + + var file_reader = file.reader(io, &.{}); + const actual_contents = try file_reader.interface.allocRemaining(testing.allocator, .unlimited); + defer testing.allocator.free(actual_contents); + + try std.testing.expectEqualSlices(u8, contents, actual_contents); + } +} + test "Dir.statFile" { try testWithAllSupportedPathTypes(struct { fn impl(ctx: *TestContext) !void { @@ -902,6 +939,8 @@ test "createDirPathOpen parent dirs do not exist" { } test "deleteDir" { + if (builtin.target.os.tag == .windows) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35686 + try testWithAllSupportedPathTypes(struct { fn impl(ctx: *TestContext) !void { const io = ctx.io; @@ -2168,7 +2207,7 @@ test "'.' and '..' in absolute functions" { } test "chmod" { - if (native_os == .windows or native_os == .wasi) return; + if (native_os == .windows or native_os == .wasi) return error.SkipZigTest; const io = testing.io; @@ -2191,8 +2230,7 @@ test "chmod" { } test "change ownership" { - if (native_os == .windows or native_os == .wasi) - return error.SkipZigTest; + if (native_os == .windows or native_os == .wasi) return error.SkipZigTest; const io = testing.io; diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index 3964ad5f946f899a51cbfdefb38cb42d2973b74d..1cb8e93092ec55534810432e78e896d88ffa881a 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -225,7 +225,7 @@ fn testHashDeepRecursive(key: anytype) u64 { test "typeContainsSlice" { comptime { - try testing.expect(!typeContainsSlice(std.meta.Tag(std.builtin.Type))); + try testing.expect(!typeContainsSlice(std.meta.Tag(std.lang.Type))); try testing.expect(typeContainsSlice([]const u8)); try testing.expect(!typeContainsSlice(u8)); diff --git a/lib/std/hash/benchmark.zig b/lib/std/hash/benchmark.zig index 3f5b763d9b0f2eb207b597c8e41098f272a090d0..a4ea82d68e6fef34b7ade95fe69bffac17e43021 100644 --- a/lib/std/hash/benchmark.zig +++ b/lib/std/hash/benchmark.zig @@ -355,7 +355,7 @@ fn usage() void { } fn mode(comptime x: comptime_int) comptime_int { - return if (builtin.mode == .Debug) x / 64 else x; + return if (builtin.mode == .debug) x / 64 else x; } pub fn main(init: std.process.Init) !void { diff --git a/lib/std/hash/cityhash.zig b/lib/std/hash/cityhash.zig index 781949321d0c37d624b29f8f5599fff5f0873f39..1acb039dab5551e4e0ef0b691c4d5ae8770bebb7 100644 --- a/lib/std/hash/cityhash.zig +++ b/lib/std/hash/cityhash.zig @@ -16,7 +16,7 @@ fn fetch64(ptr: [*]const u8, offset: usize) u64 { pub const CityHash32 = struct { const Self = @This(); - // Magic numbers for 32-bit hashing. Copied from Murmur3. + // Magic numbers for 32-bit hashing. Copied from Murmur3. const c1: u32 = 0xcc9e2d51; const c2: u32 = 0x1b873593; diff --git a/lib/std/hash/xxhash.zig b/lib/std/hash/xxhash.zig index 27f2701443cc919a9cd2686165ecc8ae087ae002..b33ac61b5bd233a0c6ccea59033d7ee6c2b62045 100644 --- a/lib/std/hash/xxhash.zig +++ b/lib/std/hash/xxhash.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const builtin = @import("builtin"); const mem = std.mem; const expectEqual = std.testing.expectEqual; @@ -761,7 +760,7 @@ pub const XxHash3 = struct { var accumulator_copy = self.accumulator; var last_block_copy: [block_bytes]u8 = undefined; - // Digest the last block onthe Accumulator copy. + // Digest the last block on the Accumulator copy. return accumulator_copy.digest(self.total_len, last_block: { if (self.buffered >= block_bytes) { const block_count = ((self.buffered - 1) / block_bytes) * block_bytes; @@ -788,7 +787,6 @@ fn testExpect(comptime H: type, seed: anytype, input: []const u8, expected: u64) } test "xxhash3" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const H = XxHash3; // Non-Seeded Tests try testExpect(H, 0, "", 0x2d06800538d394c2); @@ -820,7 +818,6 @@ test "xxhash3" { } test "xxhash3 smhasher" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const Test = struct { fn do() !void { try expectEqual(verify.smhasher(XxHash3.hash), 0x9a636405); @@ -832,7 +829,6 @@ test "xxhash3 smhasher" { } test "xxhash3 iterative api" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const Test = struct { fn do() !void { try verify.iterativeApi(XxHash3); diff --git a/lib/std/hash_map.zig b/lib/std/hash_map.zig index a6562bc5ea1ab479963b308beae24fb303d98c6d..b11f7e4a0dee9413d8ca5a798492c48f0ba5dde1 100644 --- a/lib/std/hash_map.zig +++ b/lib/std/hash_map.zig @@ -1518,7 +1518,7 @@ fn Custom( self.available = 0; } - /// This function is used in the debugger pretty formatters in tools/ to fetch the + /// This function is used in the debugger pretty formatters in lib/lldb/ to fetch the /// header type to facilitate fancy debug printing for this type. fn dbHelper(self: *Self, hdr: *Header, entry: *Entry) void { _ = self; diff --git a/lib/std/heap/PageAllocator.zig b/lib/std/heap/PageAllocator.zig index db736036b3f416d34a934b7185ac4a953affa303..1adac776bb9ac7a1d145bc7a5e464eedefd84f29 100644 --- a/lib/std/heap/PageAllocator.zig +++ b/lib/std/heap/PageAllocator.zig @@ -24,6 +24,7 @@ pub const vtable: Allocator.VTable = .{ /// that don't provide a hint (for security reasons, but it serves our needs /// too). const enable_hints = switch (builtin.target.os.tag) { + .linux => !builtin.target.cpu.arch.isSPARC(), // https://bugzilla.kernel.org/show_bug.cgi?id=221820 .openbsd => false, else => true, }; diff --git a/lib/std/heap/SafeAllocator.zig b/lib/std/heap/SafeAllocator.zig index cfe24f4c0b1f0dabeaedaff76cc33d6ae32669c3..91f65184241713f66a39953092d889cd2bed4b84 100644 --- a/lib/std/heap/SafeAllocator.zig +++ b/lib/std/heap/SafeAllocator.zig @@ -39,7 +39,7 @@ const SafeAllocator = @This(); const scoped_log = std.log.scoped(.SafeAllocator); pub const Options = struct { - const is_debug = @import("builtin").mode == .Debug; + const is_debug = @import("builtin").mode == .debug; const page_size_log2 = @max(math.log2_int(usize, std.heap.page_size_max), 8); stack_trace_frames: usize = if (is_debug and std.debug.sys_can_stack_trace) 7 else 0, @@ -1519,7 +1519,7 @@ const FuzzSingleThreadedAllocator = struct { @disableInstrumentation(); const allocs_slice = f.allocs.slice(); - const i = mem.indexOfScalar([*]u8, allocs_slice.items(.ptr), memory.ptr) orelse panic( + const i = mem.findScalar([*]u8, allocs_slice.items(.ptr), memory.ptr) orelse panic( "invalid SafeAllocator free of {f}", .{FormatMemory{ .memory = memory, .alignment = alignment }}, ); diff --git a/lib/std/http.zig b/lib/std/http.zig index 3a255580576b23e49bcecdfa88503259d458e1f5..c2966cb2558f0c0ebee2f1e2d1bdcf6a78ad8356 100644 --- a/lib/std/http.zig +++ b/lib/std/http.zig @@ -20,6 +20,8 @@ pub const Version = enum { /// https://datatracker.ietf.org/doc/html/rfc7231#section-4 Initial definition /// /// https://datatracker.ietf.org/doc/html/rfc5789#section-2 PATCH +/// +/// https://datatracker.ietf.org/doc/html/rfc10008#name-query-method QUERY pub const Method = enum { GET, HEAD, @@ -30,12 +32,13 @@ pub const Method = enum { OPTIONS, TRACE, PATCH, + QUERY, /// Returns true if a request of this method is allowed to have a body /// Actual behavior from servers may vary and should still be checked pub fn requestHasBody(m: Method) bool { return switch (m) { - .POST, .PUT, .PATCH => true, + .POST, .PUT, .PATCH, .QUERY => true, .GET, .HEAD, .DELETE, .CONNECT, .OPTIONS, .TRACE => false, }; } @@ -44,7 +47,7 @@ pub const Method = enum { /// Actual behavior from clients may vary and should still be checked pub fn responseHasBody(m: Method) bool { return switch (m) { - .GET, .POST, .PUT, .DELETE, .CONNECT, .OPTIONS, .PATCH => true, + .GET, .POST, .PUT, .DELETE, .CONNECT, .OPTIONS, .PATCH, .QUERY => true, .HEAD, .TRACE => false, }; } @@ -56,7 +59,7 @@ pub const Method = enum { /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.1 pub fn safe(m: Method) bool { return switch (m) { - .GET, .HEAD, .OPTIONS, .TRACE => true, + .GET, .HEAD, .OPTIONS, .TRACE, .QUERY => true, .POST, .PUT, .DELETE, .CONNECT, .PATCH => false, }; } @@ -70,7 +73,7 @@ pub const Method = enum { /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.2 pub fn idempotent(m: Method) bool { return switch (m) { - .GET, .HEAD, .PUT, .DELETE, .OPTIONS, .TRACE => true, + .GET, .HEAD, .PUT, .DELETE, .OPTIONS, .TRACE, .QUERY => true, .CONNECT, .POST, .PATCH => false, }; } @@ -83,7 +86,7 @@ pub const Method = enum { /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.3 pub fn cacheable(m: Method) bool { return switch (m) { - .GET, .HEAD => true, + .GET, .HEAD, .QUERY => true, .POST, .PUT, .DELETE, .CONNECT, .OPTIONS, .TRACE, .PATCH => false, }; } diff --git a/lib/std/http/Server.zig b/lib/std/http/Server.zig index 6523fa672f005664296726a858d40b3935b5561f..c505605c03406e3ef760fabe031175358a207cd5 100644 --- a/lib/std/http/Server.zig +++ b/lib/std/http/Server.zig @@ -102,7 +102,7 @@ pub const Request = struct { const method = std.meta.stringToEnum(http.Method, first_line[0..method_end]) orelse return error.UnknownHttpMethod; - const version_start = mem.lastIndexOfScalar(u8, first_line, ' ') orelse + const version_start = mem.findScalarLast(u8, first_line, ' ') orelse return error.HttpHeadersInvalid; if (version_start == method_end) return error.HttpHeadersInvalid; diff --git a/lib/std/http/test.zig b/lib/std/http/test.zig index 4182a766c5a132f8dca6fa24adafae86ba15e4d2..e7a37daa68de6751d5762b7639e25bd1401a37c0 100644 --- a/lib/std/http/test.zig +++ b/lib/std/http/test.zig @@ -1,5 +1,4 @@ const builtin = @import("builtin"); -const native_endian = builtin.cpu.arch.endian(); const std = @import("std"); const http = std.http; @@ -34,7 +33,6 @@ test "content length reader state update" { } test "trailers" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -121,7 +119,6 @@ test "trailers" { } test "HTTP server handles a chunked transfer coding request" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -190,7 +187,6 @@ test "HTTP server handles a chunked transfer coding request" { } test "echo content server" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -281,12 +277,11 @@ test "echo content server" { } test "Server.Request.respondStreaming non-chunked, unknown content-length" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; - if (builtin.os.tag == .windows) { + if (builtin.cpu.arch == .aarch64 and builtin.os.tag == .windows) { // https://github.com/ziglang/zig/issues/21457 return error.SkipZigTest; } @@ -360,7 +355,6 @@ test "Server.Request.respondStreaming non-chunked, unknown content-length" { } test "receiving arbitrary http headers from the client" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -426,16 +420,10 @@ test "receiving arbitrary http headers from the client" { } test "general client/server API coverage" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; - if (builtin.os.tag == .windows) { - // This test was never passing on Windows. - return error.SkipZigTest; - } - const test_server = try createTestServer(io, struct { fn run(test_server: *TestServer) anyerror!void { const net_server = &test_server.net_server; @@ -922,7 +910,6 @@ test "general client/server API coverage" { } test "Server streams both reading and writing" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -1162,10 +1149,6 @@ const TestServer = struct { fn createTestServer(io: Io, S: type) !*TestServer { if (builtin.single_threaded) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and native_endian == .big) { - // https://github.com/ziglang/zig/issues/13782 - return error.SkipZigTest; - } const address = try net.IpAddress.parse("127.0.0.1", 0); @@ -1192,7 +1175,6 @@ fn createTestServer(io: Io, S: type) !*TestServer { } test "redirect to different connection" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; @@ -1280,7 +1262,6 @@ test "redirect to different connection" { } test "boot failed connections from the pool" { - if (builtin.cpu.arch.isPowerPC64() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194257 if (builtin.os.tag == .openbsd) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30806 const io = std.testing.io; diff --git a/lib/std/json/Stringify.zig b/lib/std/json/Stringify.zig index 565c41b5e8e96c5bc3d3726df0171554fc8ed4d9..03c5d8fe4611dce85280df2de435194bf9a9fb1f 100644 --- a/lib/std/json/Stringify.zig +++ b/lib/std/json/Stringify.zig @@ -54,8 +54,8 @@ else void = if (build_mode_has_safety) .none else {}, const build_mode_has_safety = switch (@import("builtin").mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, + .debug, .safe => true, + .fast, .small => false, }; /// The `safety_checks_hint` parameter determines how much memory is used to enable assertions that the above grammar is being followed, @@ -66,7 +66,7 @@ const build_mode_has_safety = switch (@import("builtin").mode) { /// If `.checked_to_fixed_depth` is used, there is additionally an assertion that the nesting depth never exceeds the given limit. /// `.checked_to_fixed_depth` embeds the storage required in the `Stringify` struct. /// `.assumed_correct` requires no space and performs none of these assertions. -/// In `ReleaseFast` and `ReleaseSmall` mode, the given `safety_checks_hint` is ignored and is always treated as `.assumed_correct`. +/// In fast and small optimization modes, the given `safety_checks_hint` is ignored and is always treated as `.assumed_correct`. const safety_checks_hint: union(enum) { /// Rounded up to the nearest multiple of 8. checked_to_fixed_depth: usize, diff --git a/lib/std/lang.zig b/lib/std/lang.zig index 02a1c90e5a915a26a7186d3733a2893a99c765dd..c5ff616dc563537fc7016535e07872e9d657362b 100644 --- a/lib/std/lang.zig +++ b/lib/std/lang.zig @@ -107,13 +107,52 @@ pub const CodeModel = enum(u4) { tiny, }; +/// Deprecated, to be removed after 0.18.0 +pub const OptimizeMode = Optimize; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const OptimizeMode = enum { - Debug, - ReleaseSafe, - ReleaseFast, - ReleaseSmall, +pub const Optimize = enum { + /// Safety checks enabled. Optimize for bug detection, accurate debug info, + /// and compilation speed (in that order). + debug, + /// Safety checks enabled. Optimize for runtime performance. + safe, + /// Safety checks disabled. Optimize for runtime performance. + fast, + /// Safety checks disabled. Optimize for machine code size, then runtime performance. + small, + + /// Deprecated, to be removed after 0.18.0 + pub const Debug: @This() = .debug; + /// Deprecated, to be removed after 0.18.0 + pub const ReleaseSafe: @This() = .safe; + /// Deprecated, to be removed after 0.18.0 + pub const ReleaseFast: @This() = .fast; + /// Deprecated, to be removed after 0.18.0 + pub const ReleaseSmall: @This() = .small; + /// Deprecated, to be removed after 0.18.0 + pub fn fromString(s: []const u8) ?@This() { + return std.StaticStringMap(@This()).initComptime(&.{ + .{ "Debug", .debug }, + .{ "ReleaseSafe", .safe }, + .{ "ReleaseFast", .fast }, + .{ "ReleaseSmall", .small }, + .{ "debug", .debug }, + .{ "safe", .safe }, + .{ "fast", .fast }, + .{ "small", .small }, + }).get(s); + } + + /// Returns whether illegal behavior safety checks are enabled based on the + /// provided optimization mode. + pub fn runtimeSafety(o: @This()) bool { + return switch (o) { + .debug, .safe => true, + .fast, .small => false, + }; + } }; /// The calling convention of a function defines how arguments and return values are passed, as well @@ -171,10 +210,12 @@ pub const CallingConvention = union(enum(u8)) { x86_64_regcall_v4_win: CommonOptions, x86_64_vectorcall: CommonOptions, x86_64_interrupt: CommonOptions, + x86_64_preserve_none: CommonOptions, // Calling conventions for the `x86` architecture. x86_sysv: X86RegparmOptions, x86_win: X86RegparmOptions, + x86_mingw: X86RegparmOptions, x86_stdcall: X86RegparmOptions, x86_fastcall: CommonOptions, x86_thiscall: CommonOptions, @@ -197,6 +238,7 @@ pub const CallingConvention = union(enum(u8)) { aarch64_aapcs_win: CommonOptions, aarch64_vfabi: CommonOptions, aarch64_vfabi_sve: CommonOptions, + aarch64_preserve_none: CommonOptions, /// The standard `alpha` calling convention. alpha_osf: CommonOptions, diff --git a/lib/std/log.zig b/lib/std/log.zig index 5a219a005a6d4274c0d7df0aa16a5cf8ce10f653..9599308b91784eaa0319f1563746de3097405f03 100644 --- a/lib/std/log.zig +++ b/lib/std/log.zig @@ -53,7 +53,7 @@ pub const Level = enum { /// The default log level is based on build mode. pub const default_level: Level = switch (builtin.mode) { .Debug => .debug, - .ReleaseSafe, .ReleaseFast, .ReleaseSmall => .info, + .safe, .fast, .small => .info, }; pub const ScopeLevel = struct { diff --git a/lib/std/macho.zig b/lib/std/macho.zig index 9fdce9dd6605f450ab7eb9fee2b19b4f3787783d..48804cf7b1ccb51e8a37052686d0a9afe670d116 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -588,6 +588,25 @@ pub const rpath_command = extern struct { path: u32, }; +pub const encryption_info_command = extern struct { + cmd: LC = .ENCRYPTION_INFO, + cmdsize: u32 = @sizeOf(encryption_info_command), + + cryptoff: u32, + cryptsize: u32, + cryptid: u32 = 0, +}; + +pub const encryption_info_command_64 = extern struct { + cmd: LC = .ENCRYPTION_INFO_64, + cmdsize: u32 = @sizeOf(encryption_info_command_64), + + cryptoff: u32, + cryptsize: u32, + cryptid: u32 = 0, + _pad: u32 = 0, +}; + /// The segment load command indicates that a part of this file is to be /// mapped into the task's address space. The size of this segment in memory, /// vmsize, maybe equal to or larger than the amount to map from this file, diff --git a/lib/std/math.zig b/lib/std/math.zig index b43bc8f5981ec9083596a17ac90df631fc31d33f..27d5e0d584dca43e838d31eabec11ca2134045d9 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -75,7 +75,7 @@ pub const snan = float.snan; /// /// NaN values are never considered equal to any value. pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool { - assert(@typeInfo(T) == .float or @typeInfo(T) == .comptime_float); + comptime assert(@typeInfo(T) == .float or @typeInfo(T) == .comptime_float); assert(tolerance >= 0); // Fast path for equal values (and signed zeros and infinites). @@ -103,7 +103,7 @@ pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool { /// /// NaN values are never considered equal to any value. pub fn approxEqRel(comptime T: type, x: T, y: T, tolerance: T) bool { - assert(@typeInfo(T) == .float or @typeInfo(T) == .comptime_float); + comptime assert(@typeInfo(T) == .float or @typeInfo(T) == .comptime_float); assert(tolerance > 0); // Fast path for equal values (and signed zeros and infinites). @@ -461,7 +461,7 @@ pub fn wrap(x: anytype, r: anytype) @TypeOf(x) { } } test wrap { - if (builtin.os.tag == .windows and builtin.cpu.arch == .x86) { + if (builtin.os.tag == .windows and builtin.cpu.arch == .x86 and builtin.abi == .msvc) { // https://codeberg.org/ziglang/zig/issues/35520 return error.SkipZigTest; } @@ -1385,7 +1385,8 @@ pub fn lerp(a: anytype, b: anytype, t: anytype) @TypeOf(a, b, t) { } test lerp { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/17884 + if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isX86()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime builtin.cpu.has(.x86, .fma)) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/17884 try testing.expectEqual(@as(f64, 75), lerp(50, 100, 0.5)); diff --git a/lib/std/math/acos.zig b/lib/std/math/acos.zig index 285190227c75b5780d3b2678656272b2e01d068a..d79c36182e0aa6ebd784c45f56c0232905a9c1a2 100644 --- a/lib/std/math/acos.zig +++ b/lib/std/math/acos.zig @@ -337,8 +337,6 @@ fn acosBinary128(x: f128) f128 { } test "acosBinary16.special" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(0x1.92p0, acosBinary16(0x0p+0), math.floatEpsAt(f16, 0x1.92p0)); try testing.expectApproxEqAbs(0x1.92p1, acosBinary16(-0x1p+0), math.floatEpsAt(f16, 0x1.92p1)); try testing.expectEqual(0x0p+0, acosBinary16(0x1p+0)); @@ -350,8 +348,6 @@ test "acosBinary16.special" { } test "acosBinary16" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(0x1.834p0, acosBinary16(0x1.db4p-5), math.floatEpsAt(f16, 0x1.834p0)); try testing.expectApproxEqAbs(0x1.d48p0, acosBinary16(-0x1.068p-2), math.floatEpsAt(f16, 0x1.d48p0)); try testing.expectApproxEqAbs(0x1.b7cp0, acosBinary16(-0x1.2c4p-3), math.floatEpsAt(f16, 0x1.b7cp0)); diff --git a/lib/std/math/asin.zig b/lib/std/math/asin.zig index 68efd182aaf93db9ba5824cd76be55854c5c5f40..dfd3f063954c68d25230993b0875873273eb9ff8 100644 --- a/lib/std/math/asin.zig +++ b/lib/std/math/asin.zig @@ -326,8 +326,6 @@ fn asinBinary128(x: f128) f128 { } test "asinBinary16.special" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(0x1.92p0, asinBinary16(0x1p+0), math.floatEpsAt(f16, 0x1.92p0)); try testing.expectApproxEqAbs(-0x1.92p0, asinBinary16(-0x1p+0), math.floatEpsAt(f16, -0x1.92p0)); try testing.expectEqual(0x0p+0, asinBinary16(0x0p+0)); @@ -340,8 +338,6 @@ test "asinBinary16.special" { } test "asinBinary16" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(-0x1.e4cp-6, asinBinary16(-0x1.e4cp-6), math.floatEpsAt(f16, -0x1.e4cp-6)); try testing.expectApproxEqAbs(0x1.2a8p0, asinBinary16(0x1.d68p-1), math.floatEpsAt(f16, 0x1.2a8p0)); try testing.expectApproxEqAbs(-0x1.eep-1, asinBinary16(-0x1.a4cp-1), math.floatEpsAt(f16, -0x1.eep-1)); diff --git a/lib/std/math/atan.zig b/lib/std/math/atan.zig index 2d55b8bc1343d95f6671a96636d55b2b4a269c8e..75dab1b0c19732b229000d62634e7944491db254 100644 --- a/lib/std/math/atan.zig +++ b/lib/std/math/atan.zig @@ -481,8 +481,6 @@ fn atanBinary128(x: f128) f128 { } test "atanBinary16.special" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectEqual(0x0p+0, atanBinary16(0x0p+0)); try testing.expectEqual(-0x0p+0, atanBinary16(-0x0p+0)); try testing.expectApproxEqAbs(0x1.92p-1, atanBinary16(0x1p+0), math.floatEpsAt(f16, 0x1.92p-1)); @@ -493,8 +491,6 @@ test "atanBinary16.special" { } test "atanBinary16" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - try testing.expectApproxEqAbs(-0x1.74cp-2, atanBinary16(-0x1.864p-2), math.floatEpsAt(f16, -0x1.74cp-2)); try testing.expectApproxEqAbs(-0x1.374p0, atanBinary16(-0x1.59cp1), math.floatEpsAt(f16, -0x1.374p0)); try testing.expectApproxEqAbs(-0x1.11cp0, atanBinary16(-0x1.d2cp0), math.floatEpsAt(f16, -0x1.11cp0)); diff --git a/lib/std/math/atan2.zig b/lib/std/math/atan2.zig index f0c8aa0792046a94b900fba216dde87724ec8e1c..7c7bb4bb78e34d8d3b2c3403eba2e63d3ed1d3ce 100644 --- a/lib/std/math/atan2.zig +++ b/lib/std/math/atan2.zig @@ -252,8 +252,8 @@ test "atan2_32.special" { try expect(math.isNan(atan2_32(1.0, math.nan(f32)))); try expect(math.isNan(atan2_32(math.nan(f32), 1.0))); - try expect(atan2_32(0.0, 5.0) == 0.0); - try expect(atan2_32(-0.0, 5.0) == -0.0); + try expect(math.isPositiveZero(atan2_32(0.0, 5.0))); + try expect(math.isNegativeZero(atan2_32(-0.0, 5.0))); try expect(math.approxEqAbs(f32, atan2_32(0.0, -5.0), math.pi, epsilon)); //expect(math.approxEqAbs(f32, atan2_32(-0.0, -5.0), -math.pi, .{.rel=0,.abs=epsilon})); TODO support negative zero? try expect(math.approxEqAbs(f32, atan2_32(1.0, 0.0), math.pi / 2.0, epsilon)); @@ -276,8 +276,8 @@ test "atan2_64.special" { try expect(math.isNan(atan2_64(1.0, math.nan(f64)))); try expect(math.isNan(atan2_64(math.nan(f64), 1.0))); - try expect(atan2_64(0.0, 5.0) == 0.0); - try expect(atan2_64(-0.0, 5.0) == -0.0); + try expect(math.isPositiveZero(atan2_64(0.0, 5.0))); + try expect(math.isNegativeZero(atan2_64(-0.0, 5.0))); try expect(math.approxEqAbs(f64, atan2_64(0.0, -5.0), math.pi, epsilon)); //expect(math.approxEqAbs(f64, atan2_64(-0.0, -5.0), -math.pi, .{.rel=0,.abs=epsilon})); TODO support negative zero? try expect(math.approxEqAbs(f64, atan2_64(1.0, 0.0), math.pi / 2.0, epsilon)); diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index 485ae4918cce7545119b5b014f7c8133656aaf0b..271041e761a1d6f089c7733aa2964913c771dc0d 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -1,5 +1,4 @@ const std = @import("../../std.zig"); -const builtin = @import("builtin"); const mem = std.mem; const testing = std.testing; const Managed = std.math.big.int.Managed; @@ -276,8 +275,6 @@ fn setFloat(comptime Float: type) !void { try expectNormalized(1 << 10, res.toConst()); } test setFloat { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - try setFloat(f16); try setFloat(f32); try setFloat(f64); @@ -484,7 +481,6 @@ fn toFloat(comptime Float: type) !void { ); } test toFloat { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; try toFloat(f16); try toFloat(f32); try toFloat(f64); @@ -1391,8 +1387,6 @@ test "mul multi-single" { } test "mul multi-multi" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var op1: u256 = 0x998888efefefefefefefef; var op2: u256 = 0x333000abababababababab; _ = .{ &op1, &op2 }; @@ -1514,8 +1508,6 @@ test "mulWrap single-single signed" { } test "mulWrap multi-multi unsigned" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var op1: u256 = 0x998888efefefefefefefef; var op2: u256 = 0x333000abababababababab; _ = .{ &op1, &op2 }; @@ -1533,11 +1525,6 @@ test "mulWrap multi-multi unsigned" { } test "mulWrap multi-multi signed" { - switch (builtin.zig_backend) { - .stage2_c => return error.SkipZigTest, - else => {}, - } - var a = try Managed.initSet(testing.allocator, maxInt(SignedDoubleLimb) - 1); defer a.deinit(); var b = try Managed.initSet(testing.allocator, maxInt(SignedDoubleLimb)); @@ -1744,8 +1731,6 @@ test "div q=0 alias" { } test "div multi-multi q < r" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const op1 = 0x1ffffffff0078f432; const op2 = 0x1ffffffff01000000; var a = try Managed.initSet(testing.allocator, op1); @@ -2166,8 +2151,6 @@ test "div ceil multi-limb" { } test "div multi-multi with rem" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x8888999911110000ffffeeeeddddccccbbbbaaaa9999); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x99990000111122223333); @@ -2184,8 +2167,6 @@ test "div multi-multi with rem" { } test "div multi-multi no rem" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x8888999911110000ffffeeeedb4fec200ee3a4286361); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x99990000111122223333); @@ -2202,8 +2183,6 @@ test "div multi-multi no rem" { } test "div multi-multi (2 branch)" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x866666665555555588888887777777761111111111111111); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x86666666555555554444444433333333); @@ -2220,8 +2199,6 @@ test "div multi-multi (2 branch)" { } test "div multi-multi (3.1/3.3 branch)" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x11111111111111111111111111111111111111111111111111111111111111); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x1111111111111111111111111111111111111111171); @@ -2238,8 +2215,6 @@ test "div multi-multi (3.1/3.3 branch)" { } test "div multi-single zero-limb trailing" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x60000000000000000000000000000000000000000000000000000000000000000); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x10000000000000000); @@ -2258,8 +2233,6 @@ test "div multi-single zero-limb trailing" { } test "div multi-multi zero-limb trailing (with rem)" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000); @@ -2279,8 +2252,6 @@ test "div multi-multi zero-limb trailing (with rem)" { } test "div multi-multi zero-limb trailing (with rem) and dividend zero-limb count > divisor zero-limb count" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x8666666655555555888888877777777611111111111111110000000000000000); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x8666666655555555444444443333333300000000000000000000000000000000); @@ -2300,8 +2271,6 @@ test "div multi-multi zero-limb trailing (with rem) and dividend zero-limb count } test "div multi-multi zero-limb trailing (with rem) and dividend zero-limb count < divisor zero-limb count" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x86666666555555558888888777777776111111111111111100000000000000000000000000000000); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x866666665555555544444444333333330000000000000000); @@ -2832,10 +2801,6 @@ test "bitNotWrap signed multi" { } test "bitNotWrap more than two limbs" { - // This test requires int sizes greater than 128 bits. - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - var a = try Managed.initSet(testing.allocator, maxInt(Limb)); defer a.deinit(); @@ -3179,8 +3144,6 @@ test "gcd non-one large" { } test "gcd large multi-limb result" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - var a = try Managed.initSet(testing.allocator, 0x12345678123456781234567812345678123456781234567812345678); defer a.deinit(); var b = try Managed.initSet(testing.allocator, 0x12345671234567123456712345671234567123456712345671234567); @@ -3431,7 +3394,7 @@ test "big int conversion read/write twos complement" { var buffer1 = try testing.allocator.alloc(u8, 64); defer testing.allocator.free(buffer1); - const endians = [_]std.builtin.Endian{ .little, .big }; + const endians = [_]std.lang.Endian{ .little, .big }; const abi_size = 64; for (endians) |endian| { diff --git a/lib/std/math/float.zig b/lib/std/math/float.zig index 4bc67d494abac15c21e791f15fc56802e0fb87b8..e84bcdc4f295e1edad123673991df5b85f1cea4c 100644 --- a/lib/std/math/float.zig +++ b/lib/std/math/float.zig @@ -112,17 +112,17 @@ pub fn FloatRepr(comptime Float: type) type { /// This currently truncates denormal values, which needs to be fixed before this can be used to /// produce a rounded value. pub fn reconstruct(normalized: Normalized, sign: std.math.Sign) Float { - if (normalized.exponent > BiasedExponent.max_normal.unbias()) return @bitCast(Repr{ + if (normalized.exponent > comptime BiasedExponent.max_normal.unbias()) return @bitCast(Repr{ .mantissa = 0, .exponent = .infinite, .sign = sign, }); const mantissa = @as(Mantissa, 1 << fractional_bits) | normalized.fraction; - if (normalized.exponent < BiasedExponent.min_normal.unbias()) return @bitCast(Repr{ + if (normalized.exponent < comptime BiasedExponent.min_normal.unbias()) return @bitCast(Repr{ .mantissa = @truncate(std.math.shr( Mantissa, mantissa, - BiasedExponent.min_normal.unbias() - normalized.exponent, + (comptime BiasedExponent.min_normal.unbias()) - normalized.exponent, )), .exponent = .denormal, .sign = sign, diff --git a/lib/std/math/gamma.zig b/lib/std/math/gamma.zig index ce9a2b07f91b2cc5e5909069813d28bd4b7e9ce6..fed7e87ceef250eb92b67d43973289635c54d06c 100644 --- a/lib/std/math/gamma.zig +++ b/lib/std/math/gamma.zig @@ -263,8 +263,6 @@ test gamma { } test "gamma.special" { - if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 - inline for (&.{ f32, f64 }) |T| { try expect(std.math.isNan(gamma(T, -std.math.nan(T)))); try expect(std.math.isNan(gamma(T, std.math.nan(T)))); diff --git a/lib/std/math/hypot.zig b/lib/std/math/hypot.zig index f661e56d4ce9e46d51cce9487e783c4df78bed9c..99da74c335c342a277778f79bafe53e7fb2d7766 100644 --- a/lib/std/math/hypot.zig +++ b/lib/std/math/hypot.zig @@ -1,4 +1,3 @@ -const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; @@ -93,14 +92,10 @@ const hypot_test_cases = .{ }; test hypot { - if (builtin.cpu.arch.isPowerPC() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/171869 try expect(hypot(0.3, 0.4) == 0.5); } test "hypot.correct" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/171869 - inline for (.{ f16, f32, f64, f128 }) |T| { inline for (hypot_test_cases) |v| { const a: T, const b: T, const c: T = v; @@ -110,9 +105,6 @@ test "hypot.correct" { } test "hypot.precise" { - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/171869 - inline for (.{ f16, f32, f64 }) |T| { // f128 seems to be 5 ulp inline for (hypot_test_cases) |v| { const a: T, const b: T, const c: T = v; @@ -122,7 +114,6 @@ test "hypot.precise" { } test "hypot.special" { - if (builtin.cpu.arch.isPowerPC() and builtin.mode != .Debug) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/171869 @setEvalBranchQuota(2000); inline for (.{ f16, f32, f64, f128 }) |T| { try expect(math.isNan(hypot(nan(T), 0.0))); diff --git a/lib/std/math/isnan.zig b/lib/std/math/isnan.zig index bf2af9be1db7472aaceae82c3d052e606ce454b7..cfbe172ecdbe22890c9e928103b328f7fe23a256 100644 --- a/lib/std/math/isnan.zig +++ b/lib/std/math/isnan.zig @@ -27,13 +27,6 @@ test isNan { } test isSignalNan { - if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest; - - if (builtin.os.tag == .windows) { - // https://codeberg.org/ziglang/zig/issues/35519 - return error.SkipZigTest; - } - inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| { // TODO: Signalling NaN values get converted to quiet NaN values in // some cases where they shouldn't such that this can fail. @@ -43,6 +36,7 @@ test isSignalNan { builtin.cpu.arch != .hexagon and !builtin.cpu.arch.isMIPS32() and !builtin.cpu.arch.isPowerPC() and + !(builtin.cpu.arch.isX86() and builtin.os.tag == .windows and builtin.abi == .msvc) and // https://codeberg.org/ziglang/zig/issues/35519 builtin.zig_backend != .stage2_c) { try expect(isSignalNan(math.snan(T))); diff --git a/lib/std/math/log10.zig b/lib/std/math/log10.zig index a46948cac54dddf2dd7a822a68188f219086a9af..0dc5b2a8be90cd88276ec344c9de51a492b6430a 100644 --- a/lib/std/math/log10.zig +++ b/lib/std/math/log10.zig @@ -1,5 +1,4 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); const testing = std.testing; /// Returns the base-10 logarithm of x. @@ -135,10 +134,6 @@ inline fn less_than_5(x: u32) u32 { } test log10_int { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - inline for ( .{ u8, u16, u32, u64, u128, u256, u512 }, .{ 2, 4, 9, 19, 38, 77, 154 }, diff --git a/lib/std/math/modf.zig b/lib/std/math/modf.zig index 15515cde204a727d0191db34ace8adc68feb39e3..ea0433906958619572ad604d113f149c6fada392 100644 --- a/lib/std/math/modf.zig +++ b/lib/std/math/modf.zig @@ -1,5 +1,4 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); const math = std.math; const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; @@ -85,9 +84,6 @@ fn ModfTests(comptime T: type) type { try expectApproxEqAbs(expected_c, r.fpart, epsilon); } test "vector" { - if (builtin.os.tag.isDarwin() and builtin.cpu.arch == .aarch64) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/194256 - const widths = [_]comptime_int{ 1, 2, 3, 4, 8, 16 }; inline for (widths) |len| { diff --git a/lib/std/math/signbit.zig b/lib/std/math/signbit.zig index 115aaa26eb056e31c423695cd2a2cde79050d0a1..36a933e641ce35985523b25bb403f234143c20bc 100644 --- a/lib/std/math/signbit.zig +++ b/lib/std/math/signbit.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 8353c0ca8e209dd1516371926e0fbfd00f874ded..f6b2af68f914e5d31da6fc89f3702567d99fc1ac 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -9,6 +9,7 @@ const assert = debug.assert; const math = std.math; const testing = std.testing; const Endian = std.lang.Endian; +const AbsorbSentinel = std.meta.AbsorbSentinel; /// The standard library currently thoroughly depends on byte size /// being 8 bits. (see the use of u8 throughout allocation code as @@ -756,7 +757,8 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { } if (a.len != b.len) return false; - if (a.len == 0 or a.ptr == b.ptr) return true; + if (a.len == 0) return true; + if (@typeInfo(T) != .float and a.ptr == b.ptr) return true; for (a, b) |a_elem, b_elem| { if (a_elem != b_elem) return false; @@ -781,6 +783,9 @@ test eql { try testing.expect(eql(void, &.{ {}, {} }, &.{ {}, {} })); try testing.expect(!eql(void, &.{{}}, &.{ {}, {} })); + + const x: [3]f64 = .{ 42.0, math.nan(f64), 3.1415 }; + try testing.expect(!eql(f64, &x, &x)); } /// std.mem.eql heavily optimized for slices of bytes. @@ -850,20 +855,25 @@ pub const indexOfDiff = findDiff; /// Compares two slices and returns the index of the first inequality. /// Returns null if the slices are equal. pub fn findDiff(comptime T: type, a: []const T, b: []const T) ?usize { - const shortest = @min(a.len, b.len); - if (a.ptr == b.ptr) - return if (a.len == b.len) null else shortest; - var index: usize = 0; - while (index < shortest) : (index += 1) if (a[index] != b[index]) return index; - return if (a.len == b.len) null else shortest; + const shorter = @min(a.len, b.len); + if (@typeInfo(T) != .float and a.ptr == b.ptr) { + return if (a.len == b.len) null else shorter; + } + for (a[0..shorter], b[0..shorter], 0..) |a_elem, b_elem, i| { + if (a_elem != b_elem) return i; + } + return if (a.len == b.len) null else shorter; } test findDiff { - try testing.expectEqual(findDiff(u8, "one", "one"), null); - try testing.expectEqual(findDiff(u8, "one two", "one"), 3); - try testing.expectEqual(findDiff(u8, "one", "one two"), 3); - try testing.expectEqual(findDiff(u8, "one twx", "one two"), 6); - try testing.expectEqual(findDiff(u8, "xne", "one"), 0); + try testing.expectEqual(null, findDiff(u8, "one", "one")); + try testing.expectEqual(3, findDiff(u8, "one two", "one")); + try testing.expectEqual(3, findDiff(u8, "one", "one two")); + try testing.expectEqual(6, findDiff(u8, "one twx", "one two")); + try testing.expectEqual(0, findDiff(u8, "xne", "one")); + + const x: [3]f64 = .{ 42.0, math.nan(f64), 3.1415 }; + try testing.expectEqual(1, findDiff(f64, &x, &x)); } /// Takes a sentinel-terminated pointer and returns a slice preserving pointer attributes. @@ -1519,7 +1529,7 @@ pub fn findLast(comptime T: type, haystack: []const T, needle: []const T) ?usize if (needle.len == 0) return haystack.len; if (!std.meta.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4) - return lastIndexOfLinear(T, haystack, needle); + return findLastLinear(T, haystack, needle); const haystack_bytes = sliceAsBytes(haystack); const needle_bytes = sliceAsBytes(needle); @@ -1574,26 +1584,26 @@ pub fn findPos(comptime T: type, haystack: []const T, start_index: usize, needle test find { try testing.expect(find(u8, "one two three four five six seven eight nine ten eleven", "three four").? == 8); - try testing.expect(lastIndexOf(u8, "one two three four five six seven eight nine ten eleven", "three four").? == 8); + try testing.expect(findLast(u8, "one two three four five six seven eight nine ten eleven", "three four").? == 8); try testing.expect(find(u8, "one two three four five six seven eight nine ten eleven", "two two") == null); - try testing.expect(lastIndexOf(u8, "one two three four five six seven eight nine ten eleven", "two two") == null); + try testing.expect(findLast(u8, "one two three four five six seven eight nine ten eleven", "two two") == null); try testing.expect(find(u8, "one two three four five six seven eight nine ten", "").? == 0); - try testing.expect(lastIndexOf(u8, "one two three four five six seven eight nine ten", "").? == 48); + try testing.expect(findLast(u8, "one two three four five six seven eight nine ten", "").? == 48); try testing.expect(find(u8, "one two three four", "four").? == 14); - try testing.expect(lastIndexOf(u8, "one two three two four", "two").? == 14); + try testing.expect(findLast(u8, "one two three two four", "two").? == 14); try testing.expect(find(u8, "one two three four", "gour") == null); - try testing.expect(lastIndexOf(u8, "one two three four", "gour") == null); + try testing.expect(findLast(u8, "one two three four", "gour") == null); try testing.expect(find(u8, "foo", "foo").? == 0); - try testing.expect(lastIndexOf(u8, "foo", "foo").? == 0); + try testing.expect(findLast(u8, "foo", "foo").? == 0); try testing.expect(find(u8, "foo", "fool") == null); - try testing.expect(lastIndexOf(u8, "foo", "lfoo") == null); - try testing.expect(lastIndexOf(u8, "foo", "fool") == null); + try testing.expect(findLast(u8, "foo", "lfoo") == null); + try testing.expect(findLast(u8, "foo", "fool") == null); try testing.expect(find(u8, "foo foo", "foo").? == 0); - try testing.expect(lastIndexOf(u8, "foo foo", "foo").? == 4); - try testing.expect(lastIndexOfAny(u8, "boo, cat", "abo").? == 6); + try testing.expect(findLast(u8, "foo foo", "foo").? == 4); + try testing.expect(findLastAny(u8, "boo, cat", "abo").? == 6); try testing.expect(findScalarLast(u8, "boo", 'o').? == 2); } @@ -1615,13 +1625,13 @@ test "find multibyte" { // make haystack and needle long enough to trigger Boyer-Moore-Horspool algorithm const haystack = [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee, 0x00ff } ++ @as([100]u16, @splat(0)); const needle = [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee }; - try testing.expectEqual(lastIndexOf(u16, &haystack, &needle), 0); + try testing.expectEqual(findLast(u16, &haystack, &needle), 0); // check for misaligned false positives (little and big endian) const needleLE = [_]u16{ 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff }; - try testing.expectEqual(lastIndexOf(u16, &haystack, &needleLE), null); + try testing.expectEqual(findLast(u16, &haystack, &needleLE), null); const needleBE = [_]u16{ 0xaacc, 0xbbdd, 0xccee, 0xddff, 0xee00 }; - try testing.expectEqual(lastIndexOf(u16, &haystack, &needleBE), null); + try testing.expectEqual(findLast(u16, &haystack, &needleBE), null); } } @@ -2215,33 +2225,54 @@ test writeVarPackedInt { try testing.expectEqual(T{ .a = 1, .b = value, .c = 4 }, st); } -/// Swap the byte order of all the members of the fields of a struct -/// (Changing their endianness) -pub fn byteSwapAllFields(comptime S: type, ptr: *S) void { - byteSwapAllFieldsAligned(S, .of(S), ptr); +/// Deprecated: use `byteSwap` instead. +pub const byteSwapAllFields = byteSwap; + +/// Deprecated: use `byteSwapAligned` instead. +pub const byteSwapAllFieldsAligned = byteSwapAligned; + +/// Reverses the byte order. +/// Handles structs, unions, arrays, enums, floats, and integers recursively. +/// The order of extern struct fields and array elements remains unchanged and +/// will be byte swapped recursively. +/// Useful for converting between little-endian and big-endian representations. +pub fn byteSwap(comptime S: type, ptr: *S) void { + byteSwapAligned(S, .of(S), ptr); } -/// Swap the byte order of all the members of the fields of a struct -/// (Changing their endianness) -pub fn byteSwapAllFieldsAligned(comptime S: type, comptime a: Alignment, ptr: *align(a.toByteUnits()) S) void { +/// Reverses the byte order. +/// Handles structs, unions, arrays, enums, floats, and integers recursively. +/// The order of extern struct fields and array elements remains unchanged and +/// will be byte swapped recursively. +/// Useful for converting between little-endian and big-endian representations. +pub fn byteSwapAligned( + comptime S: type, + comptime a: Alignment, + ptr: *align(a.toByteUnits()) S, +) void { switch (@typeInfo(S)) { .@"struct" => |@"struct"| { if (@"struct".backing_integer) |Int| { ptr.* = @bitCast(@byteSwap(@as(Int, @bitCast(ptr.*)))); - } else inline for (@"struct".field_types, @"struct".field_names, @"struct".field_attrs) |f_type, f_name, f_attr| { - switch (@typeInfo(f_type)) { - .@"struct" => byteSwapAllFieldsAligned(f_type, .fromByteUnits(f_attr.@"align" orelse @alignOf(f_type)), &@field(ptr, f_name)), - .@"union", .array => byteSwapAllFieldsAligned(f_type, .fromByteUnits(f_attr.@"align" orelse @alignOf(f_type)), &@field(ptr, f_name)), - .@"enum" => { - @field(ptr, f_name) = @fromBackingInt(@intCast(@byteSwap(@backingInt(@field(ptr, f_name))))); - }, - .bool => {}, - .float => |float| { - @field(ptr, f_name) = @bitCast(@byteSwap(@as(@Int(.unsigned, float.bits), @bitCast(@field(ptr, f_name))))); - }, - else => { - @field(ptr, f_name) = @byteSwap(@field(ptr, f_name)); - }, + } else { + if (@"struct".layout != .@"extern") { + @compileError("byteSwapAligned expects a packed or extern struct"); + } + inline for (@"struct".field_types, @"struct".field_names, @"struct".field_attrs) |f_type, f_name, f_attr| { + switch (@typeInfo(f_type)) { + .@"struct" => byteSwapAligned(f_type, .fromByteUnits(f_attr.@"align" orelse @alignOf(f_type)), &@field(ptr, f_name)), + .@"union", .array => byteSwapAligned(f_type, .fromByteUnits(f_attr.@"align" orelse @alignOf(f_type)), &@field(ptr, f_name)), + .@"enum" => { + @field(ptr, f_name) = @fromBackingInt(@byteSwap(@backingInt(@field(ptr, f_name)))); + }, + .bool => {}, + .float => |float| { + @field(ptr, f_name) = @bitCast(@byteSwap(@as(@Int(.unsigned, float.bits), @bitCast(@field(ptr, f_name))))); + }, + else => { + @field(ptr, f_name) = @byteSwap(@field(ptr, f_name)); + }, + } } } }, @@ -2249,7 +2280,7 @@ pub fn byteSwapAllFieldsAligned(comptime S: type, comptime a: Alignment, ptr: *a ptr.* = @bitCast(@byteSwap(@as(Int, @bitCast(ptr.*)))); } else { if (@"union".layout != .@"extern") { - @compileError("byteSwapAllFields expects a packed or extern union"); + @compileError("byteSwapAligned expects a packed or extern union"); } const first_size = @bitSizeOf(@"union".field_types[0]); @@ -2266,13 +2297,21 @@ pub fn byteSwapAllFieldsAligned(comptime S: type, comptime a: Alignment, ptr: *a .array => |array| { byteSwapAllElements(array.child, ptr); }, + .@"enum" => { + ptr.* = @fromBackingInt(@byteSwap(@backingInt(ptr.*))); + }, + .bool => {}, + .float => |float| { + const int_repr: @Int(.unsigned, float.bits) = @bitCast(ptr.*); + ptr.* = @bitCast(@byteSwap(int_repr)); + }, else => { ptr.* = @byteSwap(ptr.*); }, } } -test byteSwapAllFields { +test byteSwap { const T = extern struct { f0: u8, f1: u16, @@ -2304,6 +2343,9 @@ test byteSwapAllFields { } align(4), f2: u32, }; + const E = enum(u32) { + _, + }; var s = T{ .f0 = 0x12, .f1 = 0x1234, @@ -2327,10 +2369,14 @@ test byteSwapAllFields { .f1 = .{ .f0 = 0x123456789ABCDEF0 }, .f2 = 0x87654321, }; - byteSwapAllFields(T, &s); - byteSwapAllFields(K, &k); - byteSwapAllFields(P, &p); - byteSwapAllFields(A, &a); + var e: E = @fromBackingInt(0x12345678); + var f: f32 = @bitCast(@as(u32, 0x4640e400)); + byteSwap(T, &s); + byteSwap(K, &k); + byteSwap(P, &p); + byteSwap(A, &a); + byteSwap(E, &e); + byteSwap(f32, &f); try std.testing.expectEqual(T{ .f0 = 0x12, .f1 = 0x3412, @@ -2354,28 +2400,15 @@ test byteSwapAllFields { .f1 = .{ .f0 = 0xF0DEBC9A78563412 }, .f2 = 0x21436587, }, a); + try std.testing.expectEqual(@as(E, @fromBackingInt(0x78563412)), e); + try std.testing.expectEqual(@as(f32, @bitCast(@as(u32, 0x00e44046))), f); } /// Reverses the byte order of all elements in a slice. /// Handles structs, unions, arrays, enums, floats, and integers recursively. /// Useful for converting between little-endian and big-endian representations. pub fn byteSwapAllElements(comptime Elem: type, slice: []Elem) void { - for (slice) |*elem| { - switch (@typeInfo(@TypeOf(elem.*))) { - .@"struct", .@"union", .array => byteSwapAllFields(@TypeOf(elem.*), elem), - .@"enum" => { - elem.* = @fromBackingInt(@intCast(@byteSwap(@backingInt(elem.*)))); - }, - .bool => {}, - .float => |float| { - const int_repr: @Int(.unsigned, float.bits) = @bitCast(elem.*); - elem.* = @bitCast(@byteSwap(int_repr)); - }, - else => { - elem.* = @byteSwap(elem.*); - }, - } - } + for (slice) |*elem| byteSwap(Elem, elem); } /// Returns an iterator that iterates over the slices of `buffer` that are not @@ -3453,8 +3486,8 @@ pub fn SplitBackwardsIterator(comptime T: type, comptime delimiter_type: Delimit pub fn next(self: *Self) ?[]const T { const end = self.index orelse return null; const start = if (switch (delimiter_type) { - .sequence => lastIndexOf(T, self.buffer[0..end], self.delimiter), - .any => lastIndexOfAny(T, self.buffer[0..end], self.delimiter), + .sequence => findLast(T, self.buffer[0..end], self.delimiter), + .any => findLastAny(T, self.buffer[0..end], self.delimiter), .scalar => findScalarLast(T, self.buffer[0..end], self.delimiter), }) |delim_start| blk: { self.index = delim_start; @@ -4706,22 +4739,28 @@ test "sliceAsBytes preserves pointer attributes" { try testing.expectEqual(in_attrs.@"align", out_attrs.@"align"); } -fn AbsorbSentinelReturnType(comptime Slice: type) type { - const info = @typeInfo(Slice).pointer; - assert(info.size == .slice); - return @Pointer(.slice, info.attrs, info.child, null); -} - /// If the provided slice is not sentinel terminated, do nothing and return that slice. /// If it is sentinel-terminated, return a non-sentinel-terminated slice with the /// length increased by one to include the absorbed sentinel element. -pub fn absorbSentinel(slice: anytype) AbsorbSentinelReturnType(@TypeOf(slice)) { +pub fn absorbSentinel(slice: anytype) AbsorbSentinel(@TypeOf(slice)) { const info = @typeInfo(@TypeOf(slice)).pointer; - comptime assert(info.size == .slice); - if (info.sentinel_ptr == null) { - return slice; - } else { - return slice.ptr[0 .. slice.len + 1]; + switch (info.size) { + .slice => { + if (info.sentinel_ptr == null) { + return slice; + } else { + return slice.ptr[0 .. slice.len + 1]; + } + }, + .one => { + const child_info = @typeInfo(info.child).array; + if (child_info.sentinel_ptr == null) { + return slice; + } else { + return slice[0 .. child_info.len + 1]; + } + }, + else => unreachable, } } @@ -4730,21 +4769,28 @@ test absorbSentinel { var buffer: [3:0]u8 = .{ 1, 2, 3 }; const foo: [:0]const u8 = &buffer; const bar: []const u8 = &buffer; + const baz: *const [3:0]u8 = &buffer; try testing.expectEqual([]const u8, @TypeOf(absorbSentinel(foo))); try testing.expectEqual([]const u8, @TypeOf(absorbSentinel(bar))); + try testing.expectEqual(*const [4]u8, @TypeOf(absorbSentinel(baz))); try testing.expectEqualSlices(u8, &.{ 1, 2, 3, 0 }, absorbSentinel(foo)); try testing.expectEqualSlices(u8, &.{ 1, 2, 3 }, absorbSentinel(bar)); + try testing.expectEqualSlices(u8, &.{ 1, 2, 3, 0 }, absorbSentinel(baz)); } { var buffer: [3:0]u8 = .{ 1, 2, 3 }; const foo: [:0]u8 = &buffer; const bar: []u8 = &buffer; + const baz: *[3:0]u8 = &buffer; try testing.expectEqual([]u8, @TypeOf(absorbSentinel(foo))); try testing.expectEqual([]u8, @TypeOf(absorbSentinel(bar))); + try testing.expectEqual(*[4]u8, @TypeOf(absorbSentinel(baz))); var expected_foo = [_]u8{ 1, 2, 3, 0 }; try testing.expectEqualSlices(u8, &expected_foo, absorbSentinel(foo)); var expected_bar = [_]u8{ 1, 2, 3 }; try testing.expectEqualSlices(u8, &expected_bar, absorbSentinel(bar)); + var expected_baz = [_]u8{ 1, 2, 3, 0 }; + try testing.expectEqualSlices(u8, &expected_baz, absorbSentinel(baz)); } } @@ -4780,62 +4826,58 @@ pub fn alignForwardLog2(addr: usize, log2_alignment: u8) usize { pub fn doNotOptimizeAway(val: anytype) void { if (@inComptime()) return; - const max_gp_register_bits = @bitSizeOf(c_long); - const t = @typeInfo(@TypeOf(val)); - switch (t) { + if (builtin.zig_backend == .stage2_c and builtin.abi == .msvc) { + _ = @atomicRmw(*const anyopaque, @as(*volatile *const anyopaque, &struct { + var escape: *const anyopaque = undefined; + }.escape), .Xchg, &val, .acq_rel); // TODO: syncscope("singlethreaded") + return; + } + + switch (@typeInfo(@TypeOf(val))) { .void, .null, .comptime_int, .comptime_float => return, .@"enum" => doNotOptimizeAway(@backingInt(val)), .bool => doNotOptimizeAway(@intFromBool(val)), - .int => { - const bits = t.int.bits; - if (bits <= max_gp_register_bits and builtin.zig_backend != .stage2_c) { + .int => |int| { + // SPIR-V targets do not have registers per se, they have values + // tied to IDs that can be passed to valid instructions. Some + // SPIR-V targets do not define c_long, so we just allow any sized + // integer on these targets + const val_fits_in_gp_register = builtin.target.cpu.arch.isSpirV() or fits: { + const max_gp_register_bits = @bitSizeOf(c_long); + break :fits int.bits <= max_gp_register_bits; + }; + if (val_fits_in_gp_register) { const val2 = @as( - @Int(t.int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, bits))), + @Int(int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, int.bits))), val, ); asm volatile ("" : : [_] "r" (val2), ); - } else doNotOptimizeAway(&val); - }, - .float => { - if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c) { - asm volatile ("" - : - : [_] "rm" (val), - ); - } else doNotOptimizeAway(&val); - }, - .pointer => { - if (builtin.zig_backend == .stage2_c) { - doNotOptimizeAwayC(val); } else { - asm volatile ("" - : - : [_] "m" (val), - : .{ .memory = true }); + doNotOptimizeAway(&val); } }, - .array => { - if (t.array.len * @sizeOf(t.array.child) <= 64) { - for (val) |v| doNotOptimizeAway(v); - } else doNotOptimizeAway(&val); + .float => |float| switch (float.bits) { + else => comptime unreachable, + 16, 80, 128 => doNotOptimizeAway(&val), + 32, 64 => asm volatile ("" + : + : [_] "rm" (val), + ), }, + .pointer => asm volatile ("" + : + : [_] "m" (val), + : .{ .memory = true }), + .array => |array| if (array.len * @sizeOf(array.child) <= 64) { + for (val) |v| doNotOptimizeAway(v); + } else doNotOptimizeAway(&val), else => doNotOptimizeAway(&val), } } -/// .stage2_c doesn't support asm blocks yet, so use volatile stores instead -var deopt_target: if (builtin.zig_backend == .stage2_c) u8 else void = undefined; -fn doNotOptimizeAwayC(ptr: anytype) void { - const dest = @as(*volatile u8, @ptrCast(&deopt_target)); - for (asBytes(ptr)) |b| { - dest.* = b; - } - dest.* = 0; -} - test doNotOptimizeAway { comptime doNotOptimizeAway("test"); @@ -4994,12 +5036,9 @@ pub fn alignInSlice(slice: anytype, comptime new_alignment: usize) ?AlignedSlice } test "read/write(Var)PackedInt" { - switch (builtin.cpu.arch) { - // This test generates too much code to execute on WASI. - // LLVM backend fails with "too many locals: locals exceed maximum" - .wasm32, .wasm64 => return error.SkipZigTest, - else => {}, - } + // This test generates too much code to execute on WASI. + // LLVM backend fails with "too many locals: locals exceed maximum" + if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; const foreign_endian: Endian = if (native_endian == .big) .little else .big; const expect = std.testing.expect; diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index 80341ecc2fa30523ef26bf7f1f68087fea18b925..bbd9e94c175286f3c2e7968b79851e4e48afbc17 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -8,6 +8,8 @@ const assert = std.debug.assert; const math = std.math; const mem = std.mem; const Alignment = std.mem.Alignment; +const Slice = std.meta.Slice; +const AbsorbSentinel = std.meta.AbsorbSentinel; pub const Error = error{OutOfMemory}; pub const Log2Align = math.Log2Int(usize); @@ -316,8 +318,10 @@ pub fn allocBytesAligned( /// `new_len` may be zero, in which case the allocation is freed. pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { const slice_info = @typeInfo(@TypeOf(allocation)).pointer; - comptime assert(slice_info.size == .slice); - const T = slice_info.child; + const T = if (slice_info.size != .slice) comptime T: { + assert(slice_info.size == .one); + break :T @typeInfo(slice_info.child).array.child; + } else slice_info.child; if (new_len == 0) { self.free(allocation); return true; @@ -326,9 +330,6 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { return false; } const old_memory: []u8 = @ptrCast(@constCast(mem.absorbSentinel(allocation))); - // I would like to use saturating multiplication here, but LLVM cannot lower it - // on WebAssembly: https://github.com/ziglang/zig/issues/9660 - //const new_len_bytes = new_len *| @sizeOf(T); const new_len_bytes = math.mul(usize, @sizeOf(T), new_len) catch return false; return self.rawResize( old_memory, @@ -354,10 +355,12 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { /// `new_len` may be zero, in which case the allocation is freed. /// /// If the allocation's elements' type is zero bytes sized, `allocation.len` is set to `new_len`. -pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?@TypeOf(allocation) { +pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?Slice(AbsorbSentinel(@TypeOf(allocation))) { const slice_info = @typeInfo(@TypeOf(allocation)).pointer; - comptime assert(slice_info.size == .slice); - const T = slice_info.child; + const T = if (slice_info.size != .slice) comptime T: { + assert(slice_info.size == .one); + break :T @typeInfo(slice_info.child).array.child; + } else slice_info.child; if (new_len == 0) { self.free(allocation); @@ -372,9 +375,6 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?@TypeOf(allo return new_memory; } const old_memory: []u8 = @ptrCast(@constCast(mem.absorbSentinel(allocation))); - // I would like to use saturating multiplication here, but LLVM cannot lower it - // on WebAssembly: https://github.com/ziglang/zig/issues/9660 - //const new_len_bytes = new_len *| @sizeOf(T); const new_len_bytes = math.mul(usize, @sizeOf(T), new_len) catch return null; const new_ptr = self.rawRemap( old_memory, @@ -399,7 +399,7 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?@TypeOf(allo /// do the realloc more efficiently than the caller /// * `resize` which returns `false` when the `Allocator` implementation cannot /// change the size without relocating the allocation. -pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) Error!@TypeOf(old_mem) { +pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) Error!Slice(AbsorbSentinel(@TypeOf(old_mem))) { return self.reallocAdvanced(old_mem, new_n, @returnAddress()); } @@ -408,10 +408,12 @@ pub fn reallocAdvanced( old_mem: anytype, new_n: usize, return_address: usize, -) Error!@TypeOf(old_mem) { +) Error!Slice(AbsorbSentinel(@TypeOf(old_mem))) { const slice_info = @typeInfo(@TypeOf(old_mem)).pointer; - comptime assert(slice_info.size == .slice); - const T = slice_info.child; + const T = if (slice_info.size != .slice) comptime T: { + assert(slice_info.size == .one); + break :T @typeInfo(slice_info.child).array.child; + } else slice_info.child; if (old_mem.len == 0) { return self.allocAdvancedWithRetAddr(T, .fromByteUnitsOptional(slice_info.attrs.@"align"), new_n, return_address); } @@ -446,7 +448,6 @@ pub fn reallocAdvanced( pub fn free(self: Allocator, memory: anytype) void { const slice_info = @typeInfo(@TypeOf(memory)).pointer; if (slice_info.size != .slice) { - // slicing with comptime-known start and end results in *[len]T, which may be free'd comptime assert(slice_info.size == .one and @typeInfo(slice_info.child) == .array); } const bytes: []u8 = @ptrCast(@constCast(mem.absorbSentinel(memory))); @@ -587,4 +588,43 @@ fn unreachableFree( test failing { const f: Allocator = .failing; try std.testing.expectError(error.OutOfMemory, f.alloc(u8, 123)); + // Expect very large allocations to fail at the implementation level and not in the interface + try std.testing.expectError(error.OutOfMemory, f.alloc(u8, std.math.maxInt(usize))); + try std.testing.expectError(error.OutOfMemory, f.allocSentinel(u8, std.math.maxInt(usize) - 1, 0)); +} + +test "free single-pointer to array" { + const allocator = std.testing.allocator; + { + const allocation = try allocator.alloc(u32, 128); + allocation[127] = 0; + const ptr: *[127:0]u32 = allocation[0..127 :0]; + allocator.free(ptr); + } + { + const allocation = try allocator.alloc(u32, 128); + allocation[127] = 0; + const ptr: *[127:0]u32 = allocation[0..127 :0]; + if (allocator.resize(ptr, 16)) { + allocator.free(ptr[0..16]); + } else allocator.free(ptr); + } + { + const allocation = try allocator.alloc(u32, 128); + allocation[127] = 0; + const ptr: *[127:0]u32 = allocation[0..127 :0]; + if (allocator.remap(ptr, 16)) |new| { + allocator.free(new); + } else allocator.free(ptr); + } + { + const allocation = try allocator.alloc(u32, 128); + allocation[127] = 0; + const ptr: *[127:0]u32 = allocation[0..127 :0]; + if (allocator.realloc(ptr, 16)) |new| { + allocator.free(new); + } else |_| { + allocator.free(allocation); + } + } } diff --git a/lib/std/meta.zig b/lib/std/meta.zig index cfeb6a758524a4e0e5a3f9e6dcac57fd029123c6..f1dec9a1df078b0cf3916573c25fd5fe62bfc9ce 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -1,10 +1,9 @@ const builtin = @import("builtin"); + const std = @import("std.zig"); -const debug = std.debug; +const assert = std.debug.assert; const mem = std.mem; -const math = std.math; const testing = std.testing; -const root = @import("root"); pub const TrailerFlags = @import("meta/trailer_flags.zig").TrailerFlags; @@ -198,15 +197,17 @@ test containerLayout { try testing.expect(containerLayout(U3) == .@"extern"); } -/// Instead of this function, prefer to use e.g. `@typeInfo(foo).@"struct".decl_names` -/// directly when you know what kind of type it is. +/// Returns the list of declaration names of namespace types. +/// +/// This function is only useful when the callsite does not know statically +/// which kind of container it is. pub fn declarations(comptime T: type) []const [:0]const u8 { return switch (@typeInfo(T)) { .@"struct" => |info| info.decl_names, .@"enum" => |info| info.decl_names, .@"union" => |info| info.decl_names, .@"opaque" => |info| info.decl_names, - else => @compileError("Expected struct, enum, union, or opaque type, found '" ++ @typeName(T) ++ "'"), + else => comptime unreachable, // type lacks namespace }; } @@ -242,10 +243,13 @@ test declarations { } /// To be removed after Zig 0.17.0 is tagged. -pub const declarationInfo = @compileError("Deprecated; use '@hasDecl' instead"); +pub const declarationInfo = @compileError("deprecated in favor of @hasDecl"); /// To be removed after Zig 0.17.0 is tagged. -pub const fields = @compileError("Deprecated; use 'fieldNames' and 'fieldTypes' instead"); +pub const fields = @compileError("deprecated in favor of @typeInfo"); +/// Deprecated in favor of `@typeInfo`. +/// +/// To be removed after 0.17.0 is tagged. pub fn fieldInfo(comptime T: type, comptime field: FieldEnum(T)) switch (@typeInfo(T)) { .@"struct" => struct { name: [:0]const u8, type: type, attrs: Type.Struct.FieldAttributes }, .@"union" => struct { name: [:0]const u8, type: type, attrs: Type.Union.FieldAttributes }, @@ -299,13 +303,16 @@ test fieldInfo { try testing.expect(comptime uf.type == u8); } +/// Deprecated in favor of `@typeInfo`. +/// +/// To be removed after 0.17.0 is tagged. pub fn fieldNames(comptime T: type) []const [:0]const u8 { return switch (@typeInfo(T)) { .@"struct" => |s| s.field_names, .@"union" => |u| u.field_names, .@"enum" => |e| e.field_names, .error_set => |es| es.error_names.?, - else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"), + else => comptime unreachable, }; } @@ -337,11 +344,14 @@ test fieldNames { try testing.expectEqualSlices(u8, u1names[1], "b"); } +/// Deprecated in favor of `@typeInfo`. +/// +/// To be removed after 0.17.0 is tagged. pub fn fieldTypes(comptime T: type) []const type { return switch (@typeInfo(T)) { .@"struct" => |s| s.field_types, .@"union" => |u| u.field_types, - else => @compileError("Expected struct or union type, found '" ++ @typeName(T) ++ "'"), + else => comptime unreachable, }; } @@ -821,8 +831,8 @@ pub fn isError(error_union: anytype) bool { } test isError { - try std.testing.expect(isError(math.divTrunc(u8, 5, 0))); - try std.testing.expect(!isError(math.divTrunc(u8, 5, 5))); + try std.testing.expect(isError(std.math.divTrunc(u8, 5, 0))); + try std.testing.expect(!isError(std.math.divTrunc(u8, 5, 5))); } /// Returns true if a type has a namespace and the namespace contains `name`; @@ -1070,3 +1080,50 @@ test hasUniqueRepresentation { try testing.expect(hasUniqueRepresentation(StructWithComptimeFields)); } + +/// Given a pointer type, type-erases the array length if present, returning an +/// equivalent pointer type that is always a slice. +pub fn Slice(comptime Pointer: type) type { + const info = @typeInfo(Pointer).pointer; + switch (info.size) { + .slice => return Pointer, + .one => { + const child_info = @typeInfo(info.child); + comptime assert(child_info == .array); + const sentinel_ptr: ?*const child_info.array.child = @ptrCast(@alignCast(child_info.array.sentinel_ptr)); + return @Pointer( + .slice, + info.attrs, + child_info.array.child, + if (sentinel_ptr) |ptr| ptr.* else null, + ); + }, + else => unreachable, + } +} + +/// Given a pointer type, removes the sentinel if present, returning an +/// equivalent pointer type with no sentinel +pub fn AbsorbSentinel(comptime Pointer: type) type { + const info = @typeInfo(Pointer).pointer; + switch (info.size) { + .slice => return @Pointer(.slice, info.attrs, info.child, null), + .one => { + const child_info = @typeInfo(info.child).array; + if (child_info.sentinel_ptr == null) { + return Pointer; + } else { + return @Pointer(.one, info.attrs, [child_info.len + 1]child_info.child, null); + } + }, + else => unreachable, + } +} + +test Slice { + try testing.expectEqual([]i32, Slice(*[10]i32)); +} + +test AbsorbSentinel { + try testing.expectEqual(*[5]u32, AbsorbSentinel(*[4:0]u32)); +} diff --git a/lib/std/meta/trailer_flags.zig b/lib/std/meta/trailer_flags.zig index 3918f954143a73cc524c0aad7ac13835fb85fce3..acad4afabebd35ae58525f232906b793b04075d2 100644 --- a/lib/std/meta/trailer_flags.zig +++ b/lib/std/meta/trailer_flags.zig @@ -39,7 +39,7 @@ pub fn TrailerFlags(comptime Fields: type) type { break :blk @Struct(.auto, null, &field_names, &field_types, &field_attrs); }; - pub const Self = @This(); + const Self = @This(); pub fn has(self: Self, comptime field: FieldEnum) bool { const field_index = @backingInt(field); diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index a10f261e31ef8d4f47a976eebb3f637c199f835f..ce6265655eb690499577bc7fbd29c19eab375854 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -163,7 +163,7 @@ pub fn MultiArrayList(comptime T: type) type { }; } - /// This function is used in the debugger pretty formatters in tools/ to fetch the + /// This function is used in the debugger pretty formatters in lib/lldb/ to fetch the /// child field order and entry type to facilitate fancy debug printing for this type. fn dbHelper(self: *Slice, child: *Elem, field: *Field, entry: *Entry) void { _ = self; @@ -681,7 +681,7 @@ pub fn MultiArrayList(comptime T: type) type { } break :entry @Struct(.@"extern", null, &entry_field_names, &entry_field_types, &entry_field_attrs); }; - /// This function is used in the debugger pretty formatters in tools/ to fetch the + /// This function is used in the debugger pretty formatters in lib/lldb/ to fetch the /// child field order and entry type to facilitate fancy debug printing for this type. fn dbHelper(self: *Self, child: *Elem, field: *Field, entry: *Entry) void { _ = self; diff --git a/lib/std/os/emscripten.zig b/lib/std/os/emscripten.zig index 5df52dd9b87fada9ccc2d5286d864902b3894e3d..da0c85d1b05a5758a52aeae315446e91fc982477 100644 --- a/lib/std/os/emscripten.zig +++ b/lib/std/os/emscripten.zig @@ -730,7 +730,7 @@ pub const clock_t = i32; pub const dl_phdr_info = extern struct { addr: usize, name: ?[*:0]const u8, - phdr: [*]std.elf.Phdr, + phdr: [*]std.elf.ElfN.Phdr, phnum: u16, }; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 5a3a0ff263ea99affa6c102f15699ca7eb079898..2df4fdf75d80e01ca25cb6bb6ea94664709a0a8c 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -2058,8 +2058,8 @@ pub const F = struct { }, }; - pub const SETSIG = if (is_hppa or native_arch == .alpha) 13 else 11; - pub const GETSIG = if (is_hppa or native_arch == .alpha) 14 else 12; + pub const SETSIG = if (is_hppa) 13 else 10; + pub const GETSIG = if (is_hppa) 14 else 11; pub const SETOWN_EX = 15; pub const GETOWN_EX = 16; @@ -8181,13 +8181,11 @@ pub const rusage = extern struct { pub const NCC = if (is_ppc) 10 else 8; pub const NCCS = if (is_mips) - 32 -else if (is_ppc or native_arch == .alpha) - 19 + 23 else if (is_sparc) 17 else - 32; + 19; pub const speed_t = if (is_ppc) enum(c_uint) { B0 = 0x0000000, diff --git a/lib/std/os/linux/IoUring.zig b/lib/std/os/linux/IoUring.zig index 49720ac4eaf641b39fdd0f1ea066ddc4245857ba..a3723244cd9b23a04bd2dacf800fd83b95d39a4c 100644 --- a/lib/std/os/linux/IoUring.zig +++ b/lib/std/os/linux/IoUring.zig @@ -267,7 +267,7 @@ pub fn cq_ready(self: *IoUring) u32 { } /// Copies as many CQEs as are ready, and that can fit into the destination `cqes` slice. -/// If none are available, enters into the kernel to wait for at most `wait_nr` CQEs. +/// If none are available, enters into the kernel to wait for at least `wait_nr` CQEs. /// Returns the number of CQEs copied, advancing the CQ ring. /// Provides all the wait/peek methods found in liburing, but with batching and a single method. /// The rationale for copying CQEs rather than copying pointers is that pointers are 8 bytes diff --git a/lib/std/os/linux/IoUring/test.zig b/lib/std/os/linux/IoUring/test.zig index 40429fbaab1cb7fb35a90427c69c2640ad907ed6..7cfe8e3ce77af942e321888dbcf3cf3d4f20002a 100644 --- a/lib/std/os/linux/IoUring/test.zig +++ b/lib/std/os/linux/IoUring/test.zig @@ -475,9 +475,6 @@ test "close" { } test "accept/connect/send/recv" { - const io = testing.io; - _ = io; - var ring = IoUring.init(16, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -620,7 +617,7 @@ test "timeout (after a relative time)" { const ms = 10; const margin = 5; - const ts: linux.kernel_timespec = .{ .sec = 0, .nsec = ms * 1000000 }; + const ts: linux.kernel_timespec = .{ .sec = 0, .nsec = ms * std.time.ns_per_ms }; const started = std.Io.Clock.awake.now(io); const sqe = try ring.timeout(0x55555555, &ts, 0, 0); @@ -730,9 +727,6 @@ test "timeout_remove" { } test "accept/connect/recv/link_timeout" { - const io = testing.io; - _ = io; - var ring = IoUring.init(16, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -748,7 +742,7 @@ test "accept/connect/recv/link_timeout" { const sqe_recv = try ring.recv(0xffffffff, socket_test_harness.server, .{ .buffer = buffer_recv[0..] }, 0); sqe_recv.flags |= linux.IOSQE_IO_LINK; - const ts = linux.kernel_timespec{ .sec = 0, .nsec = 1000000 }; + const ts: linux.kernel_timespec = .{ .sec = 0, .nsec = std.time.ns_per_ms }; _ = try ring.link_timeout(0x22222222, &ts, 0); const nr_wait = try ring.submit(); @@ -883,9 +877,6 @@ test "statx" { } test "accept/connect/recv/cancel" { - const io = testing.io; - _ = io; - var ring = IoUring.init(16, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -1568,9 +1559,6 @@ test "remove_buffers" { } test "provide_buffers: accept/connect/send/recv" { - const io = testing.io; - _ = io; - var ring = IoUring.init(16, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -1777,11 +1765,6 @@ test "accept multishot" { } test "accept/connect/send_zc/recv" { - try skipKernelLessThan(.{ .major = 6, .minor = 0, .patch = 0 }); - - const io = testing.io; - _ = io; - var ring = IoUring.init(16, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -1789,6 +1772,13 @@ test "accept/connect/send_zc/recv" { }; defer ring.deinit(); + const probe = ring.get_probe() catch return error.SkipZigTest; + const ops_not_supported = !probe.is_supported(.ACCEPT) or + !probe.is_supported(.CONNECT) or + !probe.is_supported(.SEND_ZC) or + !probe.is_supported(.RECV); + if (ops_not_supported) return error.SkipZigTest; + const socket_test_harness = try createSocketTestHarness(&ring); defer socket_test_harness.close(); @@ -1836,16 +1826,16 @@ test "accept/connect/send_zc/recv" { } test "accept_direct" { - if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30854 - - try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 }); - var ring = IoUring.init(1, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, else => return err, }; defer ring.deinit(); + + const probe = ring.get_probe() catch return error.SkipZigTest; + if (!probe.is_supported(.ACCEPT)) return error.SkipZigTest; + var address: linux.sockaddr.in = .{ .port = 0, .addr = @as(*align(1) const u32, @ptrCast( @@ -1923,13 +1913,6 @@ test "accept_direct" { } test "accept_multishot_direct" { - try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 }); - - if (builtin.cpu.arch == .riscv64) { - // https://github.com/ziglang/zig/issues/25734 - return error.SkipZigTest; - } - var ring = IoUring.init(1, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -1937,6 +1920,9 @@ test "accept_multishot_direct" { }; defer ring.deinit(); + const probe = ring.get_probe() catch return error.SkipZigTest; + if (!probe.is_supported(.ACCEPT)) return error.SkipZigTest; + var address: linux.sockaddr.in = .{ .port = 0, .addr = @as(*align(1) const u32, @ptrCast( @@ -1991,8 +1977,6 @@ test "accept_multishot_direct" { } test "socket" { - try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 }); - var ring = IoUring.init(1, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -2000,6 +1984,9 @@ test "socket" { }; defer ring.deinit(); + const probe = ring.get_probe() catch return error.SkipZigTest; + if (!probe.is_supported(.SOCKET)) return error.SkipZigTest; + // prepare, submit socket operation _ = try ring.socket(0, linux.AF.INET, posix.SOCK.STREAM, 0, 0); try testing.expectEqual(@as(u32, 1), try ring.submit()); @@ -2014,8 +2001,6 @@ test "socket" { } test "socket_direct/socket_direct_alloc/close_direct" { - try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 }); - var ring = IoUring.init(2, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -2023,6 +2008,9 @@ test "socket_direct/socket_direct_alloc/close_direct" { }; defer ring.deinit(); + const probe = ring.get_probe() catch return error.SkipZigTest; + if (!probe.is_supported(.SOCKET) or !probe.is_supported(.CLOSE)) return error.SkipZigTest; + var registered_fds: [3]linux.fd_t = @splat(-1); try ring.register_files(registered_fds[0..]); @@ -2097,8 +2085,6 @@ test "socket_direct/socket_direct_alloc/close_direct" { } test "openat_direct/close_direct" { - try skipKernelLessThan(.{ .major = 5, .minor = 19, .patch = 0 }); - var ring = IoUring.init(2, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -2106,6 +2092,9 @@ test "openat_direct/close_direct" { }; defer ring.deinit(); + const probe = ring.get_probe() catch return error.SkipZigTest; + if (!probe.is_supported(.OPENAT) or !probe.is_supported(.CLOSE)) return error.SkipZigTest; + var registered_fds: [3]linux.fd_t = @splat(-1); try ring.register_files(registered_fds[0..]); @@ -2148,9 +2137,6 @@ test "openat_direct/close_direct" { } test "ring mapped buffers recv" { - const io = testing.io; - _ = io; - var ring = IoUring.init(16, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -2238,9 +2224,6 @@ test "ring mapped buffers recv" { } test "ring mapped buffers multishot recv" { - const io = testing.io; - _ = io; - var ring = IoUring.init(16, 0) catch |err| switch (err) { error.SystemOutdated => return error.SkipZigTest, error.PermissionDenied => return error.SkipZigTest, @@ -2672,7 +2655,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness { // All good - return SocketTestHarness{ + return .{ .listener = listener_socket, .server = cqe_accept.res, .client = client, @@ -2695,27 +2678,6 @@ fn createListenerSocket(address: *linux.sockaddr.in) !posix.socket_t { return listener_socket; } -/// For use in tests. Returns SkipZigTest if kernel version is less than required. -inline fn skipKernelLessThan(required: std.SemanticVersion) !void { - var uts: linux.utsname = undefined; - const res = linux.uname(&uts); - switch (linux.errno(res)) { - .SUCCESS => {}, - else => |errno| return posix.unexpectedErrno(errno), - } - - const release = mem.sliceTo(&uts.release, 0); - // Strips potential extra, as kernel version might not be semver compliant, example "6.8.9-300.fc40.x86_64" - const extra_index = std.mem.indexOfAny(u8, release, "-+"); - const stripped = release[0..(extra_index orelse release.len)]; - // Make sure the input don't rely on the extra we just stripped - try testing.expect(required.pre == null and required.build == null); - - var current = try std.SemanticVersion.parse(stripped); - current.pre = null; // don't check pre field - if (required.order(current) == .gt) return error.SkipZigTest; -} - fn addrAny(addr: *linux.sockaddr.in) *linux.sockaddr { return @ptrCast(addr); } diff --git a/lib/std/os/linux/aarch64.zig b/lib/std/os/linux/aarch64.zig index a49c1d48bedd05331da4a7a25c6f1006797aa251..431097feccf104eba84a3f347fac6fe29ae1eb57 100644 --- a/lib/std/os/linux/aarch64.zig +++ b/lib/std/os/linux/aarch64.zig @@ -154,7 +154,7 @@ pub const restore = restore_rt; pub fn restore_rt() callconv(.naked) noreturn { switch (builtin.zig_backend) { .stage2_c => asm volatile ( - \\ mov x8, %[number] + \\ mov w8, %[number] \\ svc #0 : : [number] "i" (@backingInt(SYS.rt_sigreturn)), diff --git a/lib/std/os/linux/s390x.zig b/lib/std/os/linux/s390x.zig index 9b9ca0cd0327c93c1260128f42a497e8d96a3094..3c44beeb8df7bb5d7f0d7d7fb13f3c35c840da01 100644 --- a/lib/std/os/linux/s390x.zig +++ b/lib/std/os/linux/s390x.zig @@ -174,19 +174,35 @@ pub fn clone() callconv(.naked) u64 { } pub fn restore() callconv(.naked) noreturn { - asm volatile ( - \\svc 0 - : - : [number] "{r1}" (@backingInt(SYS.sigreturn)), - ); + switch (builtin.zig_backend) { + .stage2_c => asm volatile ( + \\lghi %%r1, %[number] + \\svc 0 + : + : [number] "K" (@backingInt(SYS.sigreturn)), + ), + else => asm volatile ( + \\svc 0 + : + : [number] "{r1}" (@backingInt(SYS.sigreturn)), + ), + } } pub fn restore_rt() callconv(.naked) noreturn { - asm volatile ( - \\svc 0 - : - : [number] "{r1}" (@backingInt(SYS.rt_sigreturn)), - ); + switch (builtin.zig_backend) { + .stage2_c => asm volatile ( + \\lghi %%r1, %[number] + \\svc 0 + : + : [number] "K" (@backingInt(SYS.rt_sigreturn)), + ), + else => asm volatile ( + \\svc 0 + : + : [number] "{r1}" (@backingInt(SYS.rt_sigreturn)), + ), + } } pub const time_t = i64; diff --git a/lib/std/os/linux/sparc.zig b/lib/std/os/linux/sparc.zig index 4a2e7188a6b2a9cf582edddf204ce8fc61d4fb95..c8addd36c45bfc08aff71672c2aeef42bb948f06 100644 --- a/lib/std/os/linux/sparc.zig +++ b/lib/std/os/linux/sparc.zig @@ -260,13 +260,16 @@ pub fn clone() callconv(.naked) u32 { pub const restore = restore_rt; -// Need to use C ABI here instead of naked -// to prevent an infinite loop when calling rt_sigreturn. -pub fn restore_rt() callconv(.c) void { - return asm volatile ("t 0x10" +pub fn restore_rt() callconv(.naked) noreturn { + asm volatile ( + \\ nop + \\ nop + ); + asm volatile ( + \\ t 0x10 : : [number] "{g1}" (@backingInt(SYS.rt_sigreturn)), - : .{ .memory = true, .xcc = true, .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); + ); } pub const VDSO = struct { diff --git a/lib/std/os/linux/sparc64.zig b/lib/std/os/linux/sparc64.zig index f7e859cc72abfe37dfee1f5ab5927979c2625615..955ae477c3f81d1f190ad7cb440108747cff9b56 100644 --- a/lib/std/os/linux/sparc64.zig +++ b/lib/std/os/linux/sparc64.zig @@ -259,13 +259,16 @@ pub fn clone() callconv(.naked) u64 { pub const restore = restore_rt; -// Need to use C ABI here instead of naked -// to prevent an infinite loop when calling rt_sigreturn. -pub fn restore_rt() callconv(.c) void { - return asm volatile ("t 0x6d" +pub fn restore_rt() callconv(.naked) noreturn { + asm volatile ( + \\ nop + \\ nop + ); + asm volatile ( + \\ t 0x6d : : [number] "{g1}" (@backingInt(SYS.rt_sigreturn)), - : .{ .memory = true, .xcc = true, .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); + ); } pub const VDSO = struct { diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig index e02ba39840497e2dec5d55ed1a7bb4a05b17ad01..81ccd5cb56eb90ff1d2d9582f45c6b22630a5173 100644 --- a/lib/std/os/linux/tls.zig +++ b/lib/std/os/linux/tls.zig @@ -22,7 +22,7 @@ const page_size_min = std.heap.page_size_min; /// Represents an ELF TLS variant. /// /// In all variants, the TP and the TLS blocks must be aligned to the `p_align` value in the -/// `PT_TLS` ELF program header. Everything else has natural alignment. +/// `PT.TLS` ELF program header. Everything else has natural alignment. /// /// The location of the DTV does not actually matter. For simplicity, we put it in the TLS area, but /// there is no actual ABI requirement that it reside there. @@ -480,17 +480,17 @@ pub fn getThreadPointer() usize { }; } -fn computeAreaDesc(phdrs: []elf.Phdr) void { +fn computeAreaDesc(phdrs: []elf.ElfN.Phdr) void { @setRuntimeSafety(false); @disableInstrumentation(); - var tls_phdr: ?*elf.Phdr = null; + var tls_phdr: ?*elf.ElfN.Phdr = null; var img_base: usize = 0; for (phdrs) |*phdr| { - switch (phdr.p_type) { - elf.PT_PHDR => img_base = @intFromPtr(phdrs.ptr) - phdr.p_vaddr, - elf.PT_TLS => tls_phdr = phdr, + switch (phdr.type) { + .PHDR => img_base = @intFromPtr(phdrs.ptr) - phdr.vaddr, + .TLS => tls_phdr = phdr, else => {}, } } @@ -500,12 +500,12 @@ fn computeAreaDesc(phdrs: []elf.Phdr) void { var block_size: usize = undefined; if (tls_phdr) |phdr| { - align_factor = phdr.p_align; + align_factor = phdr.@"align"; - // The effective size in memory is represented by `p_memsz`; the length of the data stored - // in the `PT_TLS` segment is `p_filesz` and may be less than the former. - block_init = @as([*]u8, @ptrFromInt(img_base + phdr.p_vaddr))[0..phdr.p_filesz]; - block_size = phdr.p_memsz; + // The effective size in memory is represented by `memsz`; the length of the data stored + // in the `PT.TLS` segment is `filesz` and may be less than the former. + block_init = @as([*]u8, @ptrFromInt(img_base + phdr.vaddr))[0..phdr.filesz]; + block_size = phdr.memsz; } else { align_factor = @alignOf(usize); @@ -651,7 +651,7 @@ var main_thread_area_buffer: [0x1000]u8 align(page_size_min) = undefined; /// Computes the layout of the static TLS area, allocates the area, initializes all of its fields, /// and assigns the architecture-specific value to the TP register. -pub fn initStatic(phdrs: []elf.Phdr) void { +pub fn initStatic(phdrs: []elf.ElfN.Phdr) void { @setRuntimeSafety(false); @disableInstrumentation(); @@ -726,12 +726,14 @@ comptime { // function for the GD and LD models. This function is unlikely to actually be used, since // the linker should be able to relax every TLS access to the LE model and therefore // eliminate all calls to this function, but that isn't guaranteed. - _ = struct { + const Fns = struct { const TlsIndex = switch (native_arch) { .x86_64 => extern struct { module: u64, offset: u64 }, // Even for x32... else => extern struct { module: usize, offset: usize }, // ...but not MIPS N32! }; - export fn __tls_get_addr(ti: *const TlsIndex) *anyopaque { + fn __tls_get_addr(ti: *const TlsIndex) callconv(.c) *anyopaque { + comptime assert(native_arch != .s390x); + assert(ti.module == 1); // The executable's module ID is always 1 const tp = getThreadPointer(); const block: [*]u8 = switch (current_variant) { @@ -743,6 +745,25 @@ comptime { }; return block[@intCast(ti.offset)..]; } + fn __tls_get_offset() callconv(.naked) noreturn { + comptime assert(native_arch == .s390x); + + // We receive the module's GOT pointer in r12 and the GOT offset in r2. + asm volatile ( + \\ la %%r1, 0(%%r12, %%r2) + \\ lg %%r2, 8(%%r1) + \\ lgrl %%r0, %[block_size] + \\ sgr %%r2, %%r0 + \\ br %%r14 + : + : [block_size] "s" (&area_desc.block.size), + ); + } }; + + if (native_arch == .s390x) + @export(&Fns.__tls_get_offset, .{ .name = "__tls_get_offset" }) + else + @export(&Fns.__tls_get_addr, .{ .name = "__tls_get_addr" }); } } diff --git a/lib/std/os/linux/vdso.zig b/lib/std/os/linux/vdso.zig index 1106ee8bf173dd6eaff0fe372e490249d91dd89f..53be1bf9d51f0048d57074313fa49aff65e0e6a2 100644 --- a/lib/std/os/linux/vdso.zig +++ b/lib/std/os/linux/vdso.zig @@ -19,14 +19,14 @@ pub fn lookup(vername: []const u8, name: []const u8) usize { i += 1; ph_addr += eh.e_phentsize; }) { - const this_ph = @as(*elf.Phdr, @ptrFromInt(ph_addr)); - switch (this_ph.p_type) { + const this_ph = @as(*elf.ElfN.Phdr, @ptrFromInt(ph_addr)); + switch (this_ph.type) { // On WSL1 as well as older kernels, the VDSO ELF image is pre-linked in the upper half - // of the memory space (e.g. p_vaddr = 0xffffffffff700000 on WSL1). + // of the memory space (e.g. vaddr = 0xffffffffff700000 on WSL1). // Wrapping operations are used on this line as well as subsequent calculations relative to base // (lines 47, 78) to ensure no overflow check is tripped. - elf.PT_LOAD => base = vdso_addr +% this_ph.p_offset -% this_ph.p_vaddr, - elf.PT_DYNAMIC => maybe_dynv = @as([*]usize, @ptrFromInt(vdso_addr + this_ph.p_offset)), + .LOAD => base = vdso_addr +% this_ph.offset -% this_ph.vaddr, + .DYNAMIC => maybe_dynv = @as([*]usize, @ptrFromInt(vdso_addr + this_ph.offset)), else => {}, } } diff --git a/lib/std/pie.zig b/lib/std/pie.zig index 0252cde9e8f0161ae5a3767723c3853f94ec82f0..bcec6acd590f391c56202ff897b364ee0d456554 100644 --- a/lib/std/pie.zig +++ b/lib/std/pie.zig @@ -293,7 +293,7 @@ inline fn getDynamicSymbol() [*]const elf.Dyn { }; } -pub fn relocate(phdrs: []const elf.Phdr) void { +pub fn relocate(phdrs: []const elf.ElfN.Phdr) void { @setRuntimeSafety(false); @disableInstrumentation(); @@ -303,8 +303,8 @@ pub fn relocate(phdrs: []const elf.Phdr) void { // the theoretical load addresses for the `_DYNAMIC` symbol. const base_addr = base: { for (phdrs) |*phdr| { - if (phdr.p_type != elf.PT_DYNAMIC) continue; - break :base @intFromPtr(dynv) - phdr.p_vaddr; + if (phdr.type != .DYNAMIC) continue; + break :base @intFromPtr(dynv) - phdr.vaddr; } // This is not supposed to happen for well-formed binaries. @trap(); diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig index 8accb90cb7f9c79b3246fb974c838c9c28e7245d..4fb68855b5a5953b709fae4f893bc051a50dbf09 100644 --- a/lib/std/posix/test.zig +++ b/lib/std/posix/test.zig @@ -75,7 +75,7 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void { // Count how many libraries are loaded counter.* += @as(usize, 1); - // The image should contain at least a PT_LOAD segment + // The image should contain at least a PT.LOAD segment if (info.phnum < 1) return error.MissingPtLoadSegment; // Quick & dirty validation of the phdr pointers, make sure we're not diff --git a/lib/std/process.zig b/lib/std/process.zig index e134ef16d9adb9abed54448861c72b12bb12a4c0..3e6f62b2c386a6d721b68cc44b12f26133c912fd 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -100,7 +100,7 @@ pub const UserInfo = struct { }; /// POSIX function which gets a uid from username. -pub fn getUserInfo(name: []const u8) !UserInfo { +pub fn getUserInfo(io: Io, name: []const u8) !UserInfo { return switch (native_os) { .linux, .driverkit, @@ -116,7 +116,7 @@ pub fn getUserInfo(name: []const u8) !UserInfo { .haiku, .illumos, .serenity, - => posixGetUserInfo(name), + => posixGetUserInfo(io, name), else => @compileError("Unsupported OS"), }; } @@ -127,7 +127,7 @@ pub fn posixGetUserInfo(io: Io, name: []const u8) !UserInfo { const file = try Io.Dir.openFileAbsolute(io, "/etc/passwd", .{}); defer file.close(io); var buffer: [4096]u8 = undefined; - var file_reader = file.reader(&buffer); + var file_reader = file.reader(io, &buffer); return posixGetUserInfoPasswdStream(name, &file_reader.interface) catch |err| switch (err) { error.ReadFailed => return file_reader.err.?, error.EndOfStream => return error.UserNotFound, @@ -644,7 +644,7 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 { /// leaks can be accurate. In release builds, this calls `exit` with code zero, /// and does not return. pub fn cleanExit(io: Io) void { - if (builtin.mode == .Debug) return; + if (builtin.mode == .debug) return; _ = io.lockStderr(&.{}, .no_color) catch {}; exit(0); } @@ -809,7 +809,7 @@ pub fn abort() noreturn { // even when linking libc on Windows we use our own abort implementation. // See https://github.com/ziglang/zig/issues/2071 for more details. if (native_os == .windows) { - if (builtin.mode == .Debug and windows.peb().BeingDebugged.toBool()) { + if (builtin.mode == .debug and windows.peb().BeingDebugged.toBool()) { @breakpoint(); } windows.ntdll.RtlExitUserProcess(3); diff --git a/lib/std/process/Args.zig b/lib/std/process/Args.zig index 8e6caf2d651d407a2baaab7b276f0f187381f068..35e5b7cce411f9064a76dfe7f223d531f9f848c2 100644 --- a/lib/std/process/Args.zig +++ b/lib/std/process/Args.zig @@ -752,7 +752,7 @@ pub fn IteratorGeneral(comptime options: IteratorGeneralOptions) type { start: usize = 0, end: usize = 0, - pub const Self = @This(); + const Self = @This(); pub const InitError = error{OutOfMemory}; diff --git a/lib/std/sort/block.zig b/lib/std/sort/block.zig index 4c94fb78adb6fde1582e0e806f84cfdfe88ec7a6..674e785afadf9c29f8869044de85bdc3fdfb7c85 100644 --- a/lib/std/sort/block.zig +++ b/lib/std/sort/block.zig @@ -103,7 +103,7 @@ pub fn block( context: anytype, comptime lessThanFn: fn (@TypeOf(context), lhs: T, rhs: T) bool, ) void { - const lessThan = if (builtin.mode == .Debug) struct { + const lessThan = if (builtin.mode == .debug) struct { fn lessThan(ctx: @TypeOf(context), lhs: T, rhs: T) bool { const lt = lessThanFn(ctx, lhs, rhs); const gt = lessThanFn(ctx, rhs, lhs); diff --git a/lib/std/spirv.zig b/lib/std/spirv.zig index 72ca757610e55922d552ccd8fb812b349d3f5c5f..f0b768ed1a1aeafb81a630257daab8290e772dde 100644 --- a/lib/std/spirv.zig +++ b/lib/std/spirv.zig @@ -97,7 +97,7 @@ pub fn specConst(T: type, comptime default_value: T, comptime spec_id: u32) T { }, .int, .float => return asm ( \\%ret = OpSpecConstant %ty $default_value - \\ OpDecorate %ret SpecId $spec_id" + \\ OpDecorate %ret SpecId $spec_id : [ret] "" (-> T), : [ty] "t" (T), [default_value] "c" (default_value), diff --git a/lib/std/start.zig b/lib/std/start.zig index c95e36e7778e5e6f041d7b51411d1a1e3b353601..6021da10325aa38a6be00d59ecc1d58634deba77 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -589,7 +589,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { else => continue, } } - break :init @as([*]elf.Phdr, @ptrFromInt(at_phdr))[0..at_phnum]; + break :init @as([*]elf.ElfN.Phdr, @ptrFromInt(at_phdr))[0..at_phnum]; }; // Apply the initial relocations as early as possible in the startup process. We cannot @@ -621,7 +621,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { std.os.linux.tls.initStatic(phdrs); } - // The way Linux executables represent stack size is via the PT_GNU_STACK + // The way Linux executables represent stack size is via the PT.GNU_STACK // program header. However the kernel does not recognize it; it always gives 8 MiB. // Here we look for the stack size in our program headers and use setrlimit // to ask for more stack space. @@ -645,19 +645,19 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn { std.process.exit(callMainWithArgs(argc, argv, envp)); } -fn expandStackSize(phdrs: []elf.Phdr) void { +fn expandStackSize(phdrs: []elf.ElfN.Phdr) void { @disableInstrumentation(); for (phdrs) |*phdr| { - switch (phdr.p_type) { - elf.PT_GNU_STACK => { - if (phdr.p_memsz == 0) break; - assert(phdr.p_memsz % std.heap.page_size_min == 0); + switch (phdr.type) { + .GNU_STACK => { + if (phdr.memsz == 0) break; + assert(phdr.memsz % std.heap.page_size_min == 0); // Silently fail if we are unable to get limits. const limits = std.posix.getrlimit(.STACK) catch break; // Clamp to limits.max . - const wanted_stack_size = @min(phdr.p_memsz, limits.max); + const wanted_stack_size = @min(phdr.memsz, limits.max); if (wanted_stack_size > limits.cur) { std.posix.setrlimit(.STACK, .{ @@ -702,7 +702,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal .linux => { const at_phdr = std.c.getauxval(elf.AT_PHDR); const at_phnum = std.c.getauxval(elf.AT_PHNUM); - const phdrs = (@as([*]elf.Phdr, @ptrFromInt(at_phdr)))[0..at_phnum]; + const phdrs = (@as([*]elf.ElfN.Phdr, @ptrFromInt(at_phdr)))[0..at_phnum]; expandStackSize(phdrs); }, .windows => { @@ -742,8 +742,8 @@ fn mainWithoutEnv(c_argc: c_int, c_argv: [*][*:0]c_char) callconv(.c) c_int { const bad_main_ret = "expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'"; const use_safe_allocator = !is_wasm and switch (builtin.mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => !builtin.link_libc and builtin.single_threaded, // Also not ideal. + .debug, .safe => true, + .fast, .small => !builtin.link_libc and builtin.single_threaded, // Also not ideal. }; var safe_allocator: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{}); diff --git a/lib/std/std.zig b/lib/std/std.zig index e7c50a946091a47dccf4cf1301d2982189ff8589..d1d8361967220fe75485de92ef207dfdac3363a0 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -162,7 +162,7 @@ pub const Options = struct { /// This enables `std.http.Client` to log ssl secrets to the file specified by the SSLKEYLOGFILE /// env var. Creating such a log file allows other programs with access to that file to decrypt /// all `std.http.Client` traffic made by this program. - http_enable_ssl_key_log_file: bool = @import("builtin").mode == .Debug, + http_enable_ssl_key_log_file: bool = @import("builtin").mode == .debug, side_channels_mitigations: crypto.SideChannelsMitigations = crypto.default_side_channels_mitigations, @@ -192,7 +192,7 @@ pub const Options = struct { /// If this happens the fix is to add the error code to the corresponding /// switch expression, possibly introduce a new error in the error set, and /// send a patch to Zig. - unexpected_error_tracing: bool = @import("builtin").mode == .Debug and switch (@import("builtin").zig_backend) { + unexpected_error_tracing: bool = @import("builtin").mode == .debug and switch (@import("builtin").zig_backend) { .stage2_llvm, .stage2_x86_64 => true, else => false, }, diff --git a/lib/std/tar/Writer.zig b/lib/std/tar/Writer.zig index 85941c967fcd831bc725480d715ce9d946f363a1..d43c8962d8205c35648855dbc1e6cc4bbd893edb 100644 --- a/lib/std/tar/Writer.zig +++ b/lib/std/tar/Writer.zig @@ -312,7 +312,7 @@ pub const Header = extern struct { // add as much to prefix as you can, must split at / const prefix_remaining = max_prefix - prefix_pos; - if (std.mem.lastIndexOf(u8, sub_path[0..@min(prefix_remaining, sub_path.len)], &.{'/'})) |sep_pos| { + if (std.mem.findLast(u8, sub_path[0..@min(prefix_remaining, sub_path.len)], &.{'/'})) |sep_pos| { @memcpy(w.prefix[prefix_pos..][0..sep_pos], sub_path[0..sep_pos]); if ((sub_path.len - sep_pos - 1) > max_name) return error.NameTooLong; @memcpy(w.name[0..][0 .. sub_path.len - sep_pos - 1], sub_path[sep_pos + 1 ..]); diff --git a/lib/std/tar/test.zig b/lib/std/tar/test.zig index e01fd4b884dd4b0cff328238b60288bc2a535d87..fa66d51cedb7730012d1b432c90f8d98928610c0 100644 --- a/lib/std/tar/test.zig +++ b/lib/std/tar/test.zig @@ -474,14 +474,14 @@ test "should not overwrite existing file" { defer root.cleanup(); try testing.expectError( error.PathAlreadyExists, - tar.pipeToFileSystem(io, root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }), + tar.extract(io, root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }), ); // Unpack with strip_components = 0 should pass r = .fixed(data); var root2 = std.testing.tmpDir(.{}); defer root2.cleanup(); - try tar.pipeToFileSystem(io, root2.dir, &r, .{ .mode_mode = .ignore, .strip_components = 0 }); + try tar.extract(io, root2.dir, &r, .{ .mode_mode = .ignore, .strip_components = 0 }); } test "case sensitivity" { @@ -501,7 +501,7 @@ test "case sensitivity" { var root = std.testing.tmpDir(.{}); defer root.cleanup(); - tar.pipeToFileSystem(io, root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| { + tar.extract(io, root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| { // on case insensitive fs we fail on overwrite existing file try testing.expectEqual(error.PathAlreadyExists, err); return; diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 46c7fe938b22300c23dcedc3570cb329090d3d3a..eebf3a5195c0d2407c7c51d3b67ef794011f6736 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -999,7 +999,7 @@ test "expectEqualDeep composite type" { } fn printIndicatorLine(source: []const u8, indicator_index: usize) void { - const line_begin_index = if (std.mem.lastIndexOfScalar(u8, source[0..indicator_index], '\n')) |line_begin| + const line_begin_index = if (std.mem.findScalarLast(u8, source[0..indicator_index], '\n')) |line_begin| line_begin + 1 else 0; diff --git a/lib/std/testing/Smith.zig b/lib/std/testing/Smith.zig index 7e3235fe0e5ffd1163a2cc7bf46f7583eb0a06ae..39da2910c5657b62ac6bac5103bca1e286a63cf7 100644 --- a/lib/std/testing/Smith.zig +++ b/lib/std/testing/Smith.zig @@ -52,7 +52,7 @@ pub inline fn baselineWeights(T: type) []const Weight { .bool, .int, .float => i: { // Reject types that don't have a fixed bitsize (esp. usize) // since they are not gauraunteed to fit in a u64 across targets. - if (std.mem.indexOfScalar(type, &.{ + if (std.mem.findScalar(type, &.{ isize, usize, c_char, c_longdouble, c_short, c_ushort, @@ -708,7 +708,7 @@ fn constructInput(comptime values: []const union(enum) { } test value { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const S = struct { v: void = {}, diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig index 259e46d685bcfc00fc118e8b4cd95f47bdb3869f..a6cd094800cc0a77fcd84394bc08736df7352b0f 100644 --- a/lib/std/unicode.zig +++ b/lib/std/unicode.zig @@ -425,6 +425,15 @@ pub const Utf8Iterator = struct { return it.bytes[original_i..end_ix]; } + + /// Look ahead at the next codepoint without advancing the iterator. + /// If no codepoints exist, then returns null. + pub fn peekCodepoint(it: *Utf8Iterator) ?u21 { + const original_i = it.i; + defer it.i = original_i; + + return it.nextCodepoint(); + } }; pub fn utf16IsHighSurrogate(c: u16) bool { @@ -768,6 +777,9 @@ fn testMiscInvalidUtf8() !void { test "utf8 iterator peeking" { try comptime testUtf8Peeking(); try testUtf8Peeking(); + + comptime try testUtf8PeekCodepoint(); + try testUtf8PeekCodepoint(); } fn testUtf8Peeking() !void { @@ -790,6 +802,20 @@ fn testUtf8Peeking() !void { try testing.expect(mem.eql(u8, &[_]u8{}, it.peek(1))); } +fn testUtf8PeekCodepoint() !void { + const s = Utf8View.initComptime("東京市"); + var it = s.iterator(); + + try testing.expect(it.peekCodepoint().? == 0x6771); + try testing.expect(it.peekCodepoint().? == 0x6771); + _ = it.nextCodepoint(); + try testing.expect(it.peekCodepoint().? == 0x4eac); + _ = it.nextCodepoint(); + try testing.expect(it.peekCodepoint().? == 0x5e02); + _ = it.nextCodepoint(); + try testing.expect(it.peekCodepoint() == null); +} + fn testError(bytes: []const u8, expected_err: anyerror) !void { try testing.expectError(expected_err, testDecode(bytes)); } @@ -1758,6 +1784,15 @@ pub const Wtf8Iterator = struct { return it.bytes[original_i..end_ix]; } + + /// Look ahead at the next codepoint without advancing the iterator. + /// If no codepoints exist, then returns null. + pub fn peekCodepoint(it: *Wtf8Iterator) ?u21 { + const original_i = it.i; + defer it.i = original_i; + + return it.nextCodepoint(); + } }; pub fn wtf16LeToWtf8ArrayList(result: *std.array_list.Managed(u8), utf16le: []const u16) Allocator.Error!void { diff --git a/lib/std/zig.zig b/lib/std/zig.zig index fafb3cac422ac17b36dee498ddecf014366fbc91..ec6fc7d630a92133751c8ae481ff193d3fc0dfff 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -386,23 +386,6 @@ pub const Subsystem = enum { efi_boot_service_driver, efi_rom, efi_runtime_driver, - - /// Deprecated; use '.console' instead. To be removed after 0.16.0 is tagged. - pub const Console: Subsystem = .console; - /// Deprecated; use '.windows' instead. To be removed after 0.16.0 is tagged. - pub const Windows: Subsystem = .windows; - /// Deprecated; use '.posix' instead. To be removed after 0.16.0 is tagged. - pub const Posix: Subsystem = .posix; - /// Deprecated; use '.native' instead. To be removed after 0.16.0 is tagged. - pub const Native: Subsystem = .native; - /// Deprecated; use '.efi_application' instead. To be removed after 0.16.0 is tagged. - pub const EfiApplication: Subsystem = .efi_application; - /// Deprecated; use '.efi_boot_service_driver' instead. To be removed after 0.16.0 is tagged. - pub const EfiBootServiceDriver: Subsystem = .efi_boot_service_driver; - /// Deprecated; use '.efi_rom' instead. To be removed after 0.16.0 is tagged. - pub const EfiRom: Subsystem = .efi_rom; - /// Deprecated; use '.efi_runtime_driver' instead. To be removed after 0.16.0 is tagged. - pub const EfiRuntimeDriver: Subsystem = .efi_runtime_driver; }; pub const CompressDebugSections = enum(u2) { none, zlib, zstd }; @@ -562,8 +545,7 @@ pub fn stringEscape(bytes: []const u8, w: *Writer) Writer.Error!void { '\t' => try w.writeAll("\\t"), '\\' => try w.writeAll("\\\\"), '"' => try w.writeAll("\\\""), - '\'' => try w.writeByte('\''), - ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte), + ' ', '!', '#'...'[', ']'...'~' => try w.writeByte(byte), else => { try w.writeAll("\\x"); try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }); @@ -780,11 +762,11 @@ pub const EnvVar = enum { ZIG_LIBC, ZIG_BUILD_ERROR_STYLE, ZIG_BUILD_MULTILINE_ERRORS, + ZIG_BUILD_SUMMARY, ZIG_VERBOSE_LINK, ZIG_VERBOSE_CC, ZIG_VERBOSE_CMD, ZIG_DEBUG_CMD, - ZIG_DEBUG_MAKER, ZIG_IS_DETECTING_LIBC_PATHS, ZIG_IS_AVOIDING_CALLING_ITSELF, @@ -1577,7 +1559,7 @@ pub fn resolvePath( // Heuristic for a fast path: if no component is absolute and ".." never appears, we just need to resolve `paths`. for (paths) |p| { if (Dir.path.isAbsolute(p)) break; // absolute path - if (mem.indexOf(u8, p, "..") != null) break; // may contain up-dir + if (mem.find(u8, p, "..") != null) break; // may contain up-dir } else { // no absolute path, no "..". const res = try Dir.path.resolve(gpa, paths); @@ -1675,31 +1657,32 @@ pub fn buildExeSubprocess( }; defer child.kill(io); - var stderr_task = io.concurrent(readStreamAlloc, .{ gpa, io, child.stderr.?, .unlimited }) catch - @panic("TODO use multireader instead"); - defer if (stderr_task.cancel(io)) |slice| gpa.free(slice) else |_| {}; + var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined; + var multi_reader: Io.File.MultiReader = undefined; + multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? }); + defer multi_reader.deinit(); + const stdout = multi_reader.reader(0); + const stderr = multi_reader.reader(1); - var stdout_buffer: [512]u8 = undefined; - var stdout_reader: Io.File.Reader = .initStreaming(child.stdout.?, io, &stdout_buffer); - const stdout = &stdout_reader.interface; + var stdin_buffer: [8]u8 = undefined; + var stdin_writer = child.stdin.?.writerStreaming(io, &stdin_buffer); - { - var w = child.stdin.?.writer(io, &.{}); - w.interface.writeStruct(Client.Message.Header{ .tag = .update, .bytes_len = 0 }, .little) catch |err| switch (err) { - error.WriteFailed => { - log.err("{t} writing to command: {f}", .{ w.err.?, cmd }); - return error.AlreadyReported; - }, - }; - w.interface.writeStruct(Client.Message.Header{ .tag = .exit, .bytes_len = 0 }, .little) catch |err| switch (err) { - error.WriteFailed => { - log.err("{t} writing to command: {f}", .{ w.err.?, cmd }); - return error.AlreadyReported; - }, - }; - } + var client: Client = .{ + .in = stdout, + .out = &stdin_writer.interface, + }; - const Header = Server.Message.Header; + (blk: { + client.serveMessageHeader(.{ .tag = .update, .bytes_len = 0 }) catch |err| break :blk err; + client.serveMessageHeader(.{ .tag = .exit, .bytes_len = 0 }) catch |err| break :blk err; + client.out.flush() catch |err| break :blk err; + }) catch |err| switch (err) { + error.WriteFailed => { + if (stdin_writer.err.? == error.Canceled) return error.Canceled; + log.err("{t} writing to command: {f}", .{ stdin_writer.err.?, cmd }); + return error.AlreadyReported; + }, + }; var result: ?Cache.Path = null; defer if (result) |r| gpa.free(r.sub_path); @@ -1707,33 +1690,29 @@ pub fn buildExeSubprocess( var result_error_bundle: ErrorBundle = .empty; defer result_error_bundle.deinit(gpa); - var body_buffer: std.ArrayList(u8) = .empty; - defer body_buffer.deinit(gpa); - var received_fs_inputs = false; var cache_hit = false; + var eos_err: error{EndOfStream}!void = {}; + while (true) { - const header = stdout.takeStruct(Header, .little) catch |err| switch (err) { - error.ReadFailed => { - log.err("{t} reading from command: {f}", .{ stdout_reader.err.?, cmd }); - return error.AlreadyReported; - }, - error.EndOfStream => break, - }; - body_buffer.clearRetainingCapacity(); - stdout.appendExact(gpa, &body_buffer, header.bytes_len) catch |err| switch (err) { - error.ReadFailed => { - log.err("{t} reading from command: {f}", .{ stdout_reader.err.?, cmd }); - return error.AlreadyReported; + const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { + error.Timeout => unreachable, + error.EndOfStream => |e| { + if (client.in.bufferedLen() == 0) break; + // Better to report the crash with stderr below, but we set + // this in case the child exits successfully while violating + // this protocol. + eos_err = e; + break; }, - error.OutOfMemory => |e| return e, - error.EndOfStream => { - log.err("unexpected end of stream from command: {f}", .{cmd}); + error.Canceled, error.OutOfMemory => |e| return e, + else => |e| { + log.err("{t} reading from command: {f}", .{ e, cmd }); return error.AlreadyReported; }, }; - const body = body_buffer.items; + const body = stdout.take(header.bytes_len) catch unreachable; switch (header.tag) { .zig_version => { @@ -1784,16 +1763,15 @@ pub fn buildExeSubprocess( } } - const stderr_contents = stderr_task.await(io) catch |err| switch (err) { - error.Canceled, error.OutOfMemory => |e| return e, - else => |e| c: { - log.warn("{t} reading stderr from command: {f}", .{ e, cmd }); - break :c ""; - }, - }; + const stderr_contents = stderr.buffered(); if (stderr_contents.len > 0) log.warn("unexpected stderr from {s} command:\n{s}", .{ options.argv[0], stderr_contents }); + eos_err catch { + log.err("unexpected end of stream from command: {f}", .{cmd}); + return error.AlreadyReported; + }; + // Send EOF to stdin. child.stdin.?.close(io); child.stdin = null; @@ -1851,14 +1829,6 @@ pub fn buildExeSubprocess( }; } -fn readStreamAlloc(gpa: Allocator, io: Io, file: Io.File, limit: Io.Limit) ![]u8 { - var file_reader: Io.File.Reader = .initStreaming(file, io, &.{}); - return file_reader.interface.allocRemaining(gpa, limit) catch |err| switch (err) { - error.ReadFailed => return file_reader.err.?, - else => |e| return e, - }; -} - test { _ = Ast; _ = AstRlAnnotate; diff --git a/lib/std/zig/Ast/Render.zig b/lib/std/zig/Ast/Render.zig index 53d9027d1351ebcd4a5658f6d3702bfe22cc95ca..605f3752a78e8908539d294300f3f0a1047b2315 100644 --- a/lib/std/zig/Ast/Render.zig +++ b/lib/std/zig/Ast/Render.zig @@ -941,20 +941,20 @@ fn renderExpressionFixup(r: *Render, node: Ast.Node.Index, space: Space) Error!v } fn drainNoNewline(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize { - if (std.mem.indexOfScalar(u8, w.buffered(), '\n') != null) { + if (std.mem.findScalar(u8, w.buffered(), '\n') != null) { return error.WriteFailed; } var n: usize = 0; for (data[0 .. data.len - 1]) |v| { - if (std.mem.indexOfScalar(u8, v, '\n') != null) { + if (std.mem.findScalar(u8, v, '\n') != null) { return error.WriteFailed; } n += v.len; } const pattern = data[data.len - 1]; - if (splat != 0 and std.mem.indexOfScalar(u8, pattern, '\n') != null) { + if (splat != 0 and std.mem.findScalar(u8, pattern, '\n') != null) { return error.WriteFailed; } n += pattern.len * splat; @@ -990,7 +990,7 @@ fn rendersMultiline(r: *const Render, node: Ast.Node.Index) error{OutOfMemory}!b error.WriteFailed => return true, }; if (sub_ais.disabled_offset != null) return true; - if (std.mem.indexOfScalar(u8, no_nl_w.buffered(), '\n') != null) { + if (std.mem.findScalar(u8, no_nl_w.buffered(), '\n') != null) { return true; } @@ -2993,7 +2993,7 @@ fn hasMultilineString(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.Tok /// Returns true if there exists a doc comment between the start /// of token `start_token` and the start of token `end_token`. fn hasDocComment(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.TokenIndex) bool { - return std.mem.indexOfScalar( + return std.mem.findScalar( Token.Tag, tree.tokens.items(.tag)[start_token..end_token], .doc_comment, @@ -3459,7 +3459,7 @@ const AutoIndentingStream = struct { /// Sets current indentation level to be the same as that of the last pushSpace. pub fn enableSpaceMode(ais: *AutoIndentingStream, space: Space) void { if (ais.space_stack.items.len == 0) return; - const curr = ais.space_stack.getLast().?; + const curr = ais.space_stack.last().?; if (curr.space != space) return; ais.space_mode = curr.indent_count; } @@ -3470,7 +3470,7 @@ const AutoIndentingStream = struct { pub fn lastSpaceModeIndent(ais: *AutoIndentingStream) usize { if (ais.space_stack.items.len == 0) return 0; - return ais.space_stack.getLast().?.indent_count * ais.indent_delta; + return ais.space_stack.last().?.indent_count * ais.indent_delta; } /// Push default indentation diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index c865bd92fe1d3d69cf188cf295ba637ef70a0b9f..c0860b71f61109a5b8dce360c1dea585d31d2b37 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -74,13 +74,13 @@ src_hasher: std.zig.SrcHasher, const InnerError = error{ OutOfMemory, AnalysisFail }; fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 { - const field_count = std.meta.fieldNames(@TypeOf(extra)).len; + const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len; try astgen.extra.ensureUnusedCapacity(astgen.gpa, field_count); return addExtraAssumeCapacity(astgen, extra); } fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { - const field_count = std.meta.fieldNames(@TypeOf(extra)).len; + const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len; const extra_index: u32 = @intCast(astgen.extra.items.len); astgen.extra.items.len += field_count; setExtra(astgen, extra_index, extra); @@ -7453,6 +7453,7 @@ fn switchExpr( const ident_name = try astgen.identAsString(ident_token); const ident_name_str = tree.tokenSlice(ident_token); if (mem.eql(u8, "_", ident_name_str)) { + if (non_err_is_ref != .no) return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); break :scope &scratch_scope.base; } non_err_capture = if (non_err_is_ref != .no) .by_ref else .by_val; diff --git a/lib/std/zig/Client.zig b/lib/std/zig/Client.zig index fe50f2314a0b68b5bd9d6510efec6d4146477237..cedda191b99042affaba76eec838fd9f332abdbb 100644 --- a/lib/std/zig/Client.zig +++ b/lib/std/zig/Client.zig @@ -1,3 +1,18 @@ +const Client = @This(); + +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const Configuration = std.Build.Configuration; +const OutMessage = std.zig.Client.Message; +const InMessage = std.zig.Server.Message; +const Reader = Io.Reader; +const Writer = Io.Writer; + +in: *Reader, +out: *Writer, + pub const Message = struct { pub const Header = extern struct { tag: Tag, @@ -46,11 +61,120 @@ pub const Message = struct { /// The message body has the same format as in Server. new_fuzz_input, + /// Asks the server to run a list of steps. + /// Body is a `BuildSteps`. + /// This message only applies to the build system protocol. + bsp_build_steps = 0x80000000, + _, }; + /// Trailing: + /// * step_indices: [step_count]std.Build.Configuration.Step.Index, + pub const BuildSteps = extern struct { + step_count: u32, + flags: Flags, + + pub const Flags = packed struct(u32) { + /// Can only be enabled when the server declared support for file + /// watching. + watch: bool, + reserved: u31 = 0, + }; + }; + comptime { - const std = @import("std"); - std.debug.assert(@sizeOf(std.Build.abi.fuzz.LimitKind) == 1); + assert(@sizeOf(std.Build.abi.fuzz.LimitKind) == 1); } }; + +pub fn receiveMessage(c: *const Client) Reader.Error!InMessage.Header { + return c.in.takeStruct(InMessage.Header, .little); +} + +/// Assumes that `c.in` is a reader in `multi_reader`. +/// Guarantees that the response body will be buffered in `c.in` on success. +pub fn receiveMessageWithMultiReader( + c: *Client, + multi_reader: *Io.File.MultiReader, + timeout: Io.Timeout, +) (Io.File.MultiReader.Error || Io.Timeout.Error)!InMessage.Header { + while (c.in.bufferedLen() < @sizeOf(InMessage.Header)) { + multi_reader.fill(64, timeout) catch |err| switch (err) { + error.Canceled, + error.Timeout, + error.ConcurrencyUnavailable, + error.EndOfStream, + => |e| return e, + }; + } + const header = c.in.takeStruct(InMessage.Header, .little) catch unreachable; + while (c.in.bufferedLen() < header.bytes_len) { + try multi_reader.fill(header.bytes_len - c.in.bufferedLen(), timeout); + } + try multi_reader.checkAnyError(); + return header; +} + +/// Don't forget to flush! +pub fn serveMessageHeader(c: *const Client, header: OutMessage.Header) Writer.Error!void { + try c.out.writeStruct(header, .little); +} + +pub fn serveBodylessMessage(c: *const Client, tag: OutMessage.Tag) Writer.Error!void { + try c.serveMessageHeader(.{ .tag = tag, .bytes_len = 0 }); + try c.out.flush(); +} + +pub fn serveRunTest(c: *const Client, index: u32) !void { + try c.serveMessageHeader(.{ + .tag = .run_test, + .bytes_len = @sizeOf(u32), + }); + try c.out.writeInt(u32, index, .little); + try c.out.flush(); +} + +pub fn serveRunFuzzTestMessage( + c: *const Client, + test_names: []const []const u8, + kind: std.Build.abi.fuzz.LimitKind, + amount_or_instance: u64, +) !void { + try c.serveMessageHeader(.{ + .tag = .start_fuzzing, + .bytes_len = 1 + 8 + 4 + count: { + var bytes_len: u32 = @intCast(test_names.len * 4); + for (test_names) |name| { + bytes_len += @intCast(name.len); + } + break :count bytes_len; + }, + }); + try c.out.writeByte(@backingInt(kind)); + try c.out.writeInt(u64, amount_or_instance, .little); + try c.out.writeInt(u32, @intCast(test_names.len), .little); + for (test_names) |test_name| { + try c.out.writeInt(u32, @intCast(test_name.len), .little); + try c.out.writeAll(test_name); + } + try c.out.flush(); +} + +pub fn serveBuildSteps( + c: *const Client, + steps: []const Configuration.Step.Index, + flags: OutMessage.BuildSteps.Flags, +) !void { + try c.serveMessageHeader(.{ + .tag = .bsp_build_steps, + .bytes_len = @intCast(@sizeOf(OutMessage.BuildSteps) + steps.len * @sizeOf(Configuration.Step.Index)), + }); + const body: OutMessage.BuildSteps = .{ + .step_count = @intCast(steps.len), + .flags = flags, + }; + try c.out.writeStruct(body, .little); + try c.out.writeSliceEndian(Configuration.Step.Index, steps, .little); + try c.out.flush(); +} diff --git a/lib/std/zig/LibCInstallation.zig b/lib/std/zig/LibCInstallation.zig index 6fa49a0ce985c9115495a16c862e7d6e1a9062d5..f9e0404606ee0fe503feb2b1ce096f2a8df0ddca 100644 --- a/lib/std/zig/LibCInstallation.zig +++ b/lib/std/zig/LibCInstallation.zig @@ -43,7 +43,7 @@ pub const FindError = error{ pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const std.Target) !LibCInstallation { var self: LibCInstallation = .{}; - const field_names = comptime std.meta.fieldNames(LibCInstallation); + const field_names = @typeInfo(LibCInstallation).@"struct".field_names; const FoundKey = struct { found: bool, allocated: ?[]u8, diff --git a/lib/std/zig/Server.zig b/lib/std/zig/Server.zig index cf43cb0af2822cf416868dd1eba76bcb06b791a7..1f6d208084abdcc9d93ef33929e36aa0239549af 100644 --- a/lib/std/zig/Server.zig +++ b/lib/std/zig/Server.zig @@ -1,12 +1,8 @@ const Server = @This(); -const builtin = @import("builtin"); - const std = @import("std"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; -const native_endian = builtin.target.cpu.arch.endian(); -const need_bswap = native_endian != .little; const Cache = std.Build.Cache; const OutMessage = std.zig.Server.Message; const InMessage = std.zig.Client.Message; @@ -16,6 +12,14 @@ const Writer = std.Io.Writer; in: *Reader, out: *Writer, +/// The ABI version of the build system protocol. Will be bumped whenever a +/// backwards incompatible changes to the protocol is made. +/// +/// Does not apply to the internal compiler protocol or test runner. +/// +/// See `version` in `Message.Handshake`. +pub const build_system_version: u32 = 1; + pub const Message = struct { pub const Header = extern struct { tag: Tag, @@ -70,9 +74,62 @@ pub const Message = struct { /// Body is a TimeReport. time_report, + /// The first message sent by the server over the build system protocol. + /// Body is a `Handshake`. + /// This message only applies to the build system protocol. + bsp_handshake = 0x80000000, + /// Notifies that a new configuration file is available. + /// Body is a cwd relative path to the configuration file. + /// This message only applies to the build system protocol. + bsp_configuration, + /// Does not have a body. + /// This message only applies to the build system protocol. + bsp_build_started, + /// Does not have a body. + /// This message only applies to the build system protocol. + bsp_build_completed, + /// Body is a `Configuration.Step.Index`. + /// This message only applies to the build system protocol. + bsp_step_started, + /// Body is a `BuildStepCompleted`. + /// This message only applies to the build system protocol. + bsp_step_completed, + _, }; + /// Trailing: + /// * base_paths: BasePaths, + pub const Handshake = extern struct { + /// See `build_system_version`. + version: u32, + flags: Flags, + + pub const Flags = packed struct(u32) { + file_system_watch_supported: bool, + _: u31 = 0, + }; + }; + + /// Trailing: + /// * error_bundle: ErrorBundle, + pub const BuildStepCompleted = extern struct { + step_index: std.Build.Configuration.Step.Index, + status: Status, + error_bundle: ErrorBundle, + // TODO result_error_msgs + // TODO result_stderr + // TODO result_peak_rss + // TODO result_duration_ns + + pub const Status = enum(u32) { + success, + failure, + skipped, + skipped_oom, + }; + }; + pub const PathPrefix = enum(u8) { cwd, zig_lib, @@ -140,21 +197,6 @@ pub const Message = struct { }; }; -pub const Options = struct { - in: *Reader, - out: *Writer, - zig_version: []const u8, -}; - -pub fn init(options: Options) !Server { - var s: Server = .{ - .in = options.in, - .out = options.out, - }; - try s.serveStringMessage(.zig_version, options.zig_version); - return s; -} - pub fn receiveMessage(s: *Server) !InMessage.Header { return s.in.takeStruct(InMessage.Header, .little); } @@ -183,6 +225,11 @@ pub fn serveMessageHeader(s: *const Server, header: OutMessage.Header) !void { try s.out.writeStruct(header, .little); } +pub fn serveBodylessMessage(s: *const Server, tag: OutMessage.Tag) Writer.Error!void { + try s.serveMessageHeader(.{ .tag = tag, .bytes_len = 0 }); + try s.out.flush(); +} + pub fn serveU32Message(s: *const Server, tag: OutMessage.Tag, int: u32) !void { try serveMessageHeader(s, .{ .tag = tag, diff --git a/lib/std/zig/WindowsSdk.zig b/lib/std/zig/WindowsSdk.zig index cddeecbe633eb049abbf014caf49ee38fcfe0ce6..6b8afafd0892561e449f5bd6e40ca46d06d16cce 100644 --- a/lib/std/zig/WindowsSdk.zig +++ b/lib/std/zig/WindowsSdk.zig @@ -891,7 +891,7 @@ const MsvcLibDir = struct { lib_dir_buf.appendSliceAssumeCapacity(installation_path); - if (!Dir.path.isSep(lib_dir_buf.getLast().?)) { + if (!Dir.path.isSep(lib_dir_buf.last().?)) { try lib_dir_buf.append('\\'); } const installation_path_with_trailing_sep_len = lib_dir_buf.items.len; @@ -1064,7 +1064,7 @@ const MsvcLibDir = struct { errdefer msvc_dir.deinit(); // String might contain trailing slash, so trim it here - if (msvc_dir.items.len > "C:\\".len and msvc_dir.getLast().? == '\\') _ = msvc_dir.pop(); + if (msvc_dir.items.len > "C:\\".len and msvc_dir.last().? == '\\') _ = msvc_dir.pop(); // Remove `\include` at the end of path if (std.mem.endsWith(u8, msvc_dir.items, "\\include")) { @@ -1108,7 +1108,7 @@ const MsvcLibDir = struct { try list.appendSlice(VS140COMNTOOLS); // C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools // String might contain trailing slash, so trim it here - if (list.items.len > "C:\\".len and list.getLast().? == '\\') _ = list.pop(); + if (list.items.len > "C:\\".len and list.last().? == '\\') _ = list.pop(); list.shrinkRetainingCapacity(list.items.len - "\\Common7\\Tools".len); // C:\Program Files (x86)\Microsoft Visual Studio 14.0 break :base_path list; } @@ -1131,7 +1131,7 @@ const MsvcLibDir = struct { errdefer path.deinit(); // String might contain trailing slash, so trim it here - if (path.items.len > "C:\\".len and path.getLast().? == '\\') _ = path.pop(); + if (path.items.len > "C:\\".len and path.last().? == '\\') _ = path.pop(); break :base_path path; } return error.PathNotFound; diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index bce7bd281ef314870fe68528cde51d4813a41a17..d79251c7db366d256a43487c0722c6810050ab31 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -584,7 +584,7 @@ pub const Inst = struct { /// containing the instruction. /// Uses the `un_tok` union field. ref, - /// Implements the dereference operand (`.*`). Checks that operand is a pointer + /// Implements the dereference operator (`.*`). Checks that operand is a pointer /// that supports being directly dereferenced. /// Uses the `un_node` union field. deref, @@ -2522,7 +2522,7 @@ pub const Inst = struct { // bigger than expected. Note that in Debug builds, Zig is allowed // to insert a secret field for safety checks. comptime { - if (builtin.mode != .Debug and builtin.mode != .ReleaseSafe) { + if (builtin.mode != .debug and builtin.mode != .safe) { assert(@sizeOf(Data) == 8); } } diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index 38c6a53cdd13c50fe4e6a0a172649647a94bfb3b..93a1e4e438b6f5ca5b312db0417f0311f9e7460b 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -17,7 +17,7 @@ gpa: Allocator, strip: bool, source_filename: String, -data_layout: String, +data_layout: DataLayout, target_triple: String, module_asm: std.ArrayList(u8), @@ -87,6 +87,455 @@ pub const Options = struct { triple: []const u8 = &.{}, }; +pub const DataLayout = struct { + endian: ?std.lang.Endian, + int_specs: PrimitiveSpec.Map, + float_specs: PrimitiveSpec.Map, + vector_specs: PrimitiveSpec.Map, + pointer_specs: PointerSpec.Map, + string_repr: String, + + const PrimitiveSpec = packed struct(u32) { + bit_width: BitWidth, + abi_align: Alignment, + pref_align: Alignment, + + const BitWidth = u20; + + const Map = std.array_hash_map.Custom(PrimitiveSpec, void, Context, false); + + const Context = struct { + pub fn hash(_: Context, spec: PrimitiveSpec) u32 { + return std.hash.int(spec.bit_width); + } + + pub fn eql(_: Context, lhs_spec: PrimitiveSpec, rhs_spec: PrimitiveSpec, _: usize) bool { + return lhs_spec.bit_width == rhs_spec.bit_width; + } + }; + }; + + const PointerSpec = struct { + bit_width: BitWidth, + index_bit_width: BitWidth, + flags: packed struct(u32) { + abi_align: Alignment, + pref_align: Alignment, + has_unstable_repr: bool, + has_external_state: bool, + null_ptr_repr: NullPtrRepr, + unused: u17 = 0, + }, + addr_space_name: String, + + const BitWidth = u32; + + const NullPtrRepr = enum(u1) { all_zeros, all_ones }; + + const Map = std.array_hash_map.Auto(AddrSpace, PointerSpec); + }; + + pub fn stringForTarget(target: *const std.Target) []const u8 { + // These data layouts should match Clang. + return switch (target.cpu.arch) { + .arc => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32", + .xcore => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32-f64:32-a:0:32-n32", + .hexagon => "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048", + .lanai => "E-m:e-p:32:32-i64:64-a:0:32-n32-S64", + .aarch64 => if (target.ofmt == .macho) + if (target.os.tag == .windows or target.os.tag == .uefi) + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + else if (target.abi == .ilp32) + "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + else + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + else if (target.os.tag == .windows or target.os.tag == .uefi) + "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32" + else + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", + .aarch64_be => "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", + .arm => if (target.ofmt == .macho) + "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + else + "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", + .armeb, .thumbeb => if (target.ofmt == .macho) + "E-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + else + "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", + .thumb => if (target.ofmt == .macho) + "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + else if (target.os.tag == .windows or target.os.tag == .uefi) + "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + else + "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", + .avr => "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8", + .bpfeb => "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .bpfel => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .msp430 => "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16", + .mips => "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", + .mipsel => "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", + .mips64 => switch (target.abi) { + .gnuabin32, .muslabin32, .abin32 => "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + else => "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + }, + .mips64el => switch (target.abi) { + .gnuabin32, .muslabin32, .abin32 => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + else => "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + }, + .m68k => "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16", + .powerpc => "E-m:e-p:32:32-Fn32-i64:64-n32", + .powerpcle => "e-m:e-p:32:32-Fn32-i64:64-n32", + .powerpc64 => switch (target.os.tag) { + .linux => "E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512", + .ps3 => "E-m:e-p:32:32-Fi64-i64:64-i128:128-n32:64", + else => "E-m:e-Fn32-i64:64-i128:128-n32:64", + }, + .powerpc64le => if (target.os.tag == .linux) + "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" + else + "e-m:e-Fn32-i64:64-i128:128-n32:64", + .nvptx => "e-p:32:32-p6:32:32-p7:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64", + .nvptx64 => "e-p6:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64", + .amdgcn => "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9", + .riscv32 => if (target.cpu.has(.riscv, .e)) + "e-m:e-p:32:32-i64:64-n32-S32" + else + "e-m:e-p:32:32-i64:64-n32-S128", + .riscv32be => if (target.cpu.has(.riscv, .e)) + "E-m:e-p:32:32-i64:64-n32-S32" + else + "E-m:e-p:32:32-i64:64-n32-S128", + .riscv64 => if (target.cpu.has(.riscv, .e)) + "e-m:e-p:64:64-i64:64-i128:128-n32:64-S64" + else + "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .riscv64be => if (target.cpu.has(.riscv, .e)) + "E-m:e-p:64:64-i64:64-i128:128-n32:64-S64" + else + "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64", + .sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128", + .s390x => "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64", + .x86 => if (target.os.tag == .windows or target.os.tag == .uefi) switch (target.abi) { + .gnu => if (target.ofmt == .coff) + "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" + else + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32", + else => blk: { + const msvc = switch (target.abi) { + .none, .msvc => true, + else => false, + }; + + break :blk if (target.ofmt == .coff) + if (msvc) + "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" + else + "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" + else if (msvc) + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" + else + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32"; + }, + } else if (target.ofmt == .macho) + "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128" + else + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", + .x86_64 => if (target.os.tag.isDarwin() or target.ofmt == .macho) + "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" + else switch (target.abi) { + .gnux32, .muslx32, .x32 => "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + else => if ((target.os.tag == .windows or target.os.tag == .uefi) and target.ofmt == .coff) + "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" + else + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + }, + .spirv32 => switch (target.os.tag) { + .vulkan, .opengl => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", + else => "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", + }, + .spirv64 => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", + .wasm32 => if (target.os.tag == .emscripten) + "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20" + else + "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20", + .wasm64 => if (target.os.tag == .emscripten) + "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20" + else + "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20", + .ve => "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64", + .csky => "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32", + .loongarch32 => "e-m:e-p:32:32-i64:64-n32-S128", + .loongarch64 => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + .xtensa => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32", + + .alpha, + .arceb, + .ez80, + .hppa, + .hppa64, + .kalimba, + .kvx, + .m88k, + .microblaze, + .microblazeel, + .or1k, + .propeller, + .sh, + .sheb, + .x86_16, + .xtensaeb, + => unreachable, + }; + } + + const default_int_specs: []const PrimitiveSpec = &.{ + .{ .bit_width = 8, .abi_align = .fromByteUnits(1), .pref_align = .fromByteUnits(1) }, // i8:8:8 + .{ .bit_width = 16, .abi_align = .fromByteUnits(2), .pref_align = .fromByteUnits(2) }, // i16:16:16 + .{ .bit_width = 32, .abi_align = .fromByteUnits(4), .pref_align = .fromByteUnits(4) }, // i32:32:32 + .{ .bit_width = 64, .abi_align = .fromByteUnits(4), .pref_align = .fromByteUnits(8) }, // i64:32:64 + }; + const default_float_specs: []const PrimitiveSpec = &.{ + .{ .bit_width = 16, .abi_align = .fromByteUnits(2), .pref_align = .fromByteUnits(2) }, // f16:16:16 + .{ .bit_width = 32, .abi_align = .fromByteUnits(4), .pref_align = .fromByteUnits(4) }, // f32:32:32 + .{ .bit_width = 64, .abi_align = .fromByteUnits(8), .pref_align = .fromByteUnits(8) }, // f64:64:64 + .{ .bit_width = 128, .abi_align = .fromByteUnits(16), .pref_align = .fromByteUnits(16) }, // f128:128:128 + }; + const default_vector_specs: []const PrimitiveSpec = &.{ + .{ .bit_width = 64, .abi_align = .fromByteUnits(8), .pref_align = .fromByteUnits(8) }, // v64:64:64 + .{ .bit_width = 128, .abi_align = .fromByteUnits(16), .pref_align = .fromByteUnits(16) }, // v128:128:128 + }; + + pub fn parseString(string_repr: String, builder: *Builder) Allocator.Error!DataLayout { + const gpa = builder.gpa; + + var int_specs: PrimitiveSpec.Map = .empty; + defer int_specs.deinit(gpa); + var float_specs: PrimitiveSpec.Map = .empty; + defer float_specs.deinit(gpa); + var vector_specs: PrimitiveSpec.Map = .empty; + defer vector_specs.deinit(gpa); + var pointer_specs: PointerSpec.Map = .empty; + defer pointer_specs.deinit(gpa); + var non_integral_addr_spaces: std.ArrayList(AddrSpace) = .empty; + defer non_integral_addr_spaces.deinit(gpa); + + try int_specs.ensureTotalCapacity(gpa, default_int_specs.len); + for (default_int_specs) |int_spec| int_specs.putAssumeCapacityNoClobber(int_spec, {}); + try float_specs.ensureTotalCapacity(gpa, default_float_specs.len); + for (default_float_specs) |float_spec| float_specs.putAssumeCapacityNoClobber(float_spec, {}); + try vector_specs.ensureTotalCapacity(gpa, default_vector_specs.len); + for (default_vector_specs) |vector_spec| vector_specs.putAssumeCapacityNoClobber(vector_spec, {}); + try pointer_specs.putNoClobber(gpa, .default, comptime .{ + .bit_width = 64, + .index_bit_width = 64, + .flags = .{ + .abi_align = .fromByteUnits(8), + .pref_align = .fromByteUnits(8), + .has_unstable_repr = false, + .has_external_state = false, + .null_ptr_repr = .all_zeros, + }, + .addr_space_name = .none, + }); + + var endian: ?std.lang.Endian = null; + var spec_it = std.mem.splitScalar(u8, string_repr.slice(builder).?, '-'); + while (spec_it.next()) |spec| switch (spec[0]) { + else => {}, + 'E' => { + assert(spec.len == 1); + assert(endian == null); + endian = .big; + }, + 'e' => { + assert(spec.len == 1); + assert(endian == null); + endian = .little; + }, + 'p' => { + var field_it = std.mem.splitScalar(u8, spec[1..], ':'); + + const first = field_it.first(); + var has_unstable_repr = false; + var has_external_state = false; + var null_ptr_repr: ?PointerSpec.NullPtrRepr = null; + var addr_space_name: String = .none; + const addr_space = for (first, 0..) |flag, as_start| switch (flag) { + 'u' => has_unstable_repr = true, + 'e' => has_external_state = true, + 'z' => { + assert(null_ptr_repr == null); + null_ptr_repr = .all_zeros; + }, + 'o' => { + assert(null_ptr_repr == null); + null_ptr_repr = .all_ones; + }, + else => { + if (first[first.len - ")".len] != ')') break first[as_start..]; + const name_start = std.mem.findScalarPos(u8, first, as_start, '(').?; + addr_space_name = try builder.string(first[name_start + "(".len .. first.len - ")".len]); + break first[as_start..name_start]; + }, + } else first[first.len..]; + const bit_width = std.fmt.parseInt(PointerSpec.BitWidth, field_it.next().?, 10) catch unreachable; + const abi_align: Alignment = .fromByteUnits(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable); + const pref_align: Alignment = if (field_it.next()) |pref_align| + .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable) + else + abi_align; + const index_bit_width = if (field_it.next()) |index_bit_width| + std.fmt.parseInt(PointerSpec.BitWidth, index_bit_width, 10) catch unreachable + else + bit_width; + assert(field_it.peek() == null); + + try pointer_specs.put(gpa, switch (addr_space.len) { + 0 => .default, + else => @fromBackingInt(std.fmt.parseInt(u24, addr_space, 10) catch unreachable), + }, .{ + .bit_width = bit_width, + .index_bit_width = index_bit_width, + .flags = .{ + .abi_align = abi_align, + .pref_align = pref_align, + .has_unstable_repr = has_unstable_repr, + .has_external_state = has_external_state, + .null_ptr_repr = null_ptr_repr orelse .all_zeros, + }, + .addr_space_name = addr_space_name, + }); + }, + 'i', 'f', 'v' => |kind| { + if (std.mem.eql(u8, spec, "ve")) { + vector_specs.clearRetainingCapacity(); + continue; + } + var field_it = std.mem.splitScalar(u8, spec[1..], ':'); + const bit_width = std.fmt.parseInt(PrimitiveSpec.BitWidth, field_it.first(), 10) catch unreachable; + const abi_align: Alignment = .fromByteUnits(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable); + const pref_align: Alignment = if (field_it.next()) |pref_align| + .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable) + else + abi_align; + assert(field_it.peek() == null); + const specs = switch (kind) { + else => unreachable, + 'i' => &int_specs, + 'f' => &float_specs, + 'v' => &vector_specs, + }; + try specs.put(gpa, .{ .bit_width = bit_width, .abi_align = abi_align, .pref_align = pref_align }, {}); + }, + 'n' => { + var field_it = std.mem.splitScalar(u8, spec[1..], ':'); + if (std.mem.eql(u8, field_it.first(), "i")) { + while (field_it.next()) |non_integral_addr_space| try non_integral_addr_spaces.append( + gpa, + @fromBackingInt(std.fmt.parseInt(u24, non_integral_addr_space, 10) catch unreachable), + ); + } else { + field_it.reset(); + while (field_it.next()) |native_bit_width| { + _ = std.fmt.parseInt(PrimitiveSpec.BitWidth, native_bit_width, 10) catch unreachable; + } + } + }, + }; + + for (non_integral_addr_spaces.items) |non_integral_addr_space| { + const pointer_spec_gop = try pointer_specs.getOrPut(gpa, non_integral_addr_space); + if (!pointer_spec_gop.found_existing) pointer_spec_gop.value_ptr.* = pointer_specs.get(.default).?; + pointer_spec_gop.value_ptr.flags.has_unstable_repr = true; + pointer_spec_gop.value_ptr.flags.has_external_state = false; + } + + { + const SortContext = struct { + specs: []const PrimitiveSpec, + pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { + return ctx.specs[lhs_index].bit_width < ctx.specs[rhs_index].bit_width; + } + }; + int_specs.sortUnstable(SortContext{ .specs = int_specs.keys() }); + float_specs.sortUnstable(SortContext{ .specs = float_specs.keys() }); + vector_specs.sortUnstable(SortContext{ .specs = vector_specs.keys() }); + } + { + const SortContext = struct { + addr_spaces: []const AddrSpace, + pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { + return @backingInt(ctx.addr_spaces[lhs_index]) < @backingInt(ctx.addr_spaces[rhs_index]); + } + }; + pointer_specs.sortUnstable(SortContext{ .addr_spaces = pointer_specs.keys() }); + assert(pointer_specs.keys()[0] == .default); + } + + return .{ + .endian = endian, + .int_specs = int_specs.move(), + .float_specs = float_specs.move(), + .vector_specs = vector_specs.move(), + .pointer_specs = pointer_specs.move(), + .string_repr = string_repr, + }; + } + + pub fn deinit(data_layout: *DataLayout, gpa: Allocator) void { + data_layout.int_specs.deinit(gpa); + data_layout.float_specs.deinit(gpa); + data_layout.vector_specs.deinit(gpa); + data_layout.pointer_specs.deinit(gpa); + } + + pub fn getIntegerSpec(data_layout: *const DataLayout, bit_width: PrimitiveSpec.BitWidth) PrimitiveSpec { + const specs = data_layout.int_specs.keys(); + return specs[ + @min(std.sort.lowerBound(PrimitiveSpec, specs, bit_width, struct { + fn order(ctx: PrimitiveSpec.BitWidth, spec: PrimitiveSpec) std.math.Order { + return std.math.order(ctx, spec.bit_width); + } + }.order), specs.len - 1) + ]; + } + + pub fn getFloatSpec(data_layout: *const DataLayout, bit_width: PrimitiveSpec.BitWidth) PrimitiveSpec { + if (data_layout.float_specs.getEntry(.{ + .bit_width = bit_width, + .abi_align = .default, + .pref_align = .default, + })) |entry| return entry.key_ptr.*; + const default_align: Alignment = .fromByteUnits( + std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, bit_width / 8), + ); + return .{ .bit_width = bit_width, .abi_align = default_align, .pref_align = default_align }; + } + + pub fn getVectorSpec( + data_layout: *const DataLayout, + bit_width: PrimitiveSpec.BitWidth, + store_size: Type.Size, + ) PrimitiveSpec { + if (data_layout.float_specs.getEntry(.{ + .bit_width = bit_width, + .abi_align = .default, + .pref_align = .default, + })) |entry| return entry.key_ptr.*; + const default_align: Alignment = .fromByteUnits( + std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, switch (store_size) { + .fixed, .scalable => |known_min| known_min, + }), + ); + return .{ .bit_width = bit_width, .abi_align = default_align, .pref_align = default_align }; + } + + pub fn getPointerSpec(data_layout: *const DataLayout, addr_space: AddrSpace) PointerSpec { + return data_layout.pointer_specs.get(addr_space) orelse data_layout.pointer_specs.values()[0]; + } +}; + pub const String = enum(u32) { none = maxInt(u31), empty, @@ -142,8 +591,8 @@ pub const String = enum(u32) { } fn fromIndex(index: ?usize) String { - return @fromBackingInt(@intCast(@as(u32, @intCast((index orelse return .none) + - @backingInt(String.empty))))); + return @fromBackingInt(@as(u32, @intCast((index orelse return .none) + + @backingInt(String.empty)))); } fn toIndex(self: String) ?usize { @@ -489,7 +938,10 @@ pub const Type = enum(u32) { .double, .i64, .x86_mmx => 64, .x86_fp80, .i80 => 80, .fp128, .ppc_fp128, .i128 => 128, - .ptr, .@"ptr addrspace(4)" => @panic("TODO: query data layout"), + .ptr => @intCast(builder.data_layout.getPointerSpec(.default).bit_width), + .@"ptr addrspace(4)" => @intCast( + builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(4))).bit_width, + ), _ => { const item = builder.type_items.items[@backingInt(self)]; return switch (item.tag) { @@ -498,7 +950,9 @@ pub const Type = enum(u32) { .vararg_function, => unreachable, .integer => @intCast(item.data), - .pointer => @panic("TODO: query data layout"), + .pointer => @intCast( + builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))).bit_width, + ), .target => unreachable, .vector, .scalable_vector, @@ -931,12 +1385,74 @@ pub const Type = enum(u32) { }, }; } + + const Size = union(enum) { fixed: u64, scalable: u64 }; + pub fn bits(ty: Type, builder: *const Builder) Size { + const item = builder.type_items.items[@backingInt(ty)]; + return switch (item.tag) { + else => unreachable, + .simple => switch (@as(Simple, @fromBackingInt(@intCast(item.data)))) { + else => unreachable, + .label => .{ .fixed = builder.data_layout.getPointerSpec(.default).bit_width }, + .half, .bfloat => .{ .fixed = 16 }, + .float => .{ .fixed = 32 }, + .double => .{ .fixed = 64 }, + .ppc_fp128, .fp128 => .{ .fixed = 128 }, + .x86_amx => .{ .fixed = 8192 }, + .x86_fp80 => .{ .fixed = 80 }, + }, + .integer => .{ .fixed = item.data }, + .pointer => .{ + .fixed = builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))).bit_width, + }, + }; + } + + pub fn alignment(ty: Type, kind: enum { abi, pref }, builder: *const Builder) Alignment { + const item = builder.type_items.items[@backingInt(ty)]; + switch (item.tag) { + else => unreachable, + .simple => switch (@as(Simple, @fromBackingInt(@intCast(item.data)))) { + else => unreachable, + .label => { + const spec = builder.data_layout.getPointerSpec(.default); + return switch (kind) { + .abi => spec.flags.abi_align, + .pref => spec.flags.pref_align, + }; + }, + .half, .bfloat, .float, .double, .ppc_fp128, .fp128, .x86_fp80 => { + const spec = builder.data_layout.getFloatSpec(@intCast(ty.bits(builder).fixed)); + return switch (kind) { + .abi => spec.abi_align, + .pref => spec.pref_align, + }; + }, + .x86_amx => return comptime .fromByteUnits(64), + }, + .integer => { + const spec = builder.data_layout.getIntegerSpec(@intCast(item.data)); + return switch (kind) { + .abi => spec.abi_align, + .pref => spec.pref_align, + }; + }, + .pointer => { + const spec = builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))); + return switch (kind) { + .abi => spec.flags.abi_align, + .pref => spec.flags.pref_align, + }; + }, + } + } }; pub const Attribute = union(Kind) { // Parameter Attributes zeroext, signext, + noext, inreg, byval: Type, byref: Type, @@ -947,6 +1463,7 @@ pub const Attribute = union(Kind) { @"align": Alignment.Lazy, @"noalias", nocapture, + captures: Captures, nofree, nest, returned, @@ -965,6 +1482,11 @@ pub const Attribute = union(Kind) { readnone, readonly, writeonly, + writable, + initializes: []const [2]u64, + dead_on_unwind, + dead_on_return: ?u32, + range: [2]Constant, // Function Attributes //alignstack: Alignment.Lazy, @@ -974,7 +1496,7 @@ pub const Attribute = union(Kind) { builtin, cold, convergent, - disable_sanitizer_information, + disable_sanitizer_instrumentation, fn_ret_thunk_extern, hot, inlinehint, @@ -984,6 +1506,7 @@ pub const Attribute = union(Kind) { naked, nobuiltin, nocallback, + nodivergencesource, noduplicate, //nofree, noimplicitfloat, @@ -1001,6 +1524,7 @@ pub const Attribute = union(Kind) { nosanitize_bounds, nosanitize_coverage, null_pointer_is_valid, + optdebug, optforfuzzing, optnone, optsize, @@ -1012,23 +1536,23 @@ pub const Attribute = union(Kind) { sanitize_thread, sanitize_hwaddress, sanitize_memtag, + sanitize_realtime, + sanitize_realtime_blocking, + sanitize_alloc_token, speculative_load_hardening, speculatable, ssp, sspstrong, sspreq, strictfp, + denormal_fpenv, uwtable: UwTable, nocf_check, shadowcallstack, mustprogress, vscale_range: VScaleRange, - - // Global Attributes - no_sanitize_address, - no_sanitize_hwaddress, - //sanitize_memtag, - sanitize_address_dyninit, + nooutline, + nocreateundeforpoison, string: struct { kind: String, value: String }, none: noreturn, @@ -1045,100 +1569,11 @@ pub const Attribute = union(Kind) { const storage = self.toStorage(builder); if (storage.kind.toString()) |kind| return .{ .string = .{ .kind = kind, - .value = @fromBackingInt(@intCast(storage.value)), + .value = @fromBackingInt(storage.value), } } else return switch (storage.kind) { - inline .zeroext, - .signext, - .inreg, - .byval, - .byref, - .preallocated, - .inalloca, - .sret, - .elementtype, - .@"align", - .@"noalias", - .nocapture, - .nofree, - .nest, - .returned, - .nonnull, - .dereferenceable, - .dereferenceable_or_null, - .swiftself, - .swiftasync, - .swifterror, - .immarg, - .noundef, - .nofpclass, - .alignstack, - .allocalign, - .allocptr, - .readnone, - .readonly, - .writeonly, - //.alignstack, - .allockind, - .allocsize, - .alwaysinline, - .builtin, - .cold, - .convergent, - .disable_sanitizer_information, - .fn_ret_thunk_extern, - .hot, - .inlinehint, - .jumptable, - .memory, - .minsize, - .naked, - .nobuiltin, - .nocallback, - .noduplicate, - //.nofree, - .noimplicitfloat, - .@"noinline", - .nomerge, - .nonlazybind, - .noprofile, - .skipprofile, - .noredzone, - .noreturn, - .norecurse, - .willreturn, - .nosync, - .nounwind, - .nosanitize_bounds, - .nosanitize_coverage, - .null_pointer_is_valid, - .optforfuzzing, - .optnone, - .optsize, - //.preallocated, - .returns_twice, - .safestack, - .sanitize_address, - .sanitize_memory, - .sanitize_thread, - .sanitize_hwaddress, - .sanitize_memtag, - .speculative_load_hardening, - .speculatable, - .ssp, - .sspstrong, - .sspreq, - .strictfp, - .uwtable, - .nocf_check, - .shadowcallstack, - .mustprogress, - .vscale_range, - .no_sanitize_address, - .no_sanitize_hwaddress, - .sanitize_address_dyninit, - => |kind| { + inline else => |kind| { const field_name, const field_type = comptime blk: { - @setEvalBranchQuota(10_000); + @setEvalBranchQuota(12_000); const info = @typeInfo(Attribute).@"union"; for (info.field_names, info.field_types) |field_name, field_type| { if (std.mem.eql(u8, field_name, @tagName(kind))) break :blk .{ field_name, field_type }; @@ -1149,14 +1584,17 @@ pub const Attribute = union(Kind) { return @unionInit(Attribute, field_name, switch (field_type) { void => {}, u32 => storage.value, - Alignment.Lazy, String, Type, UwTable => @fromBackingInt(@intCast(storage.value)), - AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value), + Alignment.Lazy, String, Type, UwTable => @fromBackingInt(storage.value), + AllocKind, AllocSize, Captures, FpClass, Memory, VScaleRange => @bitCast(storage.value), else => @compileError("bad payload type: " ++ field_name ++ ": " ++ @typeName(field_type)), }); }, - .string, .none => unreachable, - _ => unreachable, + .initializes, + .dead_on_return, + .range, + => @panic("TODO"), + .string, .none, _ => unreachable, }; } @@ -1174,6 +1612,7 @@ pub const Attribute = union(Kind) { switch (attribute) { .zeroext, .signext, + .noext, .inreg, .@"noalias", .nocapture, @@ -1191,11 +1630,13 @@ pub const Attribute = union(Kind) { .readnone, .readonly, .writeonly, + .writable, + .dead_on_unwind, .alwaysinline, .builtin, .cold, .convergent, - .disable_sanitizer_information, + .disable_sanitizer_instrumentation, .fn_ret_thunk_extern, .hot, .inlinehint, @@ -1204,6 +1645,7 @@ pub const Attribute = union(Kind) { .naked, .nobuiltin, .nocallback, + .nodivergencesource, .noduplicate, .noimplicitfloat, .@"noinline", @@ -1220,6 +1662,7 @@ pub const Attribute = union(Kind) { .nosanitize_bounds, .nosanitize_coverage, .null_pointer_is_valid, + .optdebug, .optforfuzzing, .optnone, .optsize, @@ -1230,18 +1673,21 @@ pub const Attribute = union(Kind) { .sanitize_thread, .sanitize_hwaddress, .sanitize_memtag, + .sanitize_realtime, + .sanitize_realtime_blocking, + .sanitize_alloc_token, .speculative_load_hardening, .speculatable, .ssp, .sspstrong, .sspreq, .strictfp, + .denormal_fpenv, .nocf_check, .shadowcallstack, .mustprogress, - .no_sanitize_address, - .no_sanitize_hwaddress, - .sanitize_address_dyninit, + .nooutline, + .nocreateundeforpoison, => try w.print(" {s}", .{@tagName(attribute)}), .byval, .byref, @@ -1254,6 +1700,45 @@ pub const Attribute = union(Kind) { .dereferenceable, .dereferenceable_or_null, => |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }), + .captures => |captures| { + try w.print(" {s}(", .{@tagName(attribute)}); + var need_comma = false; + if (captures == Captures.none) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("none"); + need_comma = true; + } + inline for (@typeInfo(Captures).@"struct".field_names) |field_name| { + if (comptime std.mem.eql(u8, field_name, "_")) continue; + const components = @field(captures, field_name); + if (components != Captures.Components.none) { + if (!comptime std.mem.eql(u8, field_name, "other")) { + if (need_comma) try w.writeAll(", "); + try w.writeAll(field_name ++ ": "); + need_comma = false; + } + if (components.address) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("address"); + need_comma = true; + } else if (components.address_is_null) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("address_is_null"); + need_comma = true; + } + if (components.provenance) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("provenance"); + need_comma = true; + } else if (components.read_provenance) { + if (need_comma) try w.writeAll(", "); + try w.writeAll("read_provenance"); + need_comma = true; + } + } + } + try w.writeByte(')'); + }, .nofpclass => |fpclass| { const Int = @typeInfo(FpClass).@"struct".backing_integer.?; try w.print(" {s}(", .{@tagName(attribute)}); @@ -1281,6 +1766,9 @@ pub const Attribute = union(Kind) { try w.print("({d})", .{alignment_bytes}); } }, + .initializes => @panic("TODO"), + .dead_on_return => @panic("TODO"), + .range => @panic("TODO"), .allockind => |allockind| { try w.print(" {t}(\"", .{attribute}); var any = false; @@ -1344,100 +1832,109 @@ pub const Attribute = union(Kind) { pub const Kind = enum(u32) { // Parameter Attributes - zeroext = 34, - signext = 24, - inreg = 5, - byval = 3, - byref = 69, - preallocated = 65, - inalloca = 38, - sret = 29, // TODO: ? - elementtype = 77, - @"align" = 1, - @"noalias" = 9, - nocapture = 11, - nofree = 62, - nest = 8, - returned = 22, - nonnull = 39, - dereferenceable = 41, - dereferenceable_or_null = 42, - swiftself = 46, - swiftasync = 75, - swifterror = 47, - immarg = 60, - noundef = 68, - nofpclass = 87, - alignstack = 25, - allocalign = 80, - allocptr = 81, - readnone = 20, - readonly = 21, - writeonly = 52, + zeroext = @backingInt(ATTR_KIND.Z_EXT), + signext = @backingInt(ATTR_KIND.S_EXT), + noext = @backingInt(ATTR_KIND.NO_EXT), + inreg = @backingInt(ATTR_KIND.IN_REG), + byval = @backingInt(ATTR_KIND.BY_VAL), + byref = @backingInt(ATTR_KIND.BYREF), + preallocated = @backingInt(ATTR_KIND.PREALLOCATED), + inalloca = @backingInt(ATTR_KIND.IN_ALLOCA), + sret = @backingInt(ATTR_KIND.STRUCT_RET), + elementtype = @backingInt(ATTR_KIND.ELEMENTTYPE), + @"align" = @backingInt(ATTR_KIND.ALIGNMENT), + @"noalias" = @backingInt(ATTR_KIND.NO_ALIAS), + nocapture = @backingInt(ATTR_KIND.NO_CAPTURE), + captures = @backingInt(ATTR_KIND.CAPTURES), + nofree = @backingInt(ATTR_KIND.NOFREE), + nest = @backingInt(ATTR_KIND.NEST), + returned = @backingInt(ATTR_KIND.RETURNED), + nonnull = @backingInt(ATTR_KIND.NON_NULL), + dereferenceable = @backingInt(ATTR_KIND.DEREFERENCEABLE), + dereferenceable_or_null = @backingInt(ATTR_KIND.DEREFERENCEABLE_OR_NULL), + swiftself = @backingInt(ATTR_KIND.SWIFT_SELF), + swiftasync = @backingInt(ATTR_KIND.SWIFT_ASYNC), + swifterror = @backingInt(ATTR_KIND.SWIFT_ERROR), + immarg = @backingInt(ATTR_KIND.IMMARG), + noundef = @backingInt(ATTR_KIND.NOUNDEF), + nofpclass = @backingInt(ATTR_KIND.NOFPCLASS), + alignstack = @backingInt(ATTR_KIND.STACK_ALIGNMENT), + allocalign = @backingInt(ATTR_KIND.ALLOC_ALIGN), + allocptr = @backingInt(ATTR_KIND.ALLOCATED_POINTER), + readnone = @backingInt(ATTR_KIND.READ_NONE), + readonly = @backingInt(ATTR_KIND.READ_ONLY), + writeonly = @backingInt(ATTR_KIND.WRITEONLY), + writable = @backingInt(ATTR_KIND.WRITABLE), + initializes = @backingInt(ATTR_KIND.INITIALIZES), + dead_on_unwind = @backingInt(ATTR_KIND.DEAD_ON_UNWIND), + dead_on_return = @backingInt(ATTR_KIND.DEAD_ON_RETURN), + range = @backingInt(ATTR_KIND.RANGE), // Function Attributes - //alignstack, - allockind = 82, - allocsize = 51, - alwaysinline = 2, - builtin = 35, - cold = 36, - convergent = 43, - disable_sanitizer_information = 78, - fn_ret_thunk_extern = 84, - hot = 72, - inlinehint = 4, - jumptable = 40, - memory = 86, - minsize = 6, - naked = 7, - nobuiltin = 10, - nocallback = 71, - noduplicate = 12, - //nofree, - noimplicitfloat = 13, - @"noinline" = 14, - nomerge = 66, - nonlazybind = 15, - noprofile = 73, - skipprofile = 85, - noredzone = 16, - noreturn = 17, - norecurse = 48, - willreturn = 61, - nosync = 63, - nounwind = 18, - nosanitize_bounds = 79, - nosanitize_coverage = 76, - null_pointer_is_valid = 67, - optforfuzzing = 57, - optnone = 37, - optsize = 19, - //preallocated, - returns_twice = 23, - safestack = 44, - sanitize_address = 30, - sanitize_memory = 32, - sanitize_thread = 31, - sanitize_hwaddress = 55, - sanitize_memtag = 64, - speculative_load_hardening = 59, - speculatable = 53, - ssp = 26, - sspstrong = 28, - sspreq = 27, - strictfp = 54, - uwtable = 33, - nocf_check = 56, - shadowcallstack = 58, - mustprogress = 70, - vscale_range = 74, - - // Global Attributes - no_sanitize_address = 100, - no_sanitize_hwaddress = 101, - //sanitize_memtag, - sanitize_address_dyninit = 102, + //alignstack = @intFromEnum(ATTR_KIND.STACK_ALIGNMENT), + allockind = @backingInt(ATTR_KIND.ALLOC_KIND), + allocsize = @backingInt(ATTR_KIND.ALLOC_SIZE), + alwaysinline = @backingInt(ATTR_KIND.ALWAYS_INLINE), + builtin = @backingInt(ATTR_KIND.BUILTIN), + cold = @backingInt(ATTR_KIND.COLD), + convergent = @backingInt(ATTR_KIND.CONVERGENT), + disable_sanitizer_instrumentation = @backingInt(ATTR_KIND.DISABLE_SANITIZER_INSTRUMENTATION), + fn_ret_thunk_extern = @backingInt(ATTR_KIND.FNRETTHUNK_EXTERN), + hot = @backingInt(ATTR_KIND.HOT), + inlinehint = @backingInt(ATTR_KIND.INLINE_HINT), + jumptable = @backingInt(ATTR_KIND.JUMP_TABLE), + memory = @backingInt(ATTR_KIND.MEMORY), + minsize = @backingInt(ATTR_KIND.MIN_SIZE), + naked = @backingInt(ATTR_KIND.NAKED), + nobuiltin = @backingInt(ATTR_KIND.NO_BUILTIN), + nocallback = @backingInt(ATTR_KIND.NO_CALLBACK), + nodivergencesource = @backingInt(ATTR_KIND.NO_DIVERGENCE_SOURCE), + noduplicate = @backingInt(ATTR_KIND.NO_DUPLICATE), + //nofree = @intFromEnum(ATTR_KIND.NOFREE), + noimplicitfloat = @backingInt(ATTR_KIND.NO_IMPLICIT_FLOAT), + @"noinline" = @backingInt(ATTR_KIND.NO_INLINE), + nomerge = @backingInt(ATTR_KIND.NO_MERGE), + nonlazybind = @backingInt(ATTR_KIND.NON_LAZY_BIND), + noprofile = @backingInt(ATTR_KIND.NO_PROFILE), + skipprofile = @backingInt(ATTR_KIND.SKIP_PROFILE), + noredzone = @backingInt(ATTR_KIND.NO_RED_ZONE), + noreturn = @backingInt(ATTR_KIND.NO_RETURN), + norecurse = @backingInt(ATTR_KIND.NO_RECURSE), + willreturn = @backingInt(ATTR_KIND.WILLRETURN), + nosync = @backingInt(ATTR_KIND.NOSYNC), + nounwind = @backingInt(ATTR_KIND.NO_UNWIND), + nosanitize_bounds = @backingInt(ATTR_KIND.NO_SANITIZE_BOUNDS), + nosanitize_coverage = @backingInt(ATTR_KIND.NO_SANITIZE_COVERAGE), + null_pointer_is_valid = @backingInt(ATTR_KIND.NULL_POINTER_IS_VALID), + optdebug = @backingInt(ATTR_KIND.OPTIMIZE_FOR_DEBUGGING), + optforfuzzing = @backingInt(ATTR_KIND.OPT_FOR_FUZZING), + optnone = @backingInt(ATTR_KIND.OPTIMIZE_NONE), + optsize = @backingInt(ATTR_KIND.OPTIMIZE_FOR_SIZE), + //preallocated = @intFromEnum(ATTR_KIND.PREALLOCATED), + returns_twice = @backingInt(ATTR_KIND.RETURNS_TWICE), + safestack = @backingInt(ATTR_KIND.SAFESTACK), + sanitize_address = @backingInt(ATTR_KIND.SANITIZE_ADDRESS), + sanitize_memory = @backingInt(ATTR_KIND.SANITIZE_MEMORY), + sanitize_thread = @backingInt(ATTR_KIND.SANITIZE_THREAD), + sanitize_hwaddress = @backingInt(ATTR_KIND.SANITIZE_HWADDRESS), + sanitize_memtag = @backingInt(ATTR_KIND.SANITIZE_MEMTAG), + sanitize_realtime = @backingInt(ATTR_KIND.SANITIZE_REALTIME), + sanitize_realtime_blocking = @backingInt(ATTR_KIND.SANITIZE_REALTIME_BLOCKING), + sanitize_alloc_token = @backingInt(ATTR_KIND.SANITIZE_ALLOC_TOKEN), + speculative_load_hardening = @backingInt(ATTR_KIND.SPECULATIVE_LOAD_HARDENING), + speculatable = @backingInt(ATTR_KIND.SPECULATABLE), + ssp = @backingInt(ATTR_KIND.STACK_PROTECT), + sspstrong = @backingInt(ATTR_KIND.STACK_PROTECT_STRONG), + sspreq = @backingInt(ATTR_KIND.STACK_PROTECT_REQ), + strictfp = @backingInt(ATTR_KIND.STRICT_FP), + denormal_fpenv = @backingInt(ATTR_KIND.DENORMAL_FPENV), + uwtable = @backingInt(ATTR_KIND.UW_TABLE), + nocf_check = @backingInt(ATTR_KIND.NOCF_CHECK), + shadowcallstack = @backingInt(ATTR_KIND.SHADOWCALLSTACK), + mustprogress = @backingInt(ATTR_KIND.MUSTPROGRESS), + vscale_range = @backingInt(ATTR_KIND.VSCALE_RANGE), + nooutline = @backingInt(ATTR_KIND.NOOUTLINE), + nocreateundeforpoison = @backingInt(ATTR_KIND.NO_CREATE_UNDEF_OR_POISON), string = maxInt(u31), none = maxInt(u32), @@ -1447,16 +1944,128 @@ pub const Attribute = union(Kind) { pub fn fromString(str: String) Kind { assert(!str.isAnon()); - const kind: Kind = @fromBackingInt(@intCast(@backingInt(str))); + const kind: Kind = @fromBackingInt(@backingInt(str)); assert(kind != .none); return kind; } fn toString(self: Kind) ?String { assert(self != .none); - const str: String = @fromBackingInt(@intCast(@backingInt(self))); + const str: String = @fromBackingInt(@backingInt(self)); return if (str.isAnon()) null else str; } + + /// enum AttributeKindCodes + const ATTR_KIND = enum(u32) { + ALIGNMENT = 1, + ALWAYS_INLINE = 2, + BY_VAL = 3, + INLINE_HINT = 4, + IN_REG = 5, + MIN_SIZE = 6, + NAKED = 7, + NEST = 8, + NO_ALIAS = 9, + NO_BUILTIN = 10, + NO_CAPTURE = 11, + NO_DUPLICATE = 12, + NO_IMPLICIT_FLOAT = 13, + NO_INLINE = 14, + NON_LAZY_BIND = 15, + NO_RED_ZONE = 16, + NO_RETURN = 17, + NO_UNWIND = 18, + OPTIMIZE_FOR_SIZE = 19, + READ_NONE = 20, + READ_ONLY = 21, + RETURNED = 22, + RETURNS_TWICE = 23, + S_EXT = 24, + STACK_ALIGNMENT = 25, + STACK_PROTECT = 26, + STACK_PROTECT_REQ = 27, + STACK_PROTECT_STRONG = 28, + STRUCT_RET = 29, + SANITIZE_ADDRESS = 30, + SANITIZE_THREAD = 31, + SANITIZE_MEMORY = 32, + UW_TABLE = 33, + Z_EXT = 34, + BUILTIN = 35, + COLD = 36, + OPTIMIZE_NONE = 37, + IN_ALLOCA = 38, + NON_NULL = 39, + JUMP_TABLE = 40, + DEREFERENCEABLE = 41, + DEREFERENCEABLE_OR_NULL = 42, + CONVERGENT = 43, + SAFESTACK = 44, + ARGMEMONLY = 45, + SWIFT_SELF = 46, + SWIFT_ERROR = 47, + NO_RECURSE = 48, + INACCESSIBLEMEM_ONLY = 49, + INACCESSIBLEMEM_OR_ARGMEMONLY = 50, + ALLOC_SIZE = 51, + WRITEONLY = 52, + SPECULATABLE = 53, + STRICT_FP = 54, + SANITIZE_HWADDRESS = 55, + NOCF_CHECK = 56, + OPT_FOR_FUZZING = 57, + SHADOWCALLSTACK = 58, + SPECULATIVE_LOAD_HARDENING = 59, + IMMARG = 60, + WILLRETURN = 61, + NOFREE = 62, + NOSYNC = 63, + SANITIZE_MEMTAG = 64, + PREALLOCATED = 65, + NO_MERGE = 66, + NULL_POINTER_IS_VALID = 67, + NOUNDEF = 68, + BYREF = 69, + MUSTPROGRESS = 70, + NO_CALLBACK = 71, + HOT = 72, + NO_PROFILE = 73, + VSCALE_RANGE = 74, + SWIFT_ASYNC = 75, + NO_SANITIZE_COVERAGE = 76, + ELEMENTTYPE = 77, + DISABLE_SANITIZER_INSTRUMENTATION = 78, + NO_SANITIZE_BOUNDS = 79, + ALLOC_ALIGN = 80, + ALLOCATED_POINTER = 81, + ALLOC_KIND = 82, + PRESPLIT_COROUTINE = 83, + FNRETTHUNK_EXTERN = 84, + SKIP_PROFILE = 85, + MEMORY = 86, + NOFPCLASS = 87, + OPTIMIZE_FOR_DEBUGGING = 88, + WRITABLE = 89, + CORO_ONLY_DESTROY_WHEN_COMPLETE = 90, + DEAD_ON_UNWIND = 91, + RANGE = 92, + SANITIZE_NUMERICAL_STABILITY = 93, + INITIALIZES = 94, + HYBRID_PATCHABLE = 95, + SANITIZE_REALTIME = 96, + SANITIZE_REALTIME_BLOCKING = 97, + CORO_ELIDE_SAFE = 98, + NO_EXT = 99, + NO_DIVERGENCE_SOURCE = 100, + SANITIZE_TYPE = 101, + CAPTURES = 102, + DEAD_ON_RETURN = 103, + SANITIZE_ALLOC_TOKEN = 104, + NO_CREATE_UNDEF_OR_POISON = 105, + DENORMAL_FPENV = 106, + NOOUTLINE = 107, + FLATTEN = 108, + }; }; pub const FpClass = packed struct(u32) { @@ -1506,6 +2115,29 @@ pub const Attribute = union(Kind) { pub const pnorm = FpClass{ .positive_normal = true }; }; + pub const Captures = packed struct(u32) { + other: Components = .none, + ret: Components = .none, + _: u24 = 0, + + pub const none: Captures = .{}; + + pub const Components = packed struct(u4) { + address_is_null: bool = false, + address: bool = false, + read_provenance: bool = false, + provenance: bool = false, + + pub const none: Components = .{}; + pub const all: Components = .{ + .address_is_null = true, + .address = true, + .read_provenance = true, + .provenance = true, + }; + }; + }; + pub const AllocKind = packed struct(u32) { alloc: bool, realloc: bool, @@ -1582,9 +2214,13 @@ pub const Attribute = union(Kind) { void => 0, u32 => value, Alignment.Lazy, String, Type, UwTable => @backingInt(value), - AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value), - else => @compileError("bad payload type: " ++ @tagName(tag) ++ @typeName(@TypeOf(value))), + AllocKind, AllocSize, Captures, FpClass, Memory, VScaleRange => @bitCast(value), + else => @compileError("bad payload type: " ++ @tagName(tag) ++ ": " ++ @typeName(@TypeOf(value))), } }, + .initializes, + .dead_on_return, + .range, + => @panic("TODO"), .string => |string_attr| .{ .kind = Kind.fromString(string_attr.kind), .value = @backingInt(string_attr.value), @@ -1907,87 +2543,87 @@ pub const AddrSpace = enum(u24) { // See llvm/lib/Target/X86/X86.h pub const x86 = struct { - pub const gs: AddrSpace = @fromBackingInt(@intCast(256)); - pub const fs: AddrSpace = @fromBackingInt(@intCast(257)); - pub const ss: AddrSpace = @fromBackingInt(@intCast(258)); + pub const gs: AddrSpace = @fromBackingInt(256); + pub const fs: AddrSpace = @fromBackingInt(257); + pub const ss: AddrSpace = @fromBackingInt(258); - pub const ptr32_sptr: AddrSpace = @fromBackingInt(@intCast(270)); - pub const ptr32_uptr: AddrSpace = @fromBackingInt(@intCast(271)); - pub const ptr64: AddrSpace = @fromBackingInt(@intCast(272)); + pub const ptr32_sptr: AddrSpace = @fromBackingInt(270); + pub const ptr32_uptr: AddrSpace = @fromBackingInt(271); + pub const ptr64: AddrSpace = @fromBackingInt(272); }; pub const x86_64 = x86; // See llvm/lib/Target/AVR/AVR.h pub const avr = struct { - pub const data: AddrSpace = @fromBackingInt(@intCast(0)); - pub const program: AddrSpace = @fromBackingInt(@intCast(1)); - pub const program1: AddrSpace = @fromBackingInt(@intCast(2)); - pub const program2: AddrSpace = @fromBackingInt(@intCast(3)); - pub const program3: AddrSpace = @fromBackingInt(@intCast(4)); - pub const program4: AddrSpace = @fromBackingInt(@intCast(5)); - pub const program5: AddrSpace = @fromBackingInt(@intCast(6)); + pub const data: AddrSpace = @fromBackingInt(0); + pub const program: AddrSpace = @fromBackingInt(1); + pub const program1: AddrSpace = @fromBackingInt(2); + pub const program2: AddrSpace = @fromBackingInt(3); + pub const program3: AddrSpace = @fromBackingInt(4); + pub const program4: AddrSpace = @fromBackingInt(5); + pub const program5: AddrSpace = @fromBackingInt(6); }; // See llvm/lib/Target/NVPTX/NVPTX.h pub const nvptx = struct { - pub const generic: AddrSpace = @fromBackingInt(@intCast(0)); - pub const global: AddrSpace = @fromBackingInt(@intCast(1)); - pub const constant: AddrSpace = @fromBackingInt(@intCast(2)); - pub const shared: AddrSpace = @fromBackingInt(@intCast(3)); - pub const param: AddrSpace = @fromBackingInt(@intCast(4)); - pub const local: AddrSpace = @fromBackingInt(@intCast(5)); + pub const generic: AddrSpace = @fromBackingInt(0); + pub const global: AddrSpace = @fromBackingInt(1); + pub const constant: AddrSpace = @fromBackingInt(2); + pub const shared: AddrSpace = @fromBackingInt(3); + pub const param: AddrSpace = @fromBackingInt(4); + pub const local: AddrSpace = @fromBackingInt(5); }; // See llvm/lib/Target/AMDGPU/AMDGPU.h pub const amdgpu = struct { - pub const flat: AddrSpace = @fromBackingInt(@intCast(0)); - pub const global: AddrSpace = @fromBackingInt(@intCast(1)); - pub const region: AddrSpace = @fromBackingInt(@intCast(2)); - pub const local: AddrSpace = @fromBackingInt(@intCast(3)); - pub const constant: AddrSpace = @fromBackingInt(@intCast(4)); - pub const private: AddrSpace = @fromBackingInt(@intCast(5)); - pub const constant_32bit: AddrSpace = @fromBackingInt(@intCast(6)); - pub const buffer_fat_pointer: AddrSpace = @fromBackingInt(@intCast(7)); - pub const buffer_resource: AddrSpace = @fromBackingInt(@intCast(8)); - pub const buffer_strided_pointer: AddrSpace = @fromBackingInt(@intCast(9)); - pub const param_d: AddrSpace = @fromBackingInt(@intCast(6)); - pub const param_i: AddrSpace = @fromBackingInt(@intCast(7)); - pub const constant_buffer_0: AddrSpace = @fromBackingInt(@intCast(8)); - pub const constant_buffer_1: AddrSpace = @fromBackingInt(@intCast(9)); - pub const constant_buffer_2: AddrSpace = @fromBackingInt(@intCast(10)); - pub const constant_buffer_3: AddrSpace = @fromBackingInt(@intCast(11)); - pub const constant_buffer_4: AddrSpace = @fromBackingInt(@intCast(12)); - pub const constant_buffer_5: AddrSpace = @fromBackingInt(@intCast(13)); - pub const constant_buffer_6: AddrSpace = @fromBackingInt(@intCast(14)); - pub const constant_buffer_7: AddrSpace = @fromBackingInt(@intCast(15)); - pub const constant_buffer_8: AddrSpace = @fromBackingInt(@intCast(16)); - pub const constant_buffer_9: AddrSpace = @fromBackingInt(@intCast(17)); - pub const constant_buffer_10: AddrSpace = @fromBackingInt(@intCast(18)); - pub const constant_buffer_11: AddrSpace = @fromBackingInt(@intCast(19)); - pub const constant_buffer_12: AddrSpace = @fromBackingInt(@intCast(20)); - pub const constant_buffer_13: AddrSpace = @fromBackingInt(@intCast(21)); - pub const constant_buffer_14: AddrSpace = @fromBackingInt(@intCast(22)); - pub const constant_buffer_15: AddrSpace = @fromBackingInt(@intCast(23)); - pub const streamout_register: AddrSpace = @fromBackingInt(@intCast(128)); + pub const flat: AddrSpace = @fromBackingInt(0); + pub const global: AddrSpace = @fromBackingInt(1); + pub const region: AddrSpace = @fromBackingInt(2); + pub const local: AddrSpace = @fromBackingInt(3); + pub const constant: AddrSpace = @fromBackingInt(4); + pub const private: AddrSpace = @fromBackingInt(5); + pub const constant_32bit: AddrSpace = @fromBackingInt(6); + pub const buffer_fat_pointer: AddrSpace = @fromBackingInt(7); + pub const buffer_resource: AddrSpace = @fromBackingInt(8); + pub const buffer_strided_pointer: AddrSpace = @fromBackingInt(9); + pub const param_d: AddrSpace = @fromBackingInt(6); + pub const param_i: AddrSpace = @fromBackingInt(7); + pub const constant_buffer_0: AddrSpace = @fromBackingInt(8); + pub const constant_buffer_1: AddrSpace = @fromBackingInt(9); + pub const constant_buffer_2: AddrSpace = @fromBackingInt(10); + pub const constant_buffer_3: AddrSpace = @fromBackingInt(11); + pub const constant_buffer_4: AddrSpace = @fromBackingInt(12); + pub const constant_buffer_5: AddrSpace = @fromBackingInt(13); + pub const constant_buffer_6: AddrSpace = @fromBackingInt(14); + pub const constant_buffer_7: AddrSpace = @fromBackingInt(15); + pub const constant_buffer_8: AddrSpace = @fromBackingInt(16); + pub const constant_buffer_9: AddrSpace = @fromBackingInt(17); + pub const constant_buffer_10: AddrSpace = @fromBackingInt(18); + pub const constant_buffer_11: AddrSpace = @fromBackingInt(19); + pub const constant_buffer_12: AddrSpace = @fromBackingInt(20); + pub const constant_buffer_13: AddrSpace = @fromBackingInt(21); + pub const constant_buffer_14: AddrSpace = @fromBackingInt(22); + pub const constant_buffer_15: AddrSpace = @fromBackingInt(23); + pub const streamout_register: AddrSpace = @fromBackingInt(128); }; pub const spirv = struct { - pub const function: AddrSpace = @fromBackingInt(@intCast(0)); - pub const cross_workgroup: AddrSpace = @fromBackingInt(@intCast(1)); - pub const uniform_constant: AddrSpace = @fromBackingInt(@intCast(2)); - pub const workgroup: AddrSpace = @fromBackingInt(@intCast(3)); - pub const generic: AddrSpace = @fromBackingInt(@intCast(4)); - pub const device_only_intel: AddrSpace = @fromBackingInt(@intCast(5)); - pub const host_only_intel: AddrSpace = @fromBackingInt(@intCast(6)); - pub const input: AddrSpace = @fromBackingInt(@intCast(7)); + pub const function: AddrSpace = @fromBackingInt(0); + pub const cross_workgroup: AddrSpace = @fromBackingInt(1); + pub const uniform_constant: AddrSpace = @fromBackingInt(2); + pub const workgroup: AddrSpace = @fromBackingInt(3); + pub const generic: AddrSpace = @fromBackingInt(4); + pub const device_only_intel: AddrSpace = @fromBackingInt(5); + pub const host_only_intel: AddrSpace = @fromBackingInt(6); + pub const input: AddrSpace = @fromBackingInt(7); }; // See llvm/include/llvm/CodeGen/WasmAddressSpaces.h pub const wasm = struct { - pub const default: AddrSpace = @fromBackingInt(@intCast(0)); - pub const variable: AddrSpace = @fromBackingInt(@intCast(1)); - pub const externref: AddrSpace = @fromBackingInt(@intCast(10)); - pub const funcref: AddrSpace = @fromBackingInt(@intCast(20)); + pub const default: AddrSpace = @fromBackingInt(0); + pub const variable: AddrSpace = @fromBackingInt(1); + pub const externref: AddrSpace = @fromBackingInt(10); + pub const funcref: AddrSpace = @fromBackingInt(20); }; pub fn format(addr_space: AddrSpace, w: *Writer) Writer.Error!void { @@ -2030,7 +2666,7 @@ pub const Alignment = enum(u6) { _, pub fn wrap(a: Alignment) Lazy { - return @fromBackingInt(@intCast(@backingInt(a))); + return @fromBackingInt(@backingInt(a)); } pub fn resolve(l: Lazy, b: *const Builder) Alignment { return switch (@backingInt(l)) { @@ -2061,11 +2697,18 @@ pub const Alignment = enum(u6) { }; } - /// Asserts that neither `a` nor `b` is `.default`. - pub fn max(a: Alignment, b: Alignment) Alignment { - assert(a != .default); - assert(b != .default); - return @fromBackingInt(@intCast(@max(@backingInt(a), @backingInt(b)))); + /// Asserts that neither `lhs` nor `rhs` is `.default`. + pub fn max(lhs: Alignment, rhs: Alignment) Alignment { + assert(lhs != .default); + assert(rhs != .default); + return @fromBackingInt(@max(@backingInt(lhs), @backingInt(rhs))); + } + + /// Asserts that neither `lhs` nor `rhs` is `.default`. + pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order { + assert(lhs != .default); + assert(rhs != .default); + return std.math.order(@backingInt(lhs), @backingInt(rhs)); } pub fn toLlvm(self: Alignment) u6 { @@ -2106,6 +2749,7 @@ pub const CallConv = enum(u10) { tailcc, cfguard_checkcc, swifttailcc, + preserve_nonecc, x86_stdcallcc = 64, x86_fastcallcc, @@ -2174,6 +2818,7 @@ pub const CallConv = enum(u10) { .tailcc, .cfguard_checkcc, .swifttailcc, + .preserve_nonecc, .x86_stdcallcc, .x86_fastcallcc, .arm_apcscc, @@ -2261,8 +2906,7 @@ pub const StrtabString = enum(u32) { } fn fromIndex(index: ?usize) StrtabString { - return @fromBackingInt(@intCast(@as(u32, @intCast((index orelse return .none) + - @backingInt(StrtabString.empty))))); + return @fromBackingInt(@intCast((index orelse return .none) + @backingInt(StrtabString.empty))); } fn toIndex(self: StrtabString) ?usize { @@ -2318,7 +2962,7 @@ pub fn trailingStrtabString(self: *Builder) Allocator.Error!StrtabString { } pub fn trailingStrtabStringAssumeCapacity(self: *Builder) StrtabString { - const start = self.strtab_string_indices.getLast().?; + const start = self.strtab_string_indices.last().?; const bytes: []const u8 = self.strtab_string_bytes.items[start..]; const gop = self.strtab_string_map.getOrPutAssumeCapacityAdapted(bytes, StrtabString.Adapter{ .builder = self }); if (gop.found_existing) { @@ -2398,7 +3042,7 @@ pub const Global = struct { } pub fn toConst(global: Index) Constant { - return @fromBackingInt(@intCast(@backingInt(Constant.first_global) + @backingInt(global))); + return @fromBackingInt(@backingInt(Constant.first_global) + @backingInt(global)); } pub fn toValue(global: Index) Value { @@ -2526,7 +3170,7 @@ pub const Global = struct { _ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]); builder.globals.swapRemoveAt(index); if (!old_name.isAnon()) return; - builder.next_unnamed_global = @fromBackingInt(@intCast(@backingInt(builder.next_unnamed_global) - 1)); + builder.next_unnamed_global = @fromBackingInt(@backingInt(builder.next_unnamed_global) - 1); if (builder.next_unnamed_global == old_name) return; builder.getGlobal(builder.next_unnamed_global).?.renameAssumeCapacity(old_name, builder); } @@ -2539,7 +3183,7 @@ pub const Global = struct { fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void { if (self.eql(other, builder)) return; - builder.next_replaced_global = @fromBackingInt(@intCast(@backingInt(builder.next_replaced_global) - 1)); + builder.next_replaced_global = @fromBackingInt(@backingInt(builder.next_replaced_global) - 1); self.renameAssumeCapacity(builder.next_replaced_global, builder); self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) }; } @@ -2699,6 +3343,8 @@ pub const Intrinsic = enum { smin, umax, umin, + scmp, + ucmp, memcpy, @"memcpy.inline", memmove, @@ -2708,10 +3354,21 @@ pub const Intrinsic = enum { powi, sin, cos, + tan, + asin, + acos, + atan, + atan2, + sinh, + cosh, + tanh, + sincos, + sincospi, + modf, pow, exp, - exp10, exp2, + exp10, ldexp, frexp, log, @@ -2723,6 +3380,8 @@ pub const Intrinsic = enum { maxnum, minimum, maximum, + minimumnum, + maximumnum, copysign, floor, ceil, @@ -2744,6 +3403,7 @@ pub const Intrinsic = enum { cttz, fshl, fshr, + clmul, // Arithmetic with Overflow @"sadd.with.overflow", @@ -2904,21 +3564,21 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .ptr } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .addressofreturnaddress = .{ .ret_len = 1, .params = &.{ .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .sponentry = .{ .ret_len = 1, .params = &.{ .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .frameaddress = .{ .ret_len = 1, @@ -2926,7 +3586,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .prefetch = .{ .ret_len = 0, @@ -2936,14 +3596,14 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.readwrite) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.readwrite) } }, }, .@"thread.pointer" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .ptr } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .abs = .{ @@ -2953,7 +3613,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .smax = .{ .ret_len = 1, @@ -2962,7 +3622,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .smin = .{ .ret_len = 1, @@ -2971,7 +3631,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .umax = .{ .ret_len = 1, @@ -2980,7 +3640,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .umin = .{ .ret_len = 1, @@ -2989,7 +3649,25 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .scmp = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 1 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .ucmp = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 1 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .memcpy = .{ .ret_len = 0, @@ -3047,7 +3725,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .powi = .{ .ret_len = 1, @@ -3056,7 +3734,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .sin = .{ .ret_len = 1, @@ -3064,7 +3742,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .cos = .{ .ret_len = 1, @@ -3072,7 +3750,99 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .tan = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .asin = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .acos = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .atan = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .atan2 = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .sinh = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .cosh = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .tanh = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .sincos = .{ + .ret_len = 2, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .sincospi = .{ + .ret_len = 2, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .modf = .{ + .ret_len = 2, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .pow = .{ .ret_len = 1, @@ -3081,7 +3851,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .exp = .{ .ret_len = 1, @@ -3089,7 +3859,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .exp2 = .{ .ret_len = 1, @@ -3097,7 +3867,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .exp10 = .{ .ret_len = 1, @@ -3105,7 +3875,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .ldexp = .{ .ret_len = 1, @@ -3114,7 +3884,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .frexp = .{ .ret_len = 2, @@ -3123,7 +3893,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .log = .{ .ret_len = 1, @@ -3131,7 +3901,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .log10 = .{ .ret_len = 1, @@ -3139,7 +3909,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .log2 = .{ .ret_len = 1, @@ -3147,7 +3917,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fma = .{ .ret_len = 1, @@ -3157,7 +3927,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fabs = .{ .ret_len = 1, @@ -3165,7 +3935,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .minnum = .{ .ret_len = 1, @@ -3174,7 +3944,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .maxnum = .{ .ret_len = 1, @@ -3183,7 +3953,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .minimum = .{ .ret_len = 1, @@ -3192,7 +3962,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .maximum = .{ .ret_len = 1, @@ -3201,7 +3971,25 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .minimumnum = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .maximumnum = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .copysign = .{ .ret_len = 1, @@ -3210,7 +3998,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .floor = .{ .ret_len = 1, @@ -3218,7 +4006,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .ceil = .{ .ret_len = 1, @@ -3226,7 +4014,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .trunc = .{ .ret_len = 1, @@ -3234,7 +4022,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .rint = .{ .ret_len = 1, @@ -3242,7 +4030,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .nearbyint = .{ .ret_len = 1, @@ -3250,7 +4038,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .round = .{ .ret_len = 1, @@ -3258,7 +4046,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .roundeven = .{ .ret_len = 1, @@ -3266,7 +4054,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .lround = .{ .ret_len = 1, @@ -3274,7 +4062,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .llround = .{ .ret_len = 1, @@ -3282,7 +4070,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .lrint = .{ .ret_len = 1, @@ -3290,7 +4078,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .llrint = .{ .ret_len = 1, @@ -3298,7 +4086,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .bitreverse = .{ @@ -3307,7 +4095,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .bswap = .{ .ret_len = 1, @@ -3315,7 +4103,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .ctpop = .{ .ret_len = 1, @@ -3323,7 +4111,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .ctlz = .{ .ret_len = 1, @@ -3332,7 +4120,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .cttz = .{ .ret_len = 1, @@ -3341,7 +4129,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fshl = .{ .ret_len = 1, @@ -3351,7 +4139,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fshr = .{ .ret_len = 1, @@ -3361,7 +4149,16 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, + }, + .clmul = .{ + .ret_len = 1, + .params = &.{ + .{ .kind = .overloaded }, + .{ .kind = .{ .matches = 0 } }, + .{ .kind = .{ .matches = 0 } }, + }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"sadd.with.overflow" = .{ @@ -3372,7 +4169,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"uadd.with.overflow" = .{ .ret_len = 2, @@ -3382,7 +4179,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"ssub.with.overflow" = .{ .ret_len = 2, @@ -3392,7 +4189,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"usub.with.overflow" = .{ .ret_len = 2, @@ -3402,7 +4199,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"smul.with.overflow" = .{ .ret_len = 2, @@ -3412,7 +4209,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"umul.with.overflow" = .{ .ret_len = 2, @@ -3422,7 +4219,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"sadd.sat" = .{ @@ -3432,7 +4229,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"uadd.sat" = .{ .ret_len = 1, @@ -3441,7 +4238,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"ssub.sat" = .{ .ret_len = 1, @@ -3450,7 +4247,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"usub.sat" = .{ .ret_len = 1, @@ -3459,7 +4256,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"sshl.sat" = .{ .ret_len = 1, @@ -3468,7 +4265,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"ushl.sat" = .{ .ret_len = 1, @@ -3477,7 +4274,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"smul.fix" = .{ @@ -3488,7 +4285,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"umul.fix" = .{ .ret_len = 1, @@ -3498,7 +4295,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"smul.fix.sat" = .{ .ret_len = 1, @@ -3508,7 +4305,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"umul.fix.sat" = .{ .ret_len = 1, @@ -3518,7 +4315,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"sdiv.fix" = .{ .ret_len = 1, @@ -3528,7 +4325,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"udiv.fix" = .{ .ret_len = 1, @@ -3538,7 +4335,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"sdiv.fix.sat" = .{ .ret_len = 1, @@ -3548,7 +4345,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"udiv.fix.sat" = .{ .ret_len = 1, @@ -3558,7 +4355,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .canonicalize = .{ @@ -3567,7 +4364,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .fmuladd = .{ .ret_len = 1, @@ -3577,7 +4374,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.add" = .{ @@ -3586,7 +4383,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fadd" = .{ .ret_len = 1, @@ -3595,7 +4392,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 2 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.mul" = .{ .ret_len = 1, @@ -3603,7 +4400,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fmul" = .{ .ret_len = 1, @@ -3612,7 +4409,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 2 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.and" = .{ .ret_len = 1, @@ -3620,7 +4417,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.or" = .{ .ret_len = 1, @@ -3628,7 +4425,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.xor" = .{ .ret_len = 1, @@ -3636,7 +4433,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.smax" = .{ .ret_len = 1, @@ -3644,7 +4441,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.smin" = .{ .ret_len = 1, @@ -3652,7 +4449,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.umax" = .{ .ret_len = 1, @@ -3660,7 +4457,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.umin" = .{ .ret_len = 1, @@ -3668,7 +4465,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fmax" = .{ .ret_len = 1, @@ -3676,7 +4473,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fmin" = .{ .ret_len = 1, @@ -3684,7 +4481,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fmaximum" = .{ .ret_len = 1, @@ -3692,7 +4489,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.reduce.fminimum" = .{ .ret_len = 1, @@ -3700,7 +4497,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches_scalar = 1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.insert" = .{ .ret_len = 1, @@ -3710,7 +4507,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i64 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"vector.extract" = .{ .ret_len = 1, @@ -3719,7 +4516,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i64 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"is.fpclass" = .{ @@ -3729,7 +4526,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nocreateundeforpoison, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"var.annotation" = .{ @@ -3814,7 +4611,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .expect = .{ .ret_len = 1, @@ -3823,7 +4620,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"expect.with.probability" = .{ .ret_len = 1, @@ -3833,7 +4630,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .{ .type = .double }, .attrs = &.{.immarg} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .assume = .{ .ret_len = 0, @@ -3848,7 +4645,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 }, .attrs = &.{.returned} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"type.test" = .{ .ret_len = 1, @@ -3857,7 +4654,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .ptr } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"type.checked.load" = .{ .ret_len = 2, @@ -3868,7 +4665,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i32 } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"type.checked.load.relative" = .{ .ret_len = 2, @@ -3879,7 +4676,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i32 } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"arithmetic.fence" = .{ .ret_len = 1, @@ -3887,12 +4684,12 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .matches = 0 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .donothing = .{ .ret_len = 0, .params = &.{}, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"load.relative" = .{ .ret_len = 1, @@ -3914,7 +4711,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .i1 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .convergent, .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .convergent, .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .ptrmask = .{ .ret_len = 1, @@ -3923,7 +4720,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .matches = 0 } }, .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"threadlocal.address" = .{ .ret_len = 1, @@ -3931,14 +4728,14 @@ pub const Intrinsic = enum { .{ .kind = .overloaded, .attrs = &.{.nonnull} }, .{ .kind = .{ .matches = 0 }, .attrs = &.{.nonnull} }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .vscale = .{ .ret_len = 1, .params = &.{ .{ .kind = .overloaded }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"dbg.declare" = .{ @@ -3948,7 +4745,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .metadata } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"dbg.value" = .{ .ret_len = 0, @@ -3957,7 +4754,7 @@ pub const Intrinsic = enum { .{ .kind = .{ .type = .metadata } }, .{ .kind = .{ .type = .metadata } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workitem.id.x" = .{ @@ -3965,42 +4762,42 @@ pub const Intrinsic = enum { .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workitem.id.y" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workitem.id.z" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workgroup.id.x" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workgroup.id.y" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.workgroup.id.z" = .{ .ret_len = 1, .params = &.{ .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"amdgcn.dispatch.ptr" = .{ .ret_len = 1, @@ -4010,7 +4807,7 @@ pub const Intrinsic = enum { .attrs = &.{.{ .@"align" = .wrap(.fromByteUnits(4)) }}, }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = .all(.none) } }, }, .@"nvvm.read.ptx.sreg.tid.x" = .{ @@ -4085,7 +4882,7 @@ pub const Intrinsic = enum { .{ .kind = .overloaded }, .{ .kind = .{ .type = .i32 } }, }, - .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, + .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .all(.none) } }, }, .@"wasm.memory.grow" = .{ .ret_len = 1, @@ -4166,6 +4963,10 @@ pub const Function = struct { self.ptr(builder).attributes = new_function_attributes; } + pub fn getAttributes(self: Index, builder: *Builder) FunctionAttributes { + return self.ptr(builder).attributes; + } + pub fn setSection(self: Index, section: String, builder: *Builder) void { self.ptr(builder).section = section; } @@ -4487,7 +5288,7 @@ pub const Function = struct { } pub fn toValue(self: Instruction.Index) Value { - return @fromBackingInt(@intCast(@backingInt(self))); + return @fromBackingInt(@backingInt(self)); } pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool { @@ -4679,7 +5480,7 @@ pub const Function = struct { .changeScalarAssumeCapacity(.i1, wip.builder), .fneg, .@"fneg fast", - => @as(Value, @fromBackingInt(@intCast(instruction.data))).typeOfWip(wip), + => @as(Value, @fromBackingInt(instruction.data)).typeOfWip(wip), .getelementptr, .@"getelementptr inbounds", => { @@ -4871,7 +5672,7 @@ pub const Function = struct { .changeScalarAssumeCapacity(.i1, builder), .fneg, .@"fneg fast", - => @as(Value, @fromBackingInt(@intCast(instruction.data))).typeOf(function_index, builder), + => @as(Value, @fromBackingInt(instruction.data)).typeOf(function_index, builder), .getelementptr, .@"getelementptr inbounds", => { @@ -4963,7 +5764,7 @@ pub const Function = struct { pub fn fromMetadata(metadata: Metadata) Weights { assert(metadata.kind == .node); - return @fromBackingInt(@intCast(metadata.index)); + return @fromBackingInt(metadata.index); } pub fn toMetadata(weights: Weights) Metadata { @@ -5156,7 +5957,7 @@ pub const Function = struct { assert(argument.tag == .arg); assert(argument.data == index); - const argument_index: Instruction.Index = @fromBackingInt(@intCast(index)); + const argument_index: Instruction.Index = @fromBackingInt(index); return argument_index.toValue(); } @@ -5202,7 +6003,7 @@ pub const Function = struct { Type, Value, Instruction.BrCond.Weights, - => @fromBackingInt(@intCast(value)), + => @fromBackingInt(value), MemoryAccessInfo, Instruction.Alloca.Info, Instruction.Call.Info, @@ -5327,7 +6128,7 @@ pub const WipFunction = struct { assert(argument.tag == .arg); assert(argument.data == index); - const argument_index: Instruction.Index = @fromBackingInt(@intCast(index)); + const argument_index: Instruction.Index = @fromBackingInt(index); return argument_index.toValue(); } @@ -5722,7 +6523,7 @@ pub const WipFunction = struct { alignment: Alignment, name: []const u8, ) Allocator.Error!Value { - return self.loadAtomic(access_kind, ty, ptr, .system, .none, alignment, name); + return self.loadAtomic(access_kind, ty, ptr, undefined, .none, alignment, name); } pub fn loadAtomic( @@ -5766,7 +6567,7 @@ pub const WipFunction = struct { ptr: Value, alignment: Alignment, ) Allocator.Error!Instruction.Index { - return self.storeAtomic(kind, val, ptr, .system, .none, alignment); + return self.storeAtomic(kind, val, ptr, undefined, .none, alignment); } pub fn storeAtomic( @@ -6414,24 +7215,24 @@ pub const WipFunction = struct { errdefer function.instructions.shrinkRetainingCapacity(0); { - var final_instruction_index: Instruction.Index = @fromBackingInt(@intCast(0)); + var final_instruction_index: Instruction.Index = @fromBackingInt(0); for (0..params_len) |param_index| { instructions.items[param_index] = final_instruction_index; - final_instruction_index = @fromBackingInt(@intCast(@backingInt(final_instruction_index) + 1)); + final_instruction_index = @fromBackingInt(@backingInt(final_instruction_index) + 1); } for (blocks, self.blocks.items) |*final_block, current_block| { assert(current_block.incoming == current_block.branches); final_block.instruction = final_instruction_index; - final_instruction_index = @fromBackingInt(@intCast(@backingInt(final_instruction_index) + 1)); + final_instruction_index = @fromBackingInt(@backingInt(final_instruction_index) + 1); for (current_block.instructions.items) |instruction| { instructions.items[@backingInt(instruction)] = final_instruction_index; - final_instruction_index = @fromBackingInt(@intCast(@backingInt(final_instruction_index) + 1)); + final_instruction_index = @fromBackingInt(@backingInt(final_instruction_index) + 1); } } } var wip_name: struct { - next_name: String = @fromBackingInt(@intCast(0)), + next_name: String = @fromBackingInt(0), next_unique_name: std.AutoHashMap(String, String), builder: *Builder, @@ -6440,19 +7241,19 @@ pub const WipFunction = struct { .none => return .none, .empty => { assert(wip_name.next_name != .none); - defer wip_name.next_name = @fromBackingInt(@intCast(@backingInt(wip_name.next_name) + 1)); + defer wip_name.next_name = @fromBackingInt(@backingInt(wip_name.next_name) + 1); return wip_name.next_name; }, _ => { assert(!name.isAnon()); const gop = try wip_name.next_unique_name.getOrPut(name); if (!gop.found_existing) { - gop.value_ptr.* = @fromBackingInt(@intCast(0)); + gop.value_ptr.* = @fromBackingInt(0); return name; } while (true) { - gop.value_ptr.* = @fromBackingInt(@intCast(@backingInt(gop.value_ptr.*) + 1)); + gop.value_ptr.* = @fromBackingInt(@backingInt(gop.value_ptr.*) + 1); const unique_name = try wip_name.builder.fmt("{f}{s}{f}", .{ name.fmtRaw(wip_name.builder), sep, @@ -6460,7 +7261,7 @@ pub const WipFunction = struct { }); const unique_gop = try wip_name.next_unique_name.getOrPut(unique_name); if (!unique_gop.found_existing) { - unique_gop.value_ptr.* = @fromBackingInt(@intCast(0)); + unique_gop.value_ptr.* = @fromBackingInt(0); return unique_name; } } @@ -6702,7 +7503,7 @@ pub const WipFunction = struct { .fneg, .@"fneg fast", .ret, - => instruction.data = @backingInt(instructions.map(@fromBackingInt(@intCast(instruction.data)))), + => instruction.data = @backingInt(instructions.map(@fromBackingInt(instruction.data))), .getelementptr, .@"getelementptr inbounds", => { @@ -7079,7 +7880,7 @@ pub const WipFunction = struct { Type, Value, Instruction.BrCond.Weights, - => @fromBackingInt(@intCast(value)), + => @fromBackingInt(value), MemoryAccessInfo, Instruction.Alloca.Info, Instruction.Call.Info, @@ -7268,7 +8069,7 @@ pub const Constant = enum(u32) { no_init = (1 << 30) - 1, _, - const first_global: Constant = @fromBackingInt(@intCast(1 << 29)); + const first_global: Constant = @fromBackingInt(1 << 29); pub const Tag = enum(u7) { positive_integer, @@ -7405,7 +8206,18 @@ pub const Constant = enum(u32) { val: Constant, type: Type, - pub const Signedness = enum { unsigned, signed, unneeded }; + pub const Signedness = enum { + unsigned, + signed, + unneeded, + + pub fn fromStdLang(signedness: std.lang.Signedness) Signedness { + return switch (signedness) { + .unsigned => .unsigned, + .signed => .signed, + }; + } + }; }; pub const GetElementPtr = struct { @@ -7444,11 +8256,11 @@ pub const Constant = enum(u32) { return if (@backingInt(self) < @backingInt(first_global)) .{ .constant = @intCast(@backingInt(self)) } else - .{ .global = @fromBackingInt(@intCast(@backingInt(self) - @backingInt(first_global))) }; + .{ .global = @fromBackingInt(@backingInt(self) - @backingInt(first_global)) }; } pub fn toValue(self: Constant) Value { - return @fromBackingInt(@intCast(Value.first_constant + @backingInt(self))); + return @fromBackingInt(Value.first_constant + @backingInt(self)); } pub fn typeOf(self: Constant, builder: *Builder) Type { @@ -7474,7 +8286,7 @@ pub const Constant = enum(u32) { .zeroinitializer, .undef, .poison, - => @fromBackingInt(@intCast(item.data)), + => @fromBackingInt(item.data), .structure, .packed_structure, .array, @@ -7482,7 +8294,7 @@ pub const Constant = enum(u32) { => builder.constantExtraData(Aggregate, item.data).type, .splat => builder.constantExtraData(Splat, item.data).type, .string => builder.arrayTypeAssumeCapacity( - @as(String, @fromBackingInt(@intCast(item.data))).slice(builder).?.len, + @as(String, @fromBackingInt(item.data)).slice(builder).?.len, .i8, ), .blockaddress => builder.ptrTypeAssumeCapacity( @@ -7491,7 +8303,7 @@ pub const Constant = enum(u32) { ), .dso_local_equivalent, .no_cfi, - => builder.ptrTypeAssumeCapacity(@as(Function.Index, @fromBackingInt(@intCast(item.data))) + => builder.ptrTypeAssumeCapacity(@as(Function.Index, @fromBackingInt(item.data)) .ptrConst(builder).global.ptrConst(builder).addr_space), .trunc, .ptrtoint, @@ -7802,7 +8614,7 @@ pub const Constant = enum(u32) { try w.writeByte('>'); }, .string => try w.print("c{f}", .{ - @as(String, @fromBackingInt(@intCast(item.data))).fmtQ(data.builder), + @as(String, @fromBackingInt(item.data)).fmtQ(data.builder), }), .blockaddress => |tag| { const extra = data.builder.constantExtraData(BlockAddress, item.data); @@ -7816,7 +8628,7 @@ pub const Constant = enum(u32) { .dso_local_equivalent, .no_cfi, => |tag| { - const function: Function.Index = @fromBackingInt(@intCast(item.data)); + const function: Function.Index = @fromBackingInt(item.data); try w.print("{s} {f}", .{ @tagName(tag), function.ptrConst(data.builder).global.fmt(data.builder), @@ -7920,9 +8732,9 @@ pub const Value = enum(u32) { metadata: Metadata, } { return if (@backingInt(self) < first_constant) - .{ .instruction = @fromBackingInt(@intCast(@backingInt(self))) } + .{ .instruction = @fromBackingInt(@backingInt(self)) } else if (@backingInt(self) < first_metadata) - .{ .constant = @fromBackingInt(@intCast(@backingInt(self) - first_constant)) } + .{ .constant = @fromBackingInt(@backingInt(self) - first_constant) } else .{ .metadata = @bitCast(@backingInt(self) - first_metadata) }; } @@ -8016,7 +8828,7 @@ pub const Metadata = packed struct(u32) { return .{ .index = metadata.index, .kind = metadata.kind, .is_none = false }; } pub fn toValue(metadata: Metadata) Value { - return @fromBackingInt(@intCast(Value.first_metadata + @as(u32, @bitCast(metadata)))); + return @fromBackingInt(Value.first_metadata + @as(u32, @bitCast(metadata))); } pub const String = enum(u32) { @@ -8032,7 +8844,7 @@ pub const Metadata = packed struct(u32) { pub fn unwrap(metadata: Metadata.String.Optional) ?Metadata.String { return switch (metadata) { .none => null, - else => @fromBackingInt(@intCast(@backingInt(metadata))), + else => @fromBackingInt(@backingInt(metadata)), }; } pub fn toMetadata(metadata: Metadata.String.Optional) Metadata.Optional { @@ -8040,7 +8852,7 @@ pub const Metadata = packed struct(u32) { } }; pub fn toOptional(metadata: Metadata.String) Metadata.String.Optional { - return @fromBackingInt(@intCast(@backingInt(metadata))); + return @fromBackingInt(@backingInt(metadata)); } pub fn toMetadata(metadata: Metadata.String) Metadata { return .{ .index = @intCast(@backingInt(metadata)), .kind = .string }; @@ -8077,7 +8889,7 @@ pub const Metadata = packed struct(u32) { }; pub fn toString(metadata: Metadata) Metadata.String { assert(metadata.kind == .string); - return @fromBackingInt(@intCast(metadata.index)); + return @fromBackingInt(metadata.index); } pub const Tag = enum(u6) { @@ -8542,7 +9354,7 @@ pub const Metadata = packed struct(u32) { try w.writeByte(')'); }, .constant => try Constant.format(.{ - .constant = @fromBackingInt(@intCast(node_item.data)), + .constant = @fromBackingInt(node_item.data), .builder = builder, .flags = data.specialized orelse .{}, }, w), @@ -8705,7 +9517,7 @@ pub const Metadata = packed struct(u32) { nodes: anytype, w: *Writer, ) !void { - const names = comptime std.meta.fieldNames(@TypeOf(nodes)); + const names = @typeInfo(@TypeOf(nodes)).@"struct".field_names; comptime var fmt_str: []const u8 = "{[distinct]s}{[node]s}("; inline for (names) |name| fmt_str = fmt_str ++ "{[" ++ name ++ "]f}"; @@ -8735,7 +9547,14 @@ pub fn init(options: Options) Allocator.Error!Builder { .strip = options.strip, .source_filename = .none, - .data_layout = .none, + .data_layout = .{ + .endian = null, + .int_specs = .empty, + .float_specs = .empty, + .vector_specs = .empty, + .pointer_specs = .empty, + .string_repr = .none, + }, .target_triple = .none, .module_asm = .empty, @@ -8744,7 +9563,7 @@ pub fn init(options: Options) Allocator.Error!Builder { .string_bytes = .empty, .types = .empty, - .next_unnamed_type = @fromBackingInt(@intCast(0)), + .next_unnamed_type = @fromBackingInt(0), .next_unique_type_id = .empty, .type_map = .empty, .type_items = .empty, @@ -8758,7 +9577,7 @@ pub fn init(options: Options) Allocator.Error!Builder { .function_attributes_set = .empty, .globals = .empty, - .next_unnamed_global = @fromBackingInt(@intCast(0)), + .next_unnamed_global = @fromBackingInt(0), .next_replaced_global = .none, .next_unique_global_id = .empty, .aliases = .empty, @@ -8791,14 +9610,14 @@ pub fn init(options: Options) Allocator.Error!Builder { try self.string_indices.append(self.gpa, 0); assert(try self.string("") == .empty); + self.data_layout = try .parseString(try self.string(DataLayout.stringForTarget(options.target)), &self); + try self.strtab_string_indices.append(self.gpa, 0); assert(try self.strtabString("") == .empty); if (options.name.len > 0) self.source_filename = try self.string(options.name); - if (options.triple.len > 0) { - self.target_triple = try self.string(options.triple); - } + if (options.triple.len > 0) self.target_triple = try self.string(options.triple); { const static_len = @typeInfo(Type).@"enum".field_names.len - 1; @@ -8815,7 +9634,7 @@ pub fn init(options: Options) Allocator.Error!Builder { assert(self.intTypeAssumeCapacity(bits) == @field(Type, std.fmt.comptimePrint("i{d}", .{bits}))); inline for (.{ 0, 4 }) |addr_space_index| { - const addr_space: AddrSpace = @fromBackingInt(@intCast(addr_space_index)); + const addr_space: AddrSpace = @fromBackingInt(addr_space_index); assert(self.ptrTypeAssumeCapacity(addr_space) == @field(Type, std.fmt.comptimePrint("ptr{f}", .{addr_space.fmt(" ")}))); } @@ -8891,6 +9710,8 @@ pub fn clearAndFree(self: *Builder) void { pub fn deinit(self: *Builder) void { const gpa = self.gpa; + self.data_layout.deinit(gpa); + self.module_asm.deinit(gpa); self.string_map.deinit(gpa); @@ -8944,7 +9765,7 @@ pub fn deinit(self: *Builder) void { pub fn finishModuleAsm(self: *Builder, aw: *Writer.Allocating) Allocator.Error!void { self.module_asm = aw.toArrayList(); - if (self.module_asm.getLast()) |last| if (last != '\n') + if (self.module_asm.last()) |last| if (last != '\n') try self.module_asm.append(self.gpa, '\n'); } @@ -8990,7 +9811,7 @@ pub fn trailingString(self: *Builder) Allocator.Error!String { } pub fn trailingStringAssumeCapacity(self: *Builder) String { - const start = self.string_indices.getLast().?; + const start = self.string_indices.last().?; const bytes: []const u8 = self.string_bytes.items[start..]; const gop = self.string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self }); if (gop.found_existing) { @@ -9092,17 +9913,17 @@ pub fn attrs(self: *Builder, attributes: []Attribute.Index) Allocator.Error!Attr return @backingInt(lhs_kind) < @backingInt(rhs_kind); } }.lessThan); - return @fromBackingInt(@intCast(try self.attrGeneric(@ptrCast(attributes)))); + return @fromBackingInt(try self.attrGeneric(@ptrCast(attributes))); } pub fn fnAttrs(self: *Builder, fn_attributes: []const Attributes) Allocator.Error!FunctionAttributes { try self.function_attributes_set.ensureUnusedCapacity(self.gpa, 1); - const function_attributes: FunctionAttributes = @fromBackingInt(@intCast(try self.attrGeneric(@ptrCast( - fn_attributes[0..if (std.mem.lastIndexOfNone(Attributes, fn_attributes, &.{.none})) |last| + const function_attributes: FunctionAttributes = @fromBackingInt(try self.attrGeneric(@ptrCast( + fn_attributes[0..if (std.mem.findLastNone(Attributes, fn_attributes, &.{.none})) |last| last + 1 else 0], - )))); + ))); _ = self.function_attributes_set.getOrPutAssumeCapacity(function_attributes); return function_attributes; @@ -9121,7 +9942,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: StrtabString, global: Globa if (name == .empty) { id = self.next_unnamed_global; assert(id != self.next_replaced_global); - self.next_unnamed_global = @fromBackingInt(@intCast(@backingInt(id) + 1)); + self.next_unnamed_global = @fromBackingInt(@backingInt(id) + 1); } while (true) { const global_gop = self.globals.getOrPutAssumeCapacity(id); @@ -9710,17 +10531,17 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void var metadata_formatter: Metadata.Formatter = .{ .builder = self, .need_comma = undefined }; defer metadata_formatter.map.deinit(self.gpa); - if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) { + if (self.source_filename != .none or self.data_layout.string_repr != .none or self.target_triple != .none) { if (need_newline) try w.writeByte('\n') else need_newline = true; if (self.source_filename != .none) try w.print( \\; ModuleID = '{s}' \\source_filename = {f} \\ , .{ self.source_filename.slice(self).?, self.source_filename.fmtQ(self) }); - if (self.data_layout != .none) try w.print( + if (self.data_layout.string_repr != .none) try w.print( \\target datalayout = {f} \\ - , .{self.data_layout.fmtQ(self)}); + , .{self.data_layout.string_repr.fmtQ(self)}); if (self.target_triple != .none) try w.print( \\target triple = {f} \\ @@ -10058,7 +10879,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void continue; }, .br => |tag| { - const target: Function.Block.Index = @fromBackingInt(@intCast(instruction.data)); + const target: Function.Block.Index = @fromBackingInt(instruction.data); try w.print(" {s} {f}", .{ @tagName(tag), target.toInst(&function).fmt(function_index, self, .{ .percent = true }), }); @@ -10187,7 +11008,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void .fneg, .@"fneg fast", => |tag| { - const val: Value = @fromBackingInt(@intCast(instruction.data)); + const val: Value = @fromBackingInt(instruction.data); try w.print(" %{f} = {s} {f}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), @@ -10288,7 +11109,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void } }, .ret => |tag| { - const val: Value = @fromBackingInt(@intCast(instruction.data)); + const val: Value = @fromBackingInt(instruction.data); try w.print(" {s} {f}", .{ @tagName(tag), val.fmt(function_index, self, .{ .percent = true }), @@ -11020,7 +11841,7 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type { if (name == .empty) { id = self.next_unnamed_type; assert(id != .none); - self.next_unnamed_type = @fromBackingInt(@intCast(@backingInt(id) + 1)); + self.next_unnamed_type = @fromBackingInt(@backingInt(id) + 1); } else assert(!name.isAnon()); while (true) { const type_gop = self.types.getOrPutAssumeCapacity(id); @@ -11135,7 +11956,7 @@ fn typeExtraDataTrail( ) |field_name, field_type, value| @field(result, field_name) = switch (field_type) { u32 => value, - String, Type => @fromBackingInt(@intCast(value)), + String, Type => @fromBackingInt(value), else => @compileError("bad field type: " ++ @typeName(field_type)), }; return .{ @@ -11746,7 +12567,7 @@ fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, val: Constant, ty: return std.meta.eql(lhs_key.cast, rhs_extra); } }; - const data = Key{ .tag = tag, .cast = .{ .val = val, .type = ty } }; + const data: Key = .{ .tag = tag, .cast = .{ .val = val, .type = ty } }; const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); if (!gop.found_existing) { gop.key_ptr.* = {}; @@ -11828,10 +12649,10 @@ fn gepConstAssumeCapacity( std.mem.eql(Constant, lhs_key.indices, rhs_indices); } }; - const data = Key{ + const data: Key = .{ .type = ty, .base = base, - .inrange = if (inrange) |index| @fromBackingInt(@intCast(index)) else .none, + .inrange = if (inrange) |index| @fromBackingInt(index) else .none, .indices = indices, }; const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); @@ -11885,7 +12706,7 @@ fn binConstAssumeCapacity( return std.meta.eql(lhs_key.extra, rhs_extra); } }; - const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } }; + const data: Key = .{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } }; const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); if (!gop.found_existing) { gop.key_ptr.* = {}; @@ -11924,8 +12745,8 @@ fn asmConstAssumeCapacity( } }; - const data = Key{ - .tag = @fromBackingInt(@intCast(@backingInt(Constant.Tag.@"asm") + @as(u4, @bitCast(info)))), + const data: Key = .{ + .tag = @fromBackingInt(@backingInt(Constant.Tag.@"asm") + @as(u4, @bitCast(info))), .extra = .{ .type = ty, .assembly = assembly, .constraints = constraints }, }; const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); @@ -12073,7 +12894,7 @@ fn constantExtraDataTrail( ) |field_name, field_type, value| @field(result, field_name) = switch (field_type) { u32 => value, - String, Type, Constant, Function.Index, Function.Block.Index => @fromBackingInt(@intCast(value)), + String, Type, Constant, Function.Index, Function.Block.Index => @fromBackingInt(value), Constant.GetElementPtr.Info => @bitCast(value), else => @compileError("bad field type: " ++ @typeName(field_type)), }; @@ -12151,7 +12972,7 @@ fn metadataExtraDataTrail( ) |field_name, field_type, value| @field(result, field_name) = switch (field_type) { u32 => value, - Metadata.String, Metadata.String.Optional, Variable.Index, Value => @fromBackingInt(@intCast(value)), + Metadata.String, Metadata.String.Optional, Variable.Index, Value => @fromBackingInt(value), Metadata, Metadata.Optional, Metadata.DIFlags => @bitCast(value), else => @compileError("bad field type: " ++ @typeName(field_type)), }; @@ -12221,7 +13042,7 @@ pub fn trailingMetadataString(self: *Builder) Allocator.Error!Metadata.String { } pub fn trailingMetadataStringAssumeCapacity(self: *Builder) Metadata.String { - const start = self.metadata_string_indices.getLast().?; + const start = self.metadata_string_indices.last().?; const bytes: []const u8 = self.metadata_string_bytes.items[start..]; assert(bytes.len > 0); const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(bytes, Metadata.String.Adapter{ .builder = self }); @@ -12663,7 +13484,7 @@ fn metadataSimpleAssumeCapacity(self: *Builder, tag: Metadata.Tag, value: anytyp builder: *const Builder, pub fn hash(_: @This(), key: Key) u32 { var hasher = std.hash.Wyhash.init(std.hash.int(@backingInt(key.tag))); - inline for (comptime std.meta.fieldNames(@TypeOf(value))) |field_name| { + inline for (@typeInfo(@TypeOf(value)).@"struct".field_names) |field_name| { hasher.update(std.mem.asBytes(&@field(key.value, field_name))); } return @truncate(hasher.final()); @@ -12759,8 +13580,8 @@ fn debugSubprogramAssumeCapacity( compile_unit: ?Metadata, ) Metadata { assert(!self.strip); - const tag: Metadata.Tag = @fromBackingInt(@intCast(@backingInt(Metadata.Tag.subprogram) + - @as(u3, @truncate(@as(u32, @bitCast(options.sp_flags)) >> 2)))); + const tag: Metadata.Tag = @fromBackingInt(@backingInt(Metadata.Tag.subprogram) + + @as(u3, @truncate(@as(u32, @bitCast(options.sp_flags)) >> 2))); return self.metadataDistinctAssumeCapacity(tag, Metadata.Subprogram{ .file = .wrap(file), .name = .wrap(name), @@ -13345,7 +14166,7 @@ fn metadataConstantAssumeCapacity(self: *Builder, constant: Constant) Metadata { pub fn eql(ctx: @This(), lhs_key: Constant, _: void, rhs_index: usize) bool { if (Metadata.Tag.constant != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false; - const rhs_data: Constant = @fromBackingInt(@intCast(ctx.builder.metadata_items.items(.data)[rhs_index])); + const rhs_data: Constant = @fromBackingInt(ctx.builder.metadata_items.items(.data)[rhs_index]); return rhs_data == lhs_key; } }; @@ -13418,7 +14239,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco }); } - if (self.data_layout.slice(self)) |data_layout| { + if (self.data_layout.string_repr.slice(self)) |data_layout| { try module_block.writeAbbrev(ModuleBlock.String{ .code = 3, .string = data_layout, @@ -13577,6 +14398,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco switch (attr_index.toAttribute(self)) { .zeroext, .signext, + .noext, .inreg, .@"noalias", .nocapture, @@ -13594,11 +14416,13 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .readnone, .readonly, .writeonly, + .writable, + .dead_on_unwind, .alwaysinline, .builtin, .cold, .convergent, - .disable_sanitizer_information, + .disable_sanitizer_instrumentation, .fn_ret_thunk_extern, .hot, .inlinehint, @@ -13607,6 +14431,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .naked, .nobuiltin, .nocallback, + .nodivergencesource, .noduplicate, .noimplicitfloat, .@"noinline", @@ -13623,6 +14448,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .nosanitize_bounds, .nosanitize_coverage, .null_pointer_is_valid, + .optdebug, .optforfuzzing, .optnone, .optsize, @@ -13633,18 +14459,21 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .sanitize_thread, .sanitize_hwaddress, .sanitize_memtag, + .sanitize_realtime, + .sanitize_realtime_blocking, + .sanitize_alloc_token, .speculative_load_hardening, .speculatable, .ssp, .sspstrong, .sspreq, .strictfp, + .denormal_fpenv, .nocf_check, .shadowcallstack, .mustprogress, - .no_sanitize_address, - .no_sanitize_hwaddress, - .sanitize_address_dyninit, + .nooutline, + .nocreateundeforpoison, => { try record.ensureUnusedCapacity(self.gpa, 2); record.appendAssumeCapacity(0); @@ -13670,6 +14499,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco record.appendAssumeCapacity(@backingInt(kind)); record.appendAssumeCapacity(alignment.resolve(self).toByteUnits() orelse 0); }, + .captures => |captures| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@backingInt(kind)); + record.appendAssumeCapacity(@as(u32, @bitCast(captures))); + }, .dereferenceable, .dereferenceable_or_null, => |size| { @@ -13684,6 +14519,9 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco record.appendAssumeCapacity(@backingInt(kind)); record.appendAssumeCapacity(@as(u32, @bitCast(fpclass))); }, + .initializes => @panic("TODO"), + .dead_on_return => @panic("TODO"), + .range => @panic("TODO"), .allockind => |allockind| { try record.ensureUnusedCapacity(self.gpa, 3); record.appendAssumeCapacity(1); @@ -13955,8 +14793,11 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco } const strtab = alias.global.strtab(self); - const global = alias.global.ptrConst(self); + + // LLVM requires the types to match + assert(global.addr_space == alias.aliasee.typeOf(self).pointerAddrSpace(self)); + try module_block.writeAbbrev(ModuleBlock.Alias{ .strtab_offset = strtab.offset, .strtab_size = strtab.size, @@ -14096,7 +14937,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco } }, .string => { - const str: String = @fromBackingInt(@intCast(data)); + const str: String = @fromBackingInt(data); if (str == .none) { try constants_block.writeAbbrev(ConstantsBlock.Null{}); } else { @@ -14223,7 +15064,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .dso_local_equivalent, .no_cfi, => |tag| { - const function: Function.Index = @fromBackingInt(@intCast(data)); + const function: Function.Index = @fromBackingInt(data); try constants_block.writeAbbrev(ConstantsBlock.DsoLocalEquivalentOrNoCfi{ .code = switch (tag) { .dso_local_equivalent => .DSO_LOCAL_EQUIVALENT, @@ -14606,7 +15447,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco }, metadata_adapter); }, .constant => { - const constant: Constant = @fromBackingInt(@intCast(data)); + const constant: Constant = @fromBackingInt(data); try metadata_block.writeAbbrevAdapted(MetadataBlock.Constant{ .ty = constant.typeOf(self), .constant = constant, @@ -14775,7 +15616,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco var adapter: FunctionAdapter = .{ .metadata_adapter = metadata_adapter, .func = &func, - .instruction_index = @fromBackingInt(@intCast(0)), + .instruction_index = @fromBackingInt(0), }; // Emit function level metadata block @@ -14786,7 +15627,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco for (func.debug_values) |value| { try metadata_block.writeAbbrev(MetadataBlock.Value{ .ty = value.typeOf(@fromBackingInt(@intCast(func_index)), self), - .value = @fromBackingInt(@intCast(adapter.getValueIndex(value.toValue()))), + .value = @fromBackingInt(adapter.getValueIndex(value.toValue())), }); } @@ -15068,10 +15909,10 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco }); }, .fneg => try function_block.writeAbbrev(FunctionBlock.FNeg{ - .val = adapter.getOffsetValueIndex(@fromBackingInt(@intCast(data))), + .val = adapter.getOffsetValueIndex(@fromBackingInt(data)), }), .@"fneg fast" => try function_block.writeAbbrev(FunctionBlock.FNegFast{ - .val = adapter.getOffsetValueIndex(@fromBackingInt(@intCast(data))), + .val = adapter.getOffsetValueIndex(@fromBackingInt(data)), .fast_math = FastMath.fast, }), .extractvalue => { @@ -15271,7 +16112,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco try function_block.writeUnabbrev(16, record.items); }, .ret => try function_block.writeAbbrev(FunctionBlock.Ret{ - .val = adapter.getOffsetValueIndex(@fromBackingInt(@intCast(data))), + .val = adapter.getOffsetValueIndex(@fromBackingInt(data)), }), .@"ret void" => try function_block.writeAbbrev(FunctionBlock.RetVoid{}), .atomicrmw => { diff --git a/lib/std/zig/llvm/bitcode_writer.zig b/lib/std/zig/llvm/bitcode_writer.zig index 98c8489172ee3960ab4502bd9ccbb360ed519735..0ee722165be0a39a2695d4f23f249c6e2a8299f0 100644 --- a/lib/std/zig/llvm/bitcode_writer.zig +++ b/lib/std/zig/llvm/bitcode_writer.zig @@ -246,7 +246,7 @@ pub fn BitcodeWriter(comptime types: []const type) type { try self.bitcode.writeBits(comptime abbrevId(Abbrev), abbrev_len); - const field_names = comptime std.meta.fieldNames(Abbrev); + const field_names = @typeInfo(Abbrev).@"struct".field_names; // This abbreviation might only contain literals if (field_names.len == 0) return; diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 060fd1d97643beac4e5724a12ea26427e7500a31..1baa6e8cad8a996b1705219bd5a25d514ce8090f 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -597,23 +597,23 @@ fn abiAndDynamicLinkerFromFile( .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch), .dynamic_linker = query.dynamic_linker orelse .none, }; - var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC + var rpath_offset: ?u64 = null; // Found inside PT.DYNAMIC const look_for_ld = query.dynamic_linker == null; var got_dyn_section: bool = false; { var it = header.iterateProgramHeaders(file_reader); - while (try it.next()) |phdr| switch (phdr.p_type) { - elf.PT_INTERP => { + while (try it.next()) |phdr| switch (phdr.type) { + .INTERP => { got_dyn_section = true; if (look_for_ld) { - const p_filesz = phdr.p_filesz; + const p_filesz = phdr.filesz; if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; const filesz: usize = @intCast(p_filesz); - try file_reader.seekTo(phdr.p_offset); + try file_reader.seekTo(phdr.offset); try file_reader.interface.readSliceAll(result.dynamic_linker.buffer[0..filesz]); - // PT_INTERP includes a null byte in filesz. + // PT.INTERP includes a null byte in filesz. const len = filesz - 1; // dynamic_linker.max_byte is "max", not "len". // We know it will fit in u8 because we check against dynamic_linker.buffer.len above. @@ -631,11 +631,11 @@ fn abiAndDynamicLinkerFromFile( } }, // We only need this for detecting glibc version. - elf.PT_DYNAMIC => { + .DYNAMIC => { got_dyn_section = true; if (builtin.target.os.tag == .linux and result.isGnuLibC() and query.glibc_version == null) { - var dyn_it = header.iterateDynamicSection(file_reader, phdr.p_offset, phdr.p_filesz); + var dyn_it = header.iterateDynamicSection(file_reader, phdr.offset, phdr.filesz); while (try dyn_it.next()) |dyn| { if (dyn.d_tag == elf.DT_RUNPATH) { rpath_offset = dyn.d_val; @@ -973,7 +973,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ // relying on `builtin.target`. const all_abis = comptime blk: { assert(@backingInt(Target.Abi.none) == 0); - const field_names = std.meta.fieldNames(Target.Abi)[1..]; + const field_names = @typeInfo(Target.Abi).@"enum".field_names[1..]; var array: [field_names.len]Target.Abi = undefined; for (field_names, 0..) |field_name, i| { array[i] = @field(Target.Abi, field_name); diff --git a/lib/std/zig/target.zig b/lib/std/zig/target.zig index 0ac83c50dc57047ff1a937182b717960b14e8f82..6e7eb636d3bc30cd40e402d3490ef4a5f438e219 100644 --- a/lib/std/zig/target.zig +++ b/lib/std/zig/target.zig @@ -46,6 +46,8 @@ pub const available_libcs = [_]ArchOsAbi{ .{ .arch = .csky, .os = .linux, .abi = .gnueabi, .os_ver = .{ .major = 4, .minor = 20, .patch = 0 }, .glibc_min = .{ .major = 2, .minor = 29, .patch = 0 }, .glibc_triple = "csky-linux-gnuabiv2-soft" }, .{ .arch = .csky, .os = .linux, .abi = .gnueabihf, .os_ver = .{ .major = 4, .minor = 20, .patch = 0 }, .glibc_min = .{ .major = 2, .minor = 29, .patch = 0 }, .glibc_triple = "csky-linux-gnuabiv2" }, .{ .arch = .hexagon, .os = .linux, .abi = .musl, .os_ver = .{ .major = 3, .minor = 2, .patch = 102 } }, + .{ .arch = .loongarch32, .os = .linux, .abi = .gnu, .os_ver = .{ .major = 6, .minor = 19, .patch = 0 }, .glibc_min = .{ .major = 2, .minor = 44, .patch = 0 }, .glibc_triple = "loongarch32-linux-gnuf64" }, + .{ .arch = .loongarch32, .os = .linux, .abi = .gnusf, .os_ver = .{ .major = 6, .minor = 19, .patch = 0 }, .glibc_min = .{ .major = 2, .minor = 44, .patch = 0 }, .glibc_triple = "loongarch32-linux-gnusf" }, .{ .arch = .loongarch64, .os = .linux, .abi = .gnu, .os_ver = .{ .major = 5, .minor = 19, .patch = 0 }, .glibc_min = .{ .major = 2, .minor = 36, .patch = 0 }, .glibc_triple = "loongarch64-linux-gnuf64" }, .{ .arch = .loongarch64, .os = .linux, .abi = .gnusf, .os_ver = .{ .major = 5, .minor = 19, .patch = 0 }, .glibc_min = .{ .major = 2, .minor = 36, .patch = 0 }, .glibc_triple = "loongarch64-linux-gnusf" }, .{ .arch = .loongarch64, .os = .linux, .abi = .musl, .os_ver = .{ .major = 5, .minor = 19, .patch = 0 } }, @@ -499,34 +501,32 @@ pub fn intByteSize(target: *const std.Target, bits: u16) u16 { } pub fn intAlignment(target: *const std.Target, bits: u16) u16 { - return switch (target.cpu.arch) { - .x86 => switch (bits) { - 0...8 => 1, - 9...16 => 2, - 17...32 => 4, - 33...64 => switch (target.os.tag) { - .uefi, .windows => 8, - else => 4, - }, - else => 16, - }, - .x86_64 => switch (bits) { - 0...8 => 1, - 9...16 => 2, - 17...32 => 4, - 33...64 => 8, - else => 16, - }, - else => switch (bits) { - 0 => 1, - else => @min( - std.math.ceilPowerOfTwoPromote(u16, @intCast((@as(u17, bits) + 7) / 8)), - target.cMaxIntAlignment(), - ), - }, + return switch (bits) { + 0 => 1, + else => @min( + std.math.ceilPowerOfTwoPromote(u16, @intCast((@as(u17, bits) + 7) / 8)), + target.cMaxIntAlignment(), + ), }; } +pub fn compilerRtFloatAbi(target: *const std.Target, bits: u16) std.Target.Abi.Float { + if (target.cpu.has(.x86, .soft_float)) return .soft; + // Marks targets where clang does not even provide a usable C type. + const no_c_type_available = .soft; + switch (bits) { + else => unreachable, + 16 => if (target.cpu.arch.isMIPS() or target.cpu.arch.isPowerPC()) return no_c_type_available, + 32, 64 => {}, + 80 => if (target.cTypeBitSize(.longdouble) != 80) return no_c_type_available, + 128 => { + if (target.cpu.arch.isX86()) return .hard; // if (target.abi == .msvc) __m128i else __float128 + if (target.cTypeBitSize(.longdouble) != 128) return no_c_type_available; + }, + } + return .hard; +} + const std = @import("std"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; diff --git a/lib/std/zip.zig b/lib/std/zip.zig index a42a9f395c694c7df04d78e7ca63baafae3b6cfd..1434702ffbf62f3db7fd1b0c133d1af501365133 100644 --- a/lib/std/zip.zig +++ b/lib/std/zip.zig @@ -109,7 +109,7 @@ pub const EndRecord = extern struct { /// TODO audit this logic pub fn findBuffer(buffer: []const u8) FindBufferError!EndRecord { - const pos = std.mem.lastIndexOf(u8, buffer, &end_record_sig) orelse return error.ZipNoEndRecord; + const pos = std.mem.findLast(u8, buffer, &end_record_sig) orelse return error.ZipNoEndRecord; if (pos + @sizeOf(EndRecord) > buffer.len) return error.EndOfStream; const record_ptr: *EndRecord = @ptrCast(buffer[pos..][0..@sizeOf(EndRecord)]); var record = record_ptr.*; diff --git a/lib/std/zon.zig b/lib/std/zon.zig index 969e0c8c761607a84871e2b443aed80ff6c83ff8..7a979beaad4f7a2c5c49e854dd7f17048b76ce48 100644 --- a/lib/std/zon.zig +++ b/lib/std/zon.zig @@ -37,10 +37,51 @@ //! ZON does not have syntax for pointers, but the parsers will allocate as needed to match the //! given Zig types. Similarly, the serializer will traverse pointers. +const std = @import("std"); + pub const parse = @import("zon/parse.zig"); pub const stringify = @import("zon/stringify.zig"); pub const Serializer = @import("zon/Serializer.zig"); +/// Returns a formatter that formats the given value using stringify. +pub fn fmt(value: anytype, options: stringify.SerializeOptions) Formatter(@TypeOf(value)) { + return Formatter(@TypeOf(value)){ .value = value, .options = options }; +} + +test fmt { + const expectFmt = std.testing.expectFmt; + try expectFmt("123", "{f}", .{fmt(@as(u32, 123), .{})}); + try expectFmt( + \\.{ + \\ .num = 927, + \\ .msg = "hello", + \\ .sub = .{ .mybool = true }, + \\} + , "{f}", .{fmt(struct { + num: u32, + msg: []const u8, + sub: struct { + mybool: bool, + }, + }{ + .num = 927, + .msg = "hello", + .sub = .{ .mybool = true }, + }, .{})}); +} + +/// Formats the given value using stringify. +pub fn Formatter(comptime T: type) type { + return struct { + value: T, + options: stringify.SerializeOptions, + + pub fn format(self: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { + try stringify.serialize(self.value, self.options, writer); + } + }; +} + test { _ = parse; _ = stringify; diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index b22de08eacccf9c75e24a6f32e85ce7d795e12a8..16294f3df6d763df2587b48fbb99e3b6615d478f 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -9,7 +9,6 @@ //! For lower level control over parsing, see `std.zig.Zoir`. const std = @import("std"); -const builtin = @import("builtin"); const Allocator = std.mem.Allocator; const Ast = std.zig.Ast; const Zoir = std.zig.Zoir; @@ -1868,8 +1867,6 @@ test "std.zon tuples" { // Test sizes 0 to 3 since small sizes get parsed differently test "std.zon arrays and slices" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/20881 - const gpa = std.testing.allocator; // Literals @@ -2802,8 +2799,6 @@ test "std.zon negative char" { } test "std.zon parse float" { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - const gpa = std.testing.allocator; // Test decimals @@ -3135,7 +3130,7 @@ test "std.zon free on error" { } test "std.zon vector" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/15330 + const builtin = @import("builtin"); if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .s390x) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/25957 const gpa = std.testing.allocator; diff --git a/lib/std/zon/stringify.zig b/lib/std/zon/stringify.zig index 57b62d41cac6c3f9aa0e442bd276edb33f2679c2..a1c6b39ebe25a350d08eba57008fbd3522c16f76 100644 --- a/lib/std/zon/stringify.zig +++ b/lib/std/zon/stringify.zig @@ -1151,9 +1151,6 @@ test "std.zon depth limits" { } test "std.zon stringify primitives" { - // Issue: https://github.com/ziglang/zig/issues/20880 - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; - try expectSerializeEqual( \\.{ \\ .a = 1.5, diff --git a/lib/zig.h b/lib/zig.h index fbc924ca334e99eb12d2f37e3ebffa970ced7b9d..30e6f3f96a97f47b6648db1d1587bc75c88b6c3f 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -166,6 +166,12 @@ #endif #define zig_expand_has_builtin(b) zig_has_builtin(b) +#if defined(__has_feature) +#define zig_has_feature(feature) __has_feature(feature) +#else +#define zig_has_feature(feature) 0 +#endif + #if defined(__has_attribute) #define zig_has_attribute(attribute) __has_attribute(attribute) #else @@ -175,9 +181,9 @@ #if __STDC_VERSION__ >= 201112L #define zig_static_assert(cond, msg) _Static_assert(cond, msg) #elif zig_has_attribute(unused) -#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] __attribute__((unused)) +#define zig_static_assert(cond, msg) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[(cond) ? 1 : -1] __attribute__((unused)) #else -#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] +#define zig_static_assert(cond, msg) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[(cond) ? 1 : -1] #endif #if __STDC_VERSION__ >= 202311L @@ -193,10 +199,8 @@ #endif #if defined(zig_msvc) -#define zig_const_arr #define zig_callconv(c) __##c #else -#define zig_const_arr static const #define zig_callconv(c) __attribute__((c)) #endif @@ -267,12 +271,20 @@ #if __STDC_VERSION__ >= 202311L #define zig_align(alignment) alignas(alignment) -#elif __STDC_VERSION__ >= 201112L +#elif __STDC_VERSION__ >= 201112L || zig_has_feature(c_alignas) #define zig_align(alignment) _Alignas(alignment) #else #define zig_align(alignment) zig_under_align(alignment) #endif +#if __STDC_VERSION__ >= 202311L +#define zig_alignOf(Type) alignof(Type) +#elif __STDC_VERSION__ >= 201112L || zig_has_feature(c_alignof) +#define zig_alignOf(Type) _Alignof(Type) +#else +#define zig_alignOf(Type) (sizeof(struct { char c; Type t; }) - sizeof(Type)) +#endif + #if zig_has_attribute(aligned) || defined(zig_tinyc) #define zig_align_fn(alignment) __attribute__((aligned(alignment))) #elif defined(zig_msvc) @@ -350,11 +362,9 @@ #define zig_export(symbol, name) __attribute__((alias(symbol))) #else #define zig_export(symbol, name) ; \ - __asm(zig_mangle_c(name) " = " zig_mangle_c(symbol)) + __asm("\t.globl\t" zig_mangle_c(name) "\n" zig_mangle_c(name) " = " zig_mangle_c(symbol)) #endif -#define zig_mangled_tentative zig_mangled -#define zig_mangled_final zig_mangled #if defined(zig_msvc) #define zig_mangled(mangled, unmangled) ; \ zig_export(#mangled, unmangled) @@ -364,7 +374,7 @@ #else /* zig_msvc */ #define zig_mangled(mangled, unmangled) __asm(zig_mangle_c(unmangled)) #define zig_mangled_export(mangled, unmangled, symbol) \ - zig_mangled_final(mangled, unmangled) \ + zig_mangled(mangled, unmangled) \ zig_export(symbol, unmangled) #endif /* zig_msvc */ @@ -550,6 +560,9 @@ #define zig_noreturn #endif +#define zig_has_always 1 +#define zig_has_never 0 + #define zig_compiler_rt_abbrev_uint32_t si #define zig_compiler_rt_abbrev_int32_t si #define zig_compiler_rt_abbrev_uint64_t di @@ -560,7 +573,11 @@ #define zig_compiler_rt_abbrev_zig_f32 sf #define zig_compiler_rt_abbrev_zig_f64 df #define zig_compiler_rt_abbrev_zig_f80 xf +#ifdef zig_powerpc +#define zig_compiler_rt_abbrev_zig_f128 kf +#else #define zig_compiler_rt_abbrev_zig_f128 tf +#endif zig_extern void *memcpy (void *zig_restrict, void const *zig_restrict, size_t); zig_extern void *memset (void *, int, size_t); @@ -645,16 +662,6 @@ typedef signed long long int16_t; #define INT16_MAX ( INT16_C(0x7FFF)) #define UINT16_MAX ( INT16_C(0xFFFF)) -#if defined(zig_ez80) -typedef unsigned int uint24_t; -typedef signed int int24_t; -#define INT24_C(c) c -#define UINT24_C(c) c##U -#endif -#define INT24_MIN (~INT24_C(0x7FFF)) -#define INT24_MAX ( INT24_C(0x7FFF)) -#define UINT24_MAX ( INT24_C(0xFFFF)) - #if SCHAR_MIN == ~0x7FFFFFFF && SCHAR_MAX == 0x7FFFFFFF && UCHAR_MAX == 0xFFFFFFFF typedef unsigned char uint32_t; typedef signed char int32_t; @@ -685,17 +692,6 @@ typedef signed long long int32_t; #define INT32_MAX ( INT32_C(0x7FFFFFFF)) #define UINT32_MAX ( INT32_C(0xFFFFFFFF)) -#if defined(zig_ez80) -typedef unsigned __int48 uint48_t; -typedef signed __int48 int48_t; -#define INT48_C(c) c -/* no suffix */ -#define UINT48_C(c) ((uint48_t)(c)) -#endif -#define INT48_MIN (~INT48_C(0x7FFFFFFFFFFF)) -#define INT48_MAX ( INT48_C(0x7FFFFFFFFFFF)) -#define UINT48_MAX ( INT48_C(0xFFFFFFFFFFFF)) - #if SCHAR_MIN == ~0x7FFFFFFFFFFFFFFF && SCHAR_MAX == 0x7FFFFFFFFFFFFFFF && UCHAR_MAX == 0xFFFFFFFFFFFFFFFF typedef unsigned char uint64_t; typedef signed char int64_t; @@ -726,6 +722,27 @@ typedef signed long long int64_t; #define INT64_MAX ( INT64_C(0x7FFFFFFFFFFFFFFF)) #define UINT64_MAX ( INT64_C(0xFFFFFFFFFFFFFFFF)) +#if defined(zig_ez80) + +typedef unsigned int uint24_t; +typedef signed int int24_t; +#define INT24_C(c) c +#define UINT24_C(c) c##U +#define INT24_MIN (~INT24_C(0x7FFF)) +#define INT24_MAX ( INT24_C(0x7FFF)) +#define UINT24_MAX ( INT24_C(0xFFFF)) + +typedef unsigned __int48 uint48_t; +typedef signed __int48 int48_t; +#define INT48_C(c) c +/* no suffix */ +#define UINT48_C(c) ((uint48_t)(c)) +#define INT48_MIN (~INT48_C(0x7FFFFFFFFFFF)) +#define INT48_MAX ( INT48_C(0x7FFFFFFFFFFF)) +#define UINT48_MAX ( INT48_C(0xFFFFFFFFFFFF)) + +#endif + typedef size_t uintptr_t; typedef ptrdiff_t intptr_t; @@ -739,23 +756,145 @@ typedef ptrdiff_t intptr_t; #define zig_maxInt_i16 INT16_MAX #define zig_minInt_u16 UINT16_C(0) #define zig_maxInt_u16 UINT16_MAX -#define zig_minInt_i24 INT24_MIN -#define zig_maxInt_i24 INT24_MAX -#define zig_minInt_u24 UINT24_C(0) -#define zig_maxInt_u24 UINT24_MAX #define zig_minInt_i32 INT32_MIN #define zig_maxInt_i32 INT32_MAX #define zig_minInt_u32 UINT32_C(0) #define zig_maxInt_u32 UINT32_MAX -#define zig_minInt_i48 INT48_MIN -#define zig_maxInt_i48 INT48_MAX -#define zig_minInt_u48 UINT48_C(0) -#define zig_maxInt_u48 UINT48_MAX #define zig_minInt_i64 INT64_MIN #define zig_maxInt_i64 INT64_MAX #define zig_minInt_u64 UINT64_C(0) #define zig_maxInt_u64 UINT64_MAX +// zig_promoted_T implements C integral promotions except with signedness preserved, which +// allows wrapping operations to avoid the ub that would be caused by the normal promotion. + +#if INT8_MAX <= INT_MAX +typedef unsigned int zig_promoted_i8; +#elif INT8_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i8; +#elif INT8_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i8; +#else +typedef int8_t zig_promoted_i8; +#endif +#if UINT8_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u8; +#elif UINT8_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u8; +#elif UINT8_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u8; +#else +typedef uint8_t zig_promoted_u8; +#endif + +#if INT16_MAX <= INT_MAX +typedef unsigned int zig_promoted_i16; +#elif INT16_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i16; +#elif INT16_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i16; +#else +typedef int16_t zig_promoted_i16; +#endif +#if UINT16_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u16; +#elif UINT16_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u16; +#elif UINT16_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u16; +#else +typedef uint16_t zig_promoted_u16; +#endif + +#if INT32_MAX <= INT_MAX +typedef unsigned int zig_promoted_i32; +#elif INT32_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i32; +#elif INT32_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i32; +#else +typedef int32_t zig_promoted_i32; +#endif +#if UINT32_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u32; +#elif UINT32_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u32; +#elif UINT32_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u32; +#else +typedef uint32_t zig_promoted_u32; +#endif + +#if INT64_MAX <= INT_MAX +typedef unsigned int zig_promoted_i64; +#elif INT64_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i64; +#elif INT64_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i64; +#else +typedef int64_t zig_promoted_i64; +#endif +#if UINT64_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u64; +#elif UINT64_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u64; +#elif UINT64_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u64; +#else +typedef uint64_t zig_promoted_u64; +#endif + +#ifdef zig_ez80 + +#define zig_minInt_i24 INT24_MIN +#define zig_maxInt_i24 INT24_MAX +#define zig_minInt_u24 UINT24_C(0) +#define zig_maxInt_u24 UINT24_MAX +#define zig_minInt_i48 INT48_MIN +#define zig_maxInt_i48 INT48_MAX +#define zig_minInt_u48 UINT48_C(0) +#define zig_maxInt_u48 UINT48_MAX + +#if INT24_MAX <= INT_MAX +typedef unsigned int zig_promoted_i24; +#elif INT24_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i24; +#elif INT24_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i24; +#else +typedef int24_t zig_promoted_i24; +#endif +#if UINT24_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u24; +#elif UINT24_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u24; +#elif UINT24_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u24; +#else +typedef uint24_t zig_promoted_u24; +#endif + +#if INT48_MAX <= INT_MAX +typedef unsigned int zig_promoted_i48; +#elif INT48_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i48; +#elif INT48_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i48; +#else +typedef int48_t zig_promoted_i48; +#endif +#if UINT48_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u48; +#elif UINT48_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u48; +#elif UINT48_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u48; +#else +typedef uint48_t zig_promoted_u48; +#endif + +#endif + #define zig_intLimit(s, w, limit, bits) zig_shr_##s##w(zig_##limit##Int_##s##w, w - (bits)) #define zig_minInt_i(w, bits) zig_intLimit(i, w, min, bits) #define zig_maxInt_i(w, bits) zig_intLimit(i, w, max, bits) @@ -770,7 +909,33 @@ typedef ptrdiff_t intptr_t; zig_operator(Type, Type, operation, operator) #define zig_shift_operator(Type, operation, operator) \ zig_operator(Type, uint8_t, operation, operator) -#define zig_int_helpers(w, PromotedUnsigned) \ + +#define zig_int_casts_common(bw, sw) \ + static inline uint##bw##_t zig_u##bw##_intCast_u##sw(uint##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline uint##bw##_t zig_u##bw##_intCast_i##sw(int##sw##_t arg) { \ + return (uint##bw##_t)arg; \ + } \ +\ + static inline int##bw##_t zig_i##bw##_intCast_u##sw(uint##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline int##bw##_t zig_i##bw##_intCast_i##sw(int##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline uint##sw##_t zig_u##sw##_truncate_u##bw(uint##bw##_t arg, uint8_t bits) { \ + return (uint##sw##_t)arg & zig_maxInt_u(sw, bits); \ + } \ +\ + static inline int##sw##_t zig_i##sw##_truncate_i##bw(int##bw##_t arg, uint8_t bits) { \ + return ((uint##sw##_t)arg & UINT##sw##_C(1) << (bits - UINT8_C(1))) != UINT##sw##_C(0) \ + ? (int##sw##_t)arg | zig_minInt_i(sw, bits) : (int##sw##_t)arg & zig_maxInt_i(sw, bits); \ + } +#define zig_int_operators(w) \ zig_basic_operator(uint##w##_t, and_u##w, &) \ zig_basic_operator( int##w##_t, and_i##w, &) \ zig_basic_operator(uint##w##_t, or_u##w, |) \ @@ -786,44 +951,48 @@ typedef ptrdiff_t intptr_t; return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \ } \ \ - static inline uint##w##_t zig_not_u##w(uint##w##_t val, uint8_t bits) { \ - return val ^ zig_maxInt_u(w, bits); \ + static inline uint##w##_t zig_not_u##w(uint##w##_t arg, uint8_t bits) { \ + return arg ^ zig_maxInt_u(w, bits); \ } \ \ - static inline int##w##_t zig_not_i##w(int##w##_t val, uint8_t bits) { \ + static inline int##w##_t zig_not_i##w(int##w##_t arg, uint8_t bits) { \ (void)bits; \ - return ~val; \ + return ~arg; \ } \ \ - static inline uint##w##_t zig_wrap_u##w(uint##w##_t val, uint8_t bits) { \ - return val & zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_wrap_i##w(int##w##_t val, uint8_t bits) { \ - return (val & UINT##w##_C(1) << (bits - UINT8_C(1))) != 0 \ - ? val | zig_minInt_i(w, bits) : val & zig_maxInt_i(w, bits); \ - } \ -\ - static inline uint##w##_t zig_abs_i##w(int##w##_t val) { \ - return (val < 0) ? -(uint##w##_t)val : (uint##w##_t)val; \ - } \ -\ - zig_basic_operator(uint##w##_t, div_floor_u##w, /) \ + zig_basic_operator(uint##w##_t, divFloor_u##w, /) \ \ - static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \ + static inline int##w##_t zig_divFloor_i##w(int##w##_t lhs, int##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != INT##w##_C(0) ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ } \ \ - static inline uint##w##_t zig_div_ceil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + static inline uint##w##_t zig_divCeil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != UINT##w##_C(0) ? UINT##w##_C(1) : UINT##w##_C(0)); \ } \ \ - static inline int##w##_t zig_div_ceil_i##w(int##w##_t lhs, int##w##_t rhs) { \ + static inline int##w##_t zig_divCeil_i##w(int##w##_t lhs, int##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != INT##w##_C(0) \ ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) + INT##w##_C(1) : INT##w##_C(0)); \ } \ \ zig_basic_operator(uint##w##_t, mod_u##w, %) \ + zig_int_casts_common(w, w) \ +\ + static inline uint##w##_t zig_u##w##_bitCast_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_u##w##_truncate_u##w(arg, bits); \ + } \ +\ + static inline uint##w##_t zig_u##w##_bitCast_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_u##w##_bitCast_u##w((uint##w##_t)arg, bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_bitCast_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_i##w##_truncate_i##w(arg, bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_bitCast_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_i##w##_bitCast_i##w((int##w##_t)arg, bits); \ + } \ \ static inline int##w##_t zig_mod_i##w(int##w##_t lhs, int##w##_t rhs) { \ int##w##_t rem = lhs % rhs; \ @@ -831,100 +1000,102 @@ typedef ptrdiff_t intptr_t; } \ \ static inline uint##w##_t zig_shlw_u##w(uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \ + return zig_u##w##_truncate_u##w(zig_shl_u##w(lhs, rhs), bits); \ } \ \ static inline int##w##_t zig_shlw_i##w(int##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)zig_shl_u##w((uint##w##_t)lhs, rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_shl_u##w(zig_u##w##_bitCast_i##w(lhs, bits), rhs), bits); \ } \ \ static inline uint##w##_t zig_addw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs + rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs + rhs, bits); \ } \ \ static inline int##w##_t zig_addw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs + (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_addw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ } \ \ static inline uint##w##_t zig_subw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs - rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs - rhs, bits); \ } \ \ static inline int##w##_t zig_subw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs - (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_subw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ } \ \ static inline uint##w##_t zig_mulw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w((PromotedUnsigned)lhs * rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs * rhs, bits); \ } \ \ static inline int##w##_t zig_mulw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs * (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_mulw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ + } \ +\ + static inline uint##w##_t zig_abs_i##w(int##w##_t arg) { \ + int##w##_t tmp = zig_shr_i##w(arg, UINT8_C(w) - UINT8_C(1)); \ + return zig_u##w##_bitCast_i##w(zig_subw_i##w(zig_xor_i##w(arg, tmp), tmp, UINT8_C(w)), UINT8_C(w)); \ + } \ +\ + static inline uint##w##_t zig_min_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + return lhs < rhs ? lhs : rhs; \ + } \ +\ + static inline int##w##_t zig_min_i##w(int##w##_t lhs, int##w##_t rhs) { \ + return lhs < rhs ? lhs : rhs; \ + } \ +\ + static inline uint##w##_t zig_max_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + return lhs >= rhs ? lhs : rhs; \ + } \ +\ + static inline int##w##_t zig_max_i##w(int##w##_t lhs, int##w##_t rhs) { \ + return lhs >= rhs ? lhs : rhs; \ } -#if UINT8_MAX <= UINT_MAX -zig_int_helpers(8, unsigned int) -#elif UINT8_MAX <= ULONG_MAX -zig_int_helpers(8, unsigned long) -#elif UINT8_MAX <= ULLONG_MAX -zig_int_helpers(8, unsigned long long) -#else -zig_int_helpers(8, uint8_t) +zig_int_operators(8) +zig_int_operators(16) +zig_int_operators(32) +zig_int_operators(64) +#ifdef zig_ez80 +zig_int_operators(24) +zig_int_operators(48) #endif -#if UINT16_MAX <= UINT_MAX -zig_int_helpers(16, unsigned int) -#elif UINT16_MAX <= ULONG_MAX -zig_int_helpers(16, unsigned long) -#elif UINT16_MAX <= ULLONG_MAX -zig_int_helpers(16, unsigned long long) -#else -zig_int_helpers(16, uint16_t) -#endif -#if defined(zig_ez80) -#if UINT24_MAX <= UINT_MAX -zig_int_helpers(24, unsigned int) -#elif UINT24_MAX <= ULONG_MAX -zig_int_helpers(24, unsigned long) -#elif UINT24_MAX <= ULLONG_MAX -zig_int_helpers(24, unsigned long long) -#else -zig_int_helpers(24, uint24_t) -#endif -#endif -#if UINT32_MAX <= UINT_MAX -zig_int_helpers(32, unsigned int) -#elif UINT32_MAX <= ULONG_MAX -zig_int_helpers(32, unsigned long) -#elif UINT32_MAX <= ULLONG_MAX -zig_int_helpers(32, unsigned long long) -#else -zig_int_helpers(32, uint32_t) -#endif -#if defined(zig_ez80) -#if UINT24_MAX <= UINT_MAX -zig_int_helpers(48, unsigned int) -#elif UINT24_MAX <= ULONG_MAX -zig_int_helpers(48, unsigned long) -#elif UINT24_MAX <= ULLONG_MAX -zig_int_helpers(48, unsigned long long) -#else -zig_int_helpers(48, uint48_t) -#endif -#endif -#if UINT64_MAX <= UINT_MAX -zig_int_helpers(64, unsigned int) -#elif UINT64_MAX <= ULONG_MAX -zig_int_helpers(64, unsigned long) -#elif UINT64_MAX <= ULLONG_MAX -zig_int_helpers(64, unsigned long long) -#else -zig_int_helpers(64, uint64_t) + +#define zig_int_casts(bw, sw) \ + static inline uint##sw##_t zig_u##sw##_intCast_u##bw(uint##bw##_t arg) { \ + return (uint##sw##_t)arg; \ + } \ +\ + static inline uint##sw##_t zig_u##sw##_intCast_i##bw(int##bw##_t arg) { \ + return (uint##sw##_t)arg; \ + } \ +\ + static inline int##sw##_t zig_i##sw##_intCast_u##bw(uint##bw##_t arg) { \ + return (int##sw##_t)arg; \ + } \ +\ + static inline int##sw##_t zig_i##sw##_intCast_i##bw(int##bw##_t arg) { \ + return (int##sw##_t)arg; \ + } \ +\ + zig_int_casts_common(bw, sw) +zig_int_casts(16, 8) +zig_int_casts(32, 8) +zig_int_casts(64, 8) +zig_int_casts(32, 16) +zig_int_casts(64, 16) +zig_int_casts(64, 32) +#ifdef zig_ez80 +zig_int_casts(32, 24) +zig_int_casts(48, 24) +zig_int_casts(64, 24) +zig_int_casts(64, 48) #endif static inline bool zig_addo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_addw_u32(lhs, rhs, bits); @@ -936,19 +1107,19 @@ static inline bool zig_addo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_i32_truncate_i32(full_res, bits); + return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); #else - int32_t full_res = (int32_t)((uint32_t)lhs + (uint32_t)rhs); - bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; + *res = zig_addw_i32(lhs, rhs, bits); + return ((*res ^ lhs) & (*res ^ rhs)) < INT32_C(0); #endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } static inline bool zig_addo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_addw_u64(lhs, rhs, bits); @@ -960,24 +1131,24 @@ static inline bool zig_addo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_i64_truncate_i64(full_res, bits); + return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); #else - int64_t full_res = (int64_t)((uint64_t)lhs + (uint64_t)rhs); - bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; + *res = zig_addw_i64(lhs, rhs, bits); + return ((*res ^ lhs) & (*res ^ rhs)) < INT64_C(0); #endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } static inline bool zig_addo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -986,12 +1157,12 @@ static inline bool zig_addo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(add_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1000,12 +1171,12 @@ static inline bool zig_addo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1014,27 +1185,28 @@ static inline bool zig_addo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_addo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1043,28 +1215,26 @@ static inline bool zig_addo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_addo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_addo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1073,22 +1243,23 @@ static inline bool zig_addo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_addo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif static inline bool zig_subo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_subw_u32(lhs, rhs, bits); @@ -1100,20 +1271,19 @@ static inline bool zig_subo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_i32_truncate_i32(full_res, bits); + return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); #else - int32_t full_res = (int32_t)((uint32_t)lhs - (uint32_t)rhs); - bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; + *res = zig_subw_i32(lhs, rhs, bits); + return ((lhs ^ rhs) & (*res ^ lhs)) < INT32_C(0); #endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } - static inline bool zig_subo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_subw_u64(lhs, rhs, bits); @@ -1125,24 +1295,24 @@ static inline bool zig_subo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_i64_truncate_i64(full_res, bits); + return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); #else - int64_t full_res = (int64_t)((uint64_t)lhs - (uint64_t)rhs); - bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; + *res = zig_subw_i64(lhs, rhs, bits); + return ((lhs ^ rhs) & (*res ^ lhs)) < INT64_C(0); #endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } static inline bool zig_subo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -1151,12 +1321,12 @@ static inline bool zig_subo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1165,12 +1335,12 @@ static inline bool zig_subo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1179,27 +1349,28 @@ static inline bool zig_subo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_subo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1208,28 +1379,26 @@ static inline bool zig_subo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_subo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_subo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1238,22 +1407,23 @@ static inline bool zig_subo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_subo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_mulw_u32(lhs, rhs, bits); @@ -1261,8 +1431,8 @@ static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8 #endif } -zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow); static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) { + zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow); #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -1271,7 +1441,7 @@ static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t int32_t full_res = __mulosi4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i32(full_res, bits); + *res = zig_i32_truncate_i32(full_res, bits); return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } @@ -1279,7 +1449,7 @@ static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8 #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_mulw_u64(lhs, rhs, bits); @@ -1287,8 +1457,8 @@ static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8 #endif } -zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) { + zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -1297,7 +1467,7 @@ static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t int64_t full_res = __mulodi4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i64(full_res, bits); + *res = zig_i64_truncate_i64(full_res, bits); return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } @@ -1305,12 +1475,12 @@ static inline bool zig_mulo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t b #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -1319,12 +1489,12 @@ static inline bool zig_mulo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1333,12 +1503,12 @@ static inline bool zig_mulo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1347,27 +1517,28 @@ static inline bool zig_mulo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_mulo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1376,28 +1547,26 @@ static inline bool zig_mulo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_mulo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_mulo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1406,18 +1575,32 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_mulo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif -#define zig_int_builtins(w) \ +#define zig_shls_builtins(lw, rw) \ + static inline uint##lw##_t zig_shls_u##lw##_u##rw(uint##lw##_t lhs, uint##rw##_t rhs, uint8_t bits) { \ + uint##lw##_t res; \ + if (rhs < bits && !zig_shlo_u##lw(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + return lhs == INT##lw##_C(0) ? zig_minInt_u(lw, bits) : zig_maxInt_u(lw, bits); \ + } \ +\ + static inline int##lw##_t zig_shls_i##lw##_u##rw(int##lw##_t lhs, uint##rw##_t rhs, uint8_t bits) { \ + int##lw##_t res; \ + if (rhs < bits && !zig_shlo_i##lw(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + return lhs == INT##lw##_C(0) ? INT##lw##_C(0) : \ + lhs < INT##lw##_C(0) ? zig_minInt_i(lw, bits) : zig_maxInt_i(lw, bits); \ + } +#define zig_int_sat_builtins(w) \ static inline bool zig_shlo_u##w(uint##w##_t *res, uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ *res = zig_shlw_u##w(lhs, rhs, bits); \ return lhs > zig_maxInt_u(w, bits) >> rhs; \ @@ -1429,18 +1612,10 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t return (lhs & mask) != INT##w##_C(0) && (lhs & mask) != mask; \ } \ \ - static inline uint##w##_t zig_shls_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - uint##w##_t res; \ - if (rhs < bits && !zig_shlo_u##w(&res, lhs, rhs, bits)) return res; \ - return lhs == INT##w##_C(0) ? INT##w##_C(0) : zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_shls_i##w(int##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - int##w##_t res; \ - if (rhs < bits && !zig_shlo_i##w(&res, lhs, rhs, bits)) return res; \ - return lhs == INT##w##_C(0) ? INT##w##_C(0) : \ - lhs < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ - } \ + zig_shls_builtins(w, 8) \ + zig_shls_builtins(w, 16) \ + zig_shls_builtins(w, 32) \ + zig_shls_builtins(w, 64) \ \ static inline uint##w##_t zig_adds_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ uint##w##_t res; \ @@ -1474,332 +1649,321 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \ return (lhs ^ rhs) < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ } -zig_int_builtins(8) -zig_int_builtins(16) +zig_int_sat_builtins(8) +zig_int_sat_builtins(16) +zig_int_sat_builtins(32) +zig_int_sat_builtins(64) #if defined(zig_ez80) -zig_int_builtins(24) +zig_int_sat_builtins(24) +zig_int_sat_builtins(48) #endif -zig_int_builtins(32) -#if defined(zig_ez80) -zig_int_builtins(48) -#endif -zig_int_builtins(64) -#define zig_builtin8(name, val) __builtin_##name(val) +#define zig_builtin8(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin8; -#define zig_builtin16(name, val) __builtin_##name(val) +#define zig_builtin16(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin16; -#if defined(zig_ez80) -#define zig_builtin24(name, val) __builtin_##name(val) -typedef unsigned int zig_Builtin24; -#endif - #if INT_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name(val) +#define zig_builtin32(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin32; #elif LONG_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name##l(val) +#define zig_builtin32(name, arg) __builtin_##name##l(arg) typedef unsigned long zig_Builtin32; #endif -#if defined(zig_ez80) -#define zig_builtin48(name, val) __builtin_##name(val) -typedef unsigned long long zig_Builtin48; -#endif - #if INT_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name(val) +#define zig_builtin64(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin64; #elif LONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##l(val) +#define zig_builtin64(name, arg) __builtin_##name##l(arg) typedef unsigned long zig_Builtin64; #elif LLONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##ll(val) +#define zig_builtin64(name, arg) __builtin_##name##ll(arg) typedef unsigned long long zig_Builtin64; #endif -static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) { - return zig_wrap_u8(val >> (8 - bits), bits); +#if defined(zig_ez80) +#define zig_builtin24(name, arg) __builtin_##name(arg) +typedef unsigned int zig_Builtin24; +#define zig_builtin48(name, arg) __builtin_##name(arg) +typedef unsigned long long zig_Builtin48; +#endif + +static inline uint8_t zig_byteSwap_u8(uint8_t arg, uint8_t bits) { + return zig_u8_truncate_u8(arg >> (8 - bits), bits); } -static inline int8_t zig_byte_swap_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_byte_swap_u8((uint8_t)val, bits), bits); +static inline int8_t zig_byteSwap_i8(int8_t arg, uint8_t bits) { + return zig_i8_truncate_i8((int8_t)zig_byteSwap_u8((uint8_t)arg, bits), bits); } -static inline uint16_t zig_byte_swap_u16(uint16_t val, uint8_t bits) { +static inline uint16_t zig_byteSwap_u16(uint16_t arg, uint8_t bits) { uint16_t full_res; #if zig_has_builtin(bswap16) || defined(zig_gcc) - full_res = __builtin_bswap16(val); + full_res = __builtin_bswap16(arg); #else - full_res = (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 8), 8) >> 0; + full_res = (uint16_t)zig_byteSwap_u8((uint8_t)(arg >> 0), 8) << 8 | + (uint16_t)zig_byteSwap_u8((uint8_t)(arg >> 8), 8) >> 0; #endif - return zig_wrap_u16(full_res >> (16 - bits), bits); + return zig_u16_truncate_u16(full_res >> (16 - bits), bits); } -static inline int16_t zig_byte_swap_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_byte_swap_u16((uint16_t)val, bits), bits); +static inline int16_t zig_byteSwap_i16(int16_t arg, uint8_t bits) { + return zig_i16_truncate_i16((int16_t)zig_byteSwap_u16((uint16_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint16_t zig_byte_swap_u24(uint24_t val, uint8_t bits) { +static inline uint16_t zig_byteSwap_u24(uint24_t arg, uint8_t bits) { uint24_t full_res; #if zig_has_builtin(bswap24) || defined(zig_gcc) - full_res = __builtin_bswap24(val); + full_res = __builtin_bswap24(arg); #else - full_res = (uint24_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 16 | - (uint24_t)zig_byte_swap_u16((uint16_t)(val >> 8), 16) >> 0; + full_res = (uint24_t)zig_byteSwap_u8((uint8_t)(arg >> 0), 8) << 16 | + (uint24_t)zig_byteSwap_u16((uint16_t)(arg >> 8), 16) >> 0; #endif - return zig_wrap_u24(full_res >> (24 - bits), bits); + return zig_u24_truncate_u24(full_res >> (24 - bits), bits); } -static inline int16_t zig_byte_swap_i24(int24_t val, uint8_t bits) { - return zig_wrap_i24((int24_t)zig_byte_swap_u24((uint24_t)val, bits), bits); +static inline int16_t zig_byteSwap_i24(int24_t arg, uint8_t bits) { + return zig_i24_truncate_i24((int24_t)zig_byteSwap_u24((uint24_t)arg, bits), bits); } #endif -static inline uint32_t zig_byte_swap_u32(uint32_t val, uint8_t bits) { +static inline uint32_t zig_byteSwap_u32(uint32_t arg, uint8_t bits) { uint32_t full_res; #if zig_has_builtin(bswap32) || defined(zig_gcc) - full_res = __builtin_bswap32(val); + full_res = __builtin_bswap32(arg); #else - full_res = (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 16), 16) >> 0; + full_res = (uint32_t)zig_byteSwap_u16((uint16_t)(arg >> 0), 16) << 16 | + (uint32_t)zig_byteSwap_u16((uint16_t)(arg >> 16), 16) >> 0; #endif - return zig_wrap_u32(full_res >> (32 - bits), bits); + return zig_u32_truncate_u32(full_res >> (32 - bits), bits); } -static inline int32_t zig_byte_swap_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_byte_swap_u32((uint32_t)val, bits), bits); +static inline int32_t zig_byteSwap_i32(int32_t arg, uint8_t bits) { + return zig_i32_truncate_i32((int32_t)zig_byteSwap_u32((uint32_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint32_t zig_byte_swap_u48(uint48_t val, uint8_t bits) { +static inline uint32_t zig_byteSwap_u48(uint48_t arg, uint8_t bits) { uint48_t full_res; #if zig_has_builtin(bswap48) || defined(zig_gcc) - full_res = __builtin_bswap48(val); + full_res = __builtin_bswap48(arg); #else - full_res = (uint48_t)zig_byte_swap_u24((uint24_t)(val >> 0), 24) << 24 | - (uint48_t)zig_byte_swap_u24((uint24_t)(val >> 24), 24) >> 0; + full_res = (uint48_t)zig_byteSwap_u24((uint24_t)(arg >> 0), 24) << 24 | + (uint48_t)zig_byteSwap_u24((uint24_t)(arg >> 24), 24) >> 0; #endif - return zig_wrap_u48(full_res >> (48 - bits), bits); + return zig_u48_truncate_u48(full_res >> (48 - bits), bits); } -static inline int32_t zig_byte_swap_i48(int48_t val, uint8_t bits) { - return zig_wrap_i48((int48_t)zig_byte_swap_u48((uint48_t)val, bits), bits); +static inline int32_t zig_byteSwap_i48(int48_t arg, uint8_t bits) { + return zig_i48_truncate_i48((int48_t)zig_byteSwap_u48((uint48_t)arg, bits), bits); } #endif -static inline uint64_t zig_byte_swap_u64(uint64_t val, uint8_t bits) { +static inline uint64_t zig_byteSwap_u64(uint64_t arg, uint8_t bits) { uint64_t full_res; #if zig_has_builtin(bswap64) || defined(zig_gcc) - full_res = __builtin_bswap64(val); + full_res = __builtin_bswap64(arg); #else - full_res = (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 32), 32) >> 0; + full_res = (uint64_t)zig_byteSwap_u32((uint32_t)(arg >> 0), 32) << 32 | + (uint64_t)zig_byteSwap_u32((uint32_t)(arg >> 32), 32) >> 0; #endif - return zig_wrap_u64(full_res >> (64 - bits), bits); + return zig_u64_truncate_u64(full_res >> (64 - bits), bits); } -static inline int64_t zig_byte_swap_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_byte_swap_u64((uint64_t)val, bits), bits); +static inline int64_t zig_byteSwap_i64(int64_t arg, uint8_t bits) { + return zig_i64_truncate_i64((int64_t)zig_byteSwap_u64((uint64_t)arg, bits), bits); } -static inline uint8_t zig_bit_reverse_u8(uint8_t val, uint8_t bits) { +static inline uint8_t zig_bitReverse_u8(uint8_t arg, uint8_t bits) { uint8_t full_res; #if zig_has_builtin(bitreverse8) - full_res = __builtin_bitreverse8(val); + full_res = __builtin_bitreverse8(arg); #else static uint8_t const lut[0x10] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; - full_res = lut[val >> 0 & 0xF] << 4 | lut[val >> 4 & 0xF] << 0; + full_res = lut[arg >> 0 & 0xF] << 4 | lut[arg >> 4 & 0xF] << 0; #endif - return zig_wrap_u8(full_res >> (8 - bits), bits); + return zig_u8_truncate_u8(full_res >> (8 - bits), bits); } -static inline int8_t zig_bit_reverse_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_bit_reverse_u8((uint8_t)val, bits), bits); +static inline int8_t zig_bitReverse_i8(int8_t arg, uint8_t bits) { + return zig_i8_truncate_i8((int8_t)zig_bitReverse_u8((uint8_t)arg, bits), bits); } -static inline uint16_t zig_bit_reverse_u16(uint16_t val, uint8_t bits) { +static inline uint16_t zig_bitReverse_u16(uint16_t arg, uint8_t bits) { uint16_t full_res; #if zig_has_builtin(bitreverse16) - full_res = __builtin_bitreverse16(val); + full_res = __builtin_bitreverse16(arg); #else - full_res = (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 8), 8) >> 0; + full_res = (uint16_t)zig_bitReverse_u8((uint8_t)(arg >> 0), 8) << 8 | + (uint16_t)zig_bitReverse_u8((uint8_t)(arg >> 8), 8) >> 0; #endif - return zig_wrap_u16(full_res >> (16 - bits), bits); + return zig_u16_truncate_u16(full_res >> (16 - bits), bits); } -static inline int16_t zig_bit_reverse_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_bit_reverse_u16((uint16_t)val, bits), bits); +static inline int16_t zig_bitReverse_i16(int16_t arg, uint8_t bits) { + return zig_i16_truncate_i16((int16_t)zig_bitReverse_u16((uint16_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint24_t zig_bit_reverse_u24(uint24_t val, uint8_t bits) { +static inline uint24_t zig_bitReverse_u24(uint24_t arg, uint8_t bits) { uint24_t full_res; #if zig_has_builtin(bitreverse24) - full_res = __builtin_bitreverse24(val); + full_res = __builtin_bitreverse24(arg); #else - full_res = (uint24_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 16 | - (uint24_t)zig_bit_reverse_u16((uint16_t)(val >> 8), 16) >> 0; + full_res = (uint24_t)zig_bitReverse_u8((uint8_t)(arg >> 0), 8) << 16 | + (uint24_t)zig_bitReverse_u16((uint16_t)(arg >> 8), 16) >> 0; #endif - return zig_wrap_u24(full_res >> (24 - bits), bits); + return zig_u24_truncate_u24(full_res >> (24 - bits), bits); } -static inline int24_t zig_bit_reverse_i24(int24_t val, uint8_t bits) { - return zig_wrap_i24((int24_t)zig_bit_reverse_u24((uint24_t)val, bits), bits); +static inline int24_t zig_bitReverse_i24(int24_t arg, uint8_t bits) { + return zig_i24_truncate_i24((int24_t)zig_bitReverse_u24((uint24_t)arg, bits), bits); } #endif -static inline uint32_t zig_bit_reverse_u32(uint32_t val, uint8_t bits) { +static inline uint32_t zig_bitReverse_u32(uint32_t arg, uint8_t bits) { uint32_t full_res; #if zig_has_builtin(bitreverse32) - full_res = __builtin_bitreverse32(val); + full_res = __builtin_bitreverse32(arg); #else - full_res = (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 16), 16) >> 0; + full_res = (uint32_t)zig_bitReverse_u16((uint16_t)(arg >> 0), 16) << 16 | + (uint32_t)zig_bitReverse_u16((uint16_t)(arg >> 16), 16) >> 0; #endif - return zig_wrap_u32(full_res >> (32 - bits), bits); + return zig_u32_truncate_u32(full_res >> (32 - bits), bits); } -static inline int32_t zig_bit_reverse_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_bit_reverse_u32((uint32_t)val, bits), bits); +static inline int32_t zig_bitReverse_i32(int32_t arg, uint8_t bits) { + return zig_i32_truncate_i32((int32_t)zig_bitReverse_u32((uint32_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint32_t zig_bit_reverse_u48(uint48_t val, uint8_t bits) { +static inline uint32_t zig_bitReverse_u48(uint48_t arg, uint8_t bits) { uint48_t full_res; #if zig_has_builtin(bitreverse48) - full_res = __builtin_bitreverse48(val); + full_res = __builtin_bitreverse48(arg); #else - full_res = (uint48_t)zig_bit_reverse_u24((uint24_t)(val >> 0), 24) << 24 | - (uint48_t)zig_bit_reverse_u24((uint24_t)(val >> 24), 24) >> 0; + full_res = (uint48_t)zig_bitReverse_u24((uint24_t)(arg >> 0), 24) << 24 | + (uint48_t)zig_bitReverse_u24((uint24_t)(arg >> 24), 24) >> 0; #endif - return zig_wrap_u32(full_res >> (48 - bits), bits); + return zig_u48_truncate_u48(full_res >> (48 - bits), bits); } -static inline int32_t zig_bit_reverse_i48(int48_t val, uint8_t bits) { - return zig_wrap_i48((int48_t)zig_bit_reverse_u48((uint48_t)val, bits), bits); +static inline int32_t zig_bitReverse_i48(int48_t arg, uint8_t bits) { + return zig_i48_truncate_i48((int48_t)zig_bitReverse_u48((uint48_t)arg, bits), bits); } #endif -static inline uint64_t zig_bit_reverse_u64(uint64_t val, uint8_t bits) { +static inline uint64_t zig_bitReverse_u64(uint64_t arg, uint8_t bits) { uint64_t full_res; #if zig_has_builtin(bitreverse64) - full_res = __builtin_bitreverse64(val); + full_res = __builtin_bitreverse64(arg); #else - full_res = (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 32), 32) >> 0; + full_res = (uint64_t)zig_bitReverse_u32((uint32_t)(arg >> 0), 32) << 32 | + (uint64_t)zig_bitReverse_u32((uint32_t)(arg >> 32), 32) >> 0; #endif - return zig_wrap_u64(full_res >> (64 - bits), bits); + return zig_u64_truncate_u64(full_res >> (64 - bits), bits); } -static inline int64_t zig_bit_reverse_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_bit_reverse_u64((uint64_t)val, bits), bits); +static inline int64_t zig_bitReverse_i64(int64_t arg, uint8_t bits) { + return zig_i64_truncate_i64((int64_t)zig_bitReverse_u64((uint64_t)arg, bits), bits); } -#define zig_builtin_popcount_common(w) \ - static inline uint8_t zig_popcount_i##w(int##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w((uint##w##_t)val, bits); \ +#define zig_builtin_popCount_common(w) \ + static inline uint8_t zig_popCount_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_popCount_u##w((uint##w##_t)arg, bits); \ } -#if zig_has_builtin(popcount) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ +#if zig_has_builtin(popCount) || defined(zig_gcc) || defined(zig_tinyc) +#define zig_builtin_popCount(w) \ + static inline uint8_t zig_popCount_u##w(uint##w##_t arg, uint8_t bits) { \ (void)bits; \ - return zig_builtin##w(popcount, val); \ + return zig_builtin##w(popcount, arg); \ } \ \ - zig_builtin_popcount_common(w) + zig_builtin_popCount_common(w) #else -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ +#define zig_builtin_popCount(w) \ + static inline uint8_t zig_popCount_u##w(uint##w##_t arg, uint8_t bits) { \ (void)bits; \ - uint##w##_t temp = val - ((val >> 1) & (UINT##w##_MAX / 3)); \ + uint##w##_t temp = arg - ((arg >> 1) & (UINT##w##_MAX / 3)); \ temp = (temp & (UINT##w##_MAX / 5)) + ((temp >> 2) & (UINT##w##_MAX / 5)); \ temp = (temp + (temp >> 4)) & (UINT##w##_MAX / 17); \ return temp * (UINT##w##_MAX / 255) >> (UINT8_C(w) - UINT8_C(8)); \ } \ \ - zig_builtin_popcount_common(w) + zig_builtin_popCount_common(w) #endif -zig_builtin_popcount(8) -zig_builtin_popcount(16) +zig_builtin_popCount(8) +zig_builtin_popCount(16) +zig_builtin_popCount(32) +zig_builtin_popCount(64) #if defined(zig_ez80) -zig_builtin_popcount(24) +zig_builtin_popCount(24) +zig_builtin_popCount(48) #endif -zig_builtin_popcount(32) -#if defined(zig_ez80) -zig_builtin_popcount(48) -#endif -zig_builtin_popcount(64) #define zig_builtin_ctz_common(w) \ - static inline uint8_t zig_ctz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w((uint##w##_t)val, bits); \ + static inline uint8_t zig_ctz_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_ctz_u##w((uint##w##_t)arg, bits); \ } #if zig_has_builtin(ctz) || defined(zig_gcc) || defined(zig_tinyc) #define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(ctz, val); \ + static inline uint8_t zig_ctz_u##w(uint##w##_t arg, uint8_t bits) { \ + if (arg == 0) return bits; \ + return zig_builtin##w(ctz, arg); \ } \ \ zig_builtin_ctz_common(w) #else #define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w(zig_not_u##w(val, bits) & zig_subw_u##w(val, 1, bits), bits); \ + static inline uint8_t zig_ctz_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_popCount_u##w(zig_not_u##w(arg, bits) & zig_subw_u##w(arg, 1, bits), bits); \ } \ \ zig_builtin_ctz_common(w) #endif zig_builtin_ctz(8) zig_builtin_ctz(16) -#if defined(zig_ez80) -zig_builtin_ctz(24) -#endif zig_builtin_ctz(32) -#if defined(zig_ez80) -zig_builtin_ctz(48) -#endif zig_builtin_ctz(64) +#if defined(zig_ez80) +zig_builtin_ctz(24) +zig_builtin_ctz(48) +#endif #define zig_builtin_clz_common(w) \ - static inline uint8_t zig_clz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_clz_u##w((uint##w##_t)val, bits); \ + static inline uint8_t zig_clz_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_clz_u##w((uint##w##_t)arg, bits); \ } #if zig_has_builtin(clz) || defined(zig_gcc) || defined(zig_tinyc) #define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ + static inline uint8_t zig_clz_u##w(uint##w##_t arg, uint8_t bits) { \ + if (arg == 0) return bits; \ + return zig_builtin##w(clz, arg) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ } \ \ zig_builtin_clz_common(w) #else #define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w(zig_bit_reverse_u##w(val, bits), bits); \ + static inline uint8_t zig_clz_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_ctz_u##w(zig_bitReverse_u##w(arg, bits), bits); \ } \ \ zig_builtin_clz_common(w) #endif zig_builtin_clz(8) zig_builtin_clz(16) -#if defined(zig_ez80) -zig_builtin_clz(24) -#endif zig_builtin_clz(32) -#if defined(zig_ez80) -zig_builtin_clz(48) -#endif zig_builtin_clz(64) +#if defined(zig_ez80) +zig_builtin_clz(24) +zig_builtin_clz(48) +#endif /* ======================== 128-bit Integer Support ========================= */ @@ -1816,16 +1980,14 @@ zig_builtin_clz(64) typedef unsigned __int128 zig_u128; typedef signed __int128 zig_i128; -#define zig_make_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) -#define zig_make_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo)) -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#define zig_hi_u128(val) ((uint64_t)((val) >> 64)) -#define zig_lo_u128(val) ((uint64_t)((val) >> 0)) -#define zig_hi_i128(val) (( int64_t)((val) >> 64)) -#define zig_lo_i128(val) ((uint64_t)((val) >> 0)) -#define zig_bitCast_u128(val) ((zig_u128)(val)) -#define zig_bitCast_i128(val) ((zig_i128)(val)) +#define zig_init_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) +#define zig_init_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo)) +#define zig_make_u128(hi, lo) zig_init_u128(hi, lo) +#define zig_make_i128(hi, lo) zig_init_i128(hi, lo) +#define zig_hi_u128(arg) ((uint64_t)((arg) >> 64)) +#define zig_lo_u128(arg) ((uint64_t)((arg) >> 0)) +#define zig_hi_i128(arg) (( int64_t)((arg) >> 64)) +#define zig_lo_i128(arg) ((uint64_t)((arg) >> 0)) #define zig_cmp_int128(Type) \ static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ return (lhs > rhs) - (lhs < rhs); \ @@ -1835,32 +1997,49 @@ typedef signed __int128 zig_i128; return lhs operator rhs; \ } +static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { + return lhs << rhs; +} + +static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { + return lhs >> rhs; +} + +static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { + return lhs << rhs; +} + +static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { + // This works around a GCC miscompilation, but it has the side benefit of + // emitting better code. It is behind the `#if` because it depends on + // arithmetic right shift, which is implementation-defined in C, but should + // be guaranteed on any GCC-compatible compiler. +#if defined(zig_gnuc) + return lhs >> rhs; +#else + zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0); + return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; +#endif +} + #else /* zig_has_int128 */ #if zig_little_endian -typedef struct { zig_align(16) uint64_t lo; uint64_t hi; } zig_u128; -typedef struct { zig_align(16) uint64_t lo; int64_t hi; } zig_i128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t lo; uint64_t hi; } zig_u128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t lo; int64_t hi; } zig_i128; #else -typedef struct { zig_align(16) uint64_t hi; uint64_t lo; } zig_u128; -typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t hi; uint64_t lo; } zig_u128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) int64_t hi; uint64_t lo; } zig_i128; #endif -#define zig_make_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) }) -#define zig_make_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) }) - -#if defined(zig_msvc) /* MSVC doesn't allow struct literals in constant expressions */ -#define zig_init_u128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#define zig_init_i128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#else /* But non-MSVC doesn't like the unprotected commas */ -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#endif -#define zig_hi_u128(val) ((val).hi) -#define zig_lo_u128(val) ((val).lo) -#define zig_hi_i128(val) ((val).hi) -#define zig_lo_i128(val) ((val).lo) -#define zig_bitCast_u128(val) zig_make_u128((uint64_t)(val).hi, (val).lo) -#define zig_bitCast_i128(val) zig_make_i128(( int64_t)(val).hi, (val).lo) +#define zig_init_u128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_init_i128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_make_u128(hi, lo) (zig_u128)zig_init_u128(hi, lo) +#define zig_make_i128(hi, lo) (zig_i128)zig_init_i128(hi, lo) +#define zig_hi_u128(arg) (arg).hi +#define zig_lo_u128(arg) (arg).lo +#define zig_hi_i128(arg) (arg).hi +#define zig_lo_i128(arg) (arg).lo #define zig_cmp_int128(Type) \ static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ return (lhs.hi == rhs.hi) \ @@ -1872,6 +2051,30 @@ typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128; return (zig_##Type){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \ } +static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; + return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +} + +static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) }; + return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs }; +} + +static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; + return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +} + +static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) }; + return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) }; +} + #endif /* zig_has_int128 */ #define zig_minInt_u128 zig_make_u128(zig_minInt_u64, zig_minInt_u64) @@ -1891,42 +2094,177 @@ zig_bit_int128(i128, or, |) zig_bit_int128(u128, xor, ^) zig_bit_int128(i128, xor, ^) -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs); +static inline uint8_t zig_u8_intCast_u128(zig_u128 arg) { + return (uint8_t)zig_lo_u128(arg); +} +static inline uint8_t zig_u8_intCast_i128(zig_i128 arg) { + return (uint8_t)zig_lo_i128(arg); +} +static inline int8_t zig_i8_intCast_i128(zig_i128 arg) { + return (int8_t)zig_lo_i128(arg); +} +static inline int8_t zig_i8_intCast_u128(zig_u128 arg) { + return (int8_t)zig_lo_u128(arg); +} -#if zig_has_int128 +static inline uint16_t zig_u16_intCast_u128(zig_u128 arg) { + return (uint16_t)zig_lo_u128(arg); +} +static inline uint16_t zig_u16_intCast_i128(zig_i128 arg) { + return (uint16_t)zig_lo_i128(arg); +} +static inline int16_t zig_i16_intCast_i128(zig_i128 arg) { + return (int16_t)zig_lo_i128(arg); +} +static inline int16_t zig_i16_intCast_u128(zig_u128 arg) { + return (int16_t)zig_lo_u128(arg); +} -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return val ^ zig_maxInt_u(128, bits); +static inline uint32_t zig_u32_intCast_u128(zig_u128 arg) { + return (uint32_t)zig_lo_u128(arg); +} +static inline uint32_t zig_u32_intCast_i128(zig_i128 arg) { + return (uint32_t)zig_lo_i128(arg); +} +static inline int32_t zig_i32_intCast_i128(zig_i128 arg) { + return (int32_t)zig_lo_i128(arg); +} +static inline int32_t zig_i32_intCast_u128(zig_u128 arg) { + return (int32_t)zig_lo_u128(arg); } -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - (void)bits; - return ~val; +static inline uint64_t zig_u64_intCast_u128(zig_u128 arg) { + return zig_lo_u128(arg); +} +static inline uint64_t zig_u64_intCast_i128(zig_i128 arg) { + return zig_lo_i128(arg); +} +static inline int64_t zig_i64_intCast_i128(zig_i128 arg) { + return (int64_t)zig_lo_i128(arg); +} +static inline int64_t zig_i64_intCast_u128(zig_u128 arg) { + return (int64_t)zig_lo_u128(arg); +} + +static inline zig_u128 zig_u128_intCast_u8(uint8_t arg) { + return zig_make_u128(UINT8_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i8(int8_t arg) { + return zig_make_u128(UINT8_C(0), (uint8_t)arg); +} +static inline zig_i128 zig_i128_intCast_i8(int8_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint8_t)arg); +} +static inline zig_i128 zig_i128_intCast_u8(uint8_t arg) { + return zig_make_i128(INT8_C(0), arg); } -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - return lhs >> rhs; +static inline zig_u128 zig_u128_intCast_u16(uint16_t arg) { + return zig_make_u128(UINT16_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i16(int16_t arg) { + return zig_make_u128(UINT16_C(0), (uint16_t)arg); +} +static inline zig_i128 zig_i128_intCast_i16(int16_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint16_t)arg); +} +static inline zig_i128 zig_i128_intCast_u16(uint16_t arg) { + return zig_make_i128(INT16_C(0), arg); } -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - return lhs << rhs; +static inline zig_u128 zig_u128_intCast_u32(uint32_t arg) { + return zig_make_u128(UINT32_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i32(int32_t arg) { + return zig_make_u128(UINT32_C(0), (uint32_t)arg); +} +static inline zig_i128 zig_i128_intCast_i32(int32_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint32_t)arg); +} +static inline zig_i128 zig_i128_intCast_u32(uint32_t arg) { + return zig_make_i128(INT32_C(0), arg); } -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - // This works around a GCC miscompilation, but it has the side benefit of - // emitting better code. It is behind the `#if` because it depends on - // arithmetic right shift, which is implementation-defined in C, but should - // be guaranteed on any GCC-compatible compiler. -#if defined(zig_gnuc) - return lhs >> rhs; +static inline zig_u128 zig_u128_intCast_u64(uint64_t arg) { + return zig_make_u128(UINT64_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i64(int64_t arg) { + return zig_make_u128(UINT64_C(0), (uint64_t)arg); +} +static inline zig_i128 zig_i128_intCast_i64(int64_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint64_t)arg); +} +static inline zig_i128 zig_i128_intCast_u64(uint64_t arg) { + return zig_make_i128(INT64_C(0), arg); +} + +static inline zig_u128 zig_u128_intCast_u128(zig_u128 arg) { + return arg; +} +static inline zig_u128 zig_u128_intCast_i128(zig_i128 arg) { +#if zig_has_int128 + return (zig_u128)arg; +#else + return zig_make_u128(zig_u64_bitCast_i64(zig_hi_i128(arg), UINT8_C(64)), zig_lo_u128(arg)); +#endif +} +static inline zig_i128 zig_i128_intCast_i128(zig_i128 arg) { + return arg; +} +static inline zig_i128 zig_i128_intCast_u128(zig_u128 arg) { +#if zig_has_int128 + return (zig_i128)arg; #else - zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0); - return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; + return zig_make_i128(zig_i64_bitCast_u64(zig_hi_i128(arg), UINT8_C(64)), zig_lo_u128(arg)); #endif } -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - return lhs << rhs; +#define zig_int128_cast_builtins(w) \ + static inline uint##w##_t zig_u##w##_truncate_u128(zig_u128 arg, uint8_t bits) { \ + return zig_u##w##_truncate_u##w((uint##w##_t)zig_lo_u128(arg), bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_truncate_i128(zig_i128 arg, uint8_t bits) { \ + return zig_i##w##_truncate_i##w((int##w##_t)zig_lo_i128(arg), bits); \ + } +zig_int128_cast_builtins(8) +zig_int128_cast_builtins(16) +zig_int128_cast_builtins(32) +zig_int128_cast_builtins(64) + +static inline zig_u128 zig_u128_truncate_u128(zig_u128 arg, uint8_t bits) { + return zig_and_u128(arg, zig_maxInt_u(128, bits)); +} +static inline zig_i128 zig_i128_truncate_i128(zig_i128 arg, uint8_t bits) { + if (bits > UINT8_C(64)) return zig_make_i128(zig_i64_truncate_i64(zig_hi_i128(arg), bits - UINT8_C(64)), zig_lo_i128(arg)); + int64_t lo = zig_i64_truncate_i128(arg, bits); + return zig_make_i128(zig_shr_i64(lo, 63), (uint64_t)lo); +} + +static inline zig_u128 zig_u128_bitCast_u128(zig_u128 arg, uint8_t bits) { + (void)bits; + return arg; +} +static inline zig_u128 zig_u128_bitCast_i128(zig_i128 arg, uint8_t bits) { + return zig_u128_truncate_u128(zig_u128_intCast_i128(arg), bits); +} +static inline zig_i128 zig_i128_bitCast_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return arg; +} +static inline zig_i128 zig_i128_bitCast_u128(zig_u128 arg, uint8_t bits) { + return zig_i128_truncate_i128(zig_i128_intCast_u128(arg), bits); +} + +#if zig_has_int128 + +static inline zig_u128 zig_not_u128(zig_u128 arg, uint8_t bits) { + return arg ^ zig_maxInt_u(128, bits); +} + +static inline zig_i128 zig_not_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return ~arg; } static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { @@ -1953,11 +2291,11 @@ static inline zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { return lhs * rhs; } -static inline zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { +static inline zig_u128 zig_divTrunc_u128(zig_u128 lhs, zig_u128 rhs) { return lhs / rhs; } -static inline zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divTrunc_i128(zig_i128 lhs, zig_i128 rhs) { return lhs / rhs; } @@ -1971,36 +2309,14 @@ static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { #else /* zig_has_int128 */ -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return (zig_u128){ .hi = zig_not_u64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; +static inline zig_u128 zig_not_u128(zig_u128 arg, uint8_t bits) { + if (bits <= UINT8_C(64)) return (zig_u128){ .hi = UINT64_C(0), .lo = zig_not_u64(arg.lo, bits) }; + return (zig_u128){ .hi = zig_not_u64(arg.hi, bits - UINT8_C(64)), .lo = zig_not_u64(arg.lo, UINT8_C(64)) }; } -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - return (zig_i128){ .hi = zig_not_i64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; -} - -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) }; - return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs }; -} - -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; -} - -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) }; - return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) }; -} - -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +static inline zig_i128 zig_not_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return (zig_i128){ .hi = ~arg.hi, .lo = ~arg.lo }; } static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { @@ -2027,59 +2343,59 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { return res; } -zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); return __multi3(lhs, rhs); } static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) { - return zig_bitCast_u128(zig_mul_i128(zig_bitCast_i128(lhs), zig_bitCast_i128(rhs))); + return zig_u128_bitCast_i128(zig_mul_i128(zig_i128_bitCast_u128(lhs, UINT8_C(128)), zig_i128_bitCast_u128(rhs, UINT8_C(128))), UINT8_C(128)); } -zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); -static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { +static zig_u128 zig_divTrunc_u128(zig_u128 lhs, zig_u128 rhs) { + zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); return __udivti3(lhs, rhs); } -zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); -static zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { +static zig_i128 zig_divTrunc_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); return __divti3(lhs, rhs); } -zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); static zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) { + zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); return __umodti3(lhs, rhs); } -zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); return __modti3(lhs, rhs); } #endif /* zig_has_int128 */ -#define zig_div_floor_u128 zig_div_trunc_u128 +#define zig_divFloor_u128 zig_divTrunc_u128 -static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divFloor_i128(zig_i128 lhs, zig_i128 rhs) { zig_i128 rem = zig_rem_i128(lhs, rhs); int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) : INT64_C(0); - return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); + return zig_add_i128(zig_divTrunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); } -static inline zig_u128 zig_div_ceil_u128(zig_u128 lhs, zig_u128 rhs) { +static inline zig_u128 zig_divCeil_u128(zig_u128 lhs, zig_u128 rhs) { zig_u128 rem = zig_rem_u128(lhs, rhs); uint64_t mask = zig_or_u64(zig_hi_u128(rem), zig_lo_u128(rem)) != UINT64_C(0) ? UINT64_C(1) : UINT64_C(0); - return zig_add_u128(zig_div_trunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); + return zig_add_u128(zig_divTrunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); } -static inline zig_i128 zig_div_ceil_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divCeil_i128(zig_i128 lhs, zig_i128 rhs) { zig_i128 rem = zig_rem_i128(lhs, rhs); int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) + INT64_C(1) : INT64_C(0); - return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); + return zig_add_i128(zig_divTrunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); } #define zig_mod_u128 zig_rem_u128 @@ -2107,51 +2423,41 @@ static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) { return zig_cmp_i128(lhs, rhs) > INT32_C(0) ? lhs : rhs; } -static inline zig_u128 zig_wrap_u128(zig_u128 val, uint8_t bits) { - return zig_and_u128(val, zig_maxInt_u(128, bits)); -} - -static inline zig_i128 zig_wrap_i128(zig_i128 val, uint8_t bits) { - if (bits > UINT8_C(64)) return zig_make_i128(zig_wrap_i64(zig_hi_i128(val), bits - UINT8_C(64)), zig_lo_i128(val)); - int64_t lo = zig_wrap_i64((int64_t)zig_lo_i128(val), bits); - return zig_make_i128(zig_shr_i64(lo, 63), (uint64_t)lo); -} - static inline zig_u128 zig_shlw_u128(zig_u128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_shl_u128(lhs, rhs), bits); } static inline zig_i128 zig_shlw_i128(zig_i128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_shl_u128(zig_bitCast_u128(lhs), rhs)), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_shl_u128(zig_u128_bitCast_i128(lhs, bits), rhs), bits), bits); } static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_add_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_add_u128(lhs, rhs), bits); } static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_add_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_add_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_sub_u128(lhs, rhs), bits); } static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_sub_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_sub_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_mul_u128(lhs, rhs), bits); } static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_mul_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } -static inline zig_u128 zig_abs_i128(zig_i128 val) { - zig_i128 tmp = zig_shr_i128(val, 127); - return zig_bitCast_u128(zig_sub_i128(zig_xor_i128(val, tmp), tmp)); +static inline zig_u128 zig_abs_i128(zig_i128 arg) { + zig_u128 tmp = zig_u128_bitCast_i128(zig_shr_i128(arg, 127), UINT8_C(128)); + return zig_sub_u128(zig_xor_u128(zig_u128_bitCast_i128(arg, UINT8_C(128)), tmp), tmp); } #if zig_has_int128 @@ -2160,7 +2466,7 @@ static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(add_overflow) zig_u128 full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_addw_u128(lhs, rhs, bits); @@ -2176,7 +2482,7 @@ static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = (zig_i128)((zig_u128)lhs + (zig_u128)rhs); bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } @@ -2184,7 +2490,7 @@ static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(sub_overflow) zig_u128 full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_subw_u128(lhs, rhs, bits); @@ -2200,7 +2506,7 @@ static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = (zig_i128)((zig_u128)lhs - (zig_u128)rhs); bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } @@ -2208,7 +2514,7 @@ static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(mul_overflow) zig_u128 full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_mulw_u128(lhs, rhs, bits); @@ -2216,8 +2522,8 @@ static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #endif } -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { + zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); #if zig_has_builtin(mul_overflow) zig_i128 full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -2226,50 +2532,78 @@ static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } #else /* zig_has_int128 */ static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + uint64_t lo; + bool overflow = zig_addo_u64(&lo, zig_u64_intCast_u128(lhs), zig_u64_intCast_u128(rhs), bits); + *res = zig_u128_intCast_u64(lo); + return overflow; + } else { + uint64_t hi; + bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + int64_t lo; + bool overflow = zig_addo_i64(&lo, zig_i64_intCast_i128(lhs), zig_i64_intCast_i128(rhs), bits); + *res = zig_i128_intCast_i64(lo); + return overflow; + } else { + int64_t hi; + bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + uint64_t lo; + bool overflow = zig_subo_u64(&lo, zig_u64_intCast_u128(lhs), zig_u64_intCast_u128(rhs), bits); + *res = zig_u128_intCast_u64(lo); + return overflow; + } else { + uint64_t hi; + bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + int64_t lo; + bool overflow = zig_subo_i64(&lo, zig_i64_intCast_i128(lhs), zig_i64_intCast_i128(rhs), bits); + *res = zig_i128_intCast_i64(lo); + return overflow; + } else { + int64_t hi; + bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { *res = zig_mulw_u128(lhs, rhs, bits); - return zig_cmp_u128(*res, zig_make_u128(0, 0)) != INT32_C(0) && - zig_cmp_u128(lhs, zig_div_trunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); + return zig_cmp_u128(rhs, zig_make_u128(0, 0)) != INT32_C(0) && + zig_cmp_u128(lhs, zig_divTrunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); } -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { + zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); int overflow_int; zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0 || zig_cmp_i128(full_res, zig_minInt_i(128, bits)) < INT32_C(0) || zig_cmp_i128(full_res, zig_maxInt_i(128, bits)) > INT32_C(0); - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow; } @@ -2282,28 +2616,54 @@ static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, uint8_t rhs, uint8 static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, uint8_t rhs, uint8_t bits) { *res = zig_shlw_i128(lhs, rhs, bits); - zig_i128 mask = zig_bitCast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1))); + zig_i128 mask = zig_i128_bitCast_u128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1)), bits); return zig_cmp_i128(zig_and_i128(lhs, mask), zig_make_i128(0, 0)) != INT32_C(0) && zig_cmp_i128(zig_and_i128(lhs, mask), mask) != INT32_C(0); } -static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { +#define zig_int128_shls_builtins(rw) \ + static inline zig_u128 zig_shls_u128_u##rw(zig_u128 lhs, uint##rw##_t rhs, uint8_t bits) { \ + zig_u128 res; \ + if (rhs < bits && !zig_shlo_u128(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + switch (zig_cmp_u128(lhs, zig_make_u128(UINT64_C(0), UINT64_C(0)))) { \ + case 0: return zig_minInt_u(128, bits); \ + case 1: return zig_maxInt_u(128, bits); \ + default: zig_unreachable(); \ + } \ + } \ +\ + static inline zig_i128 zig_shls_i128_u##rw(zig_i128 lhs, uint##rw##_t rhs, uint8_t bits) { \ + zig_i128 res; \ + if (rhs < bits && !zig_shlo_i128(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + switch (zig_cmp_i128(lhs, zig_make_i128(INT64_C(0), UINT64_C(0)))) { \ + case -1: return zig_minInt_i(128, bits); \ + case 0: return zig_make_i128(INT64_C(0), UINT64_C(0)); \ + case 1: return zig_maxInt_i(128, bits); \ + default: zig_unreachable(); \ + } \ + } +zig_int128_shls_builtins(8) +zig_int128_shls_builtins(16) +zig_int128_shls_builtins(32) +zig_int128_shls_builtins(64) + +static inline zig_u128 zig_shls_u128_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { zig_u128 res; if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_u128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits)) return res; switch (zig_cmp_u128(lhs, zig_make_u128(0, 0))) { - case 0: return zig_make_u128(0, 0); - case 1: return zig_maxInt_u(128, bits); + case INT32_C(0): return zig_make_u128(0, 0); + case INT32_C(1): return zig_maxInt_u(128, bits); default: zig_unreachable(); } } -static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_u128 rhs, uint8_t bits) { +static inline zig_i128 zig_shls_i128_u128(zig_i128 lhs, zig_u128 rhs, uint8_t bits) { zig_i128 res; if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_i128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits)) return res; switch (zig_cmp_i128(lhs, zig_make_i128(0, 0))) { - case -1: return zig_minInt_i(128, bits); - case 0: return zig_make_i128(0, 0); - case 1: return zig_maxInt_i(128, bits); + case -INT32_C(1): return zig_minInt_i(128, bits); + case INT32_C(0): return zig_make_i128(0, 0); + case INT32_C(1): return zig_maxInt_i(128, bits); default: zig_unreachable(); } } @@ -2341,57 +2701,60 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_make_i128(0, 0)) < INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits); } -static inline uint8_t zig_clz_u128(zig_u128 val, uint8_t bits) { - if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(val), bits); - if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - UINT8_C(64)); - return zig_clz_u64(zig_lo_u128(val), UINT8_C(64)) + (bits - UINT8_C(64)); +static inline uint8_t zig_clz_u128(zig_u128 arg, uint8_t bits) { + if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(arg), bits); + if (zig_hi_u128(arg) != 0) return zig_clz_u64(zig_hi_u128(arg), bits - UINT8_C(64)); + return zig_clz_u64(zig_lo_u128(arg), UINT8_C(64)) + (bits - UINT8_C(64)); } -static inline uint8_t zig_clz_i128(zig_i128 val, uint8_t bits) { - return zig_clz_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_clz_i128(zig_i128 arg, uint8_t bits) { + return zig_clz_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline uint8_t zig_ctz_u128(zig_u128 val, uint8_t bits) { - if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), UINT8_C(64)); - return zig_ctz_u64(zig_hi_u128(val), bits - UINT8_C(64)) + UINT8_C(64); +static inline uint8_t zig_ctz_u128(zig_u128 arg, uint8_t bits) { + if (zig_lo_u128(arg) != 0) return zig_ctz_u64(zig_lo_u128(arg), UINT8_C(64)); + return zig_ctz_u64(zig_hi_u128(arg), bits - UINT8_C(64)) + UINT8_C(64); } -static inline uint8_t zig_ctz_i128(zig_i128 val, uint8_t bits) { - return zig_ctz_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_ctz_i128(zig_i128 arg, uint8_t bits) { + return zig_ctz_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline uint8_t zig_popcount_u128(zig_u128 val, uint8_t bits) { - return zig_popcount_u64(zig_hi_u128(val), bits - UINT8_C(64)) + - zig_popcount_u64(zig_lo_u128(val), UINT8_C(64)); +static inline uint8_t zig_popCount_u128(zig_u128 arg, uint8_t bits) { + return (bits > UINT8_C(64) ? zig_popCount_u64(zig_hi_u128(arg), bits - UINT8_C(64)) : UINT8_C(0)) + + zig_popCount_u64(zig_lo_u128(arg), UINT8_C(64)); } -static inline uint8_t zig_popcount_i128(zig_i128 val, uint8_t bits) { - return zig_popcount_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_popCount_i128(zig_i128 arg, uint8_t bits) { + return zig_popCount_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline zig_u128 zig_byte_swap_u128(zig_u128 val, uint8_t bits) { +static inline zig_u128 zig_byteSwap_u128(zig_u128 arg, uint8_t bits) { zig_u128 full_res; #if zig_has_builtin(bswap128) - full_res = __builtin_bswap128(val); + full_res = __builtin_bswap128(arg); #else - full_res = zig_make_u128(zig_byte_swap_u64(zig_lo_u128(val), UINT8_C(64)), - zig_byte_swap_u64(zig_hi_u128(val), UINT8_C(64))); + full_res = zig_make_u128( + zig_byteSwap_u64(zig_lo_u128(arg), UINT8_C(64)), + zig_byteSwap_u64(zig_hi_u128(arg), UINT8_C(64)) + ); #endif return zig_shr_u128(full_res, UINT8_C(128) - bits); } -static inline zig_i128 zig_byte_swap_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_byte_swap_u128(zig_bitCast_u128(val), bits)); +static inline zig_i128 zig_byteSwap_i128(zig_i128 arg, uint8_t bits) { + return zig_i128_bitCast_u128(zig_byteSwap_u128(zig_u128_bitCast_i128(arg, bits), bits), bits); } -static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, uint8_t bits) { - return zig_shr_u128(zig_make_u128(zig_bit_reverse_u64(zig_lo_u128(val), UINT8_C(64)), - zig_bit_reverse_u64(zig_hi_u128(val), UINT8_C(64))), - UINT8_C(128) - bits); +static inline zig_u128 zig_bitReverse_u128(zig_u128 arg, uint8_t bits) { + return zig_shr_u128(zig_make_u128( + zig_bitReverse_u64(zig_lo_u128(arg), UINT8_C(64)), + zig_bitReverse_u64(zig_hi_u128(arg), UINT8_C(64)) + ), UINT8_C(128) - bits); } -static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_bit_reverse_u128(zig_bitCast_u128(val), bits)); +static inline zig_i128 zig_bitReverse_i128(zig_i128 arg, uint8_t bits) { + return zig_i128_bitCast_u128(zig_bitReverse_u128(zig_u128_bitCast_i128(arg, bits), bits), bits); } #if zig_has_int128 @@ -2411,12 +2774,378 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { /* ========================== Big Integer Support =========================== */ static inline uint16_t zig_int_bytes(uint16_t bits) { - uint16_t bytes = (bits + CHAR_BIT - 1) / CHAR_BIT; + uint16_t bytes = (bits - UINT16_C(1)) / CHAR_BIT + UINT16_C(1); uint16_t alignment = ZIG_TARGET_MAX_INT_ALIGNMENT; + while (alignment / 2 >= bytes) alignment /= 2; return (bytes + alignment - 1) / alignment * alignment; } +static inline void zig_minInt_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + + if (is_signed) { + int8_t signed_sign_byte = zig_minInt_i(8, remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_minInt_u(8, remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memset(&res_bytes[0], zig_minInt_u8, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + byte_offset = size - UINT16_C(1) - byte_offset; + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], zig_minInt_u8, size - byte_offset); +#endif +} + +static inline void zig_maxInt_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + + if (is_signed) { + int8_t signed_sign_byte = zig_maxInt_i(8, remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_maxInt_u(8, remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memset(&res_bytes[0], zig_maxInt_u8, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + byte_offset = size - UINT16_C(1) - byte_offset; + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], zig_maxInt_u8, size - byte_offset); +#endif +} + +static inline int8_t zig_signFill_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + + if (!is_signed) return INT8_C(0); +#if zig_little_endian + byte_offset = zig_int_bytes(bits) - 1; +#endif + return zig_shr_i8(zig_i8_bitCast_u8(arg_bytes[byte_offset], UINT8_C(8)), UINT8_C(7)); +} + +static inline void zig_big_intCast_big(void *res, const void *arg, bool res_is_signed, uint16_t res_bits, bool arg_is_signed, uint16_t arg_bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_size = zig_int_bytes(res_bits); + uint16_t arg_size = zig_int_bytes(arg_bits); + uint16_t copy_size = zig_min_u16(res_size, arg_size); + uint8_t sign_fill = zig_u8_bitCast_i8(zig_signFill_big(arg, arg_is_signed, arg_bits), UINT8_C(8)); + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], copy_size); + memset(&res_bytes[copy_size], sign_fill, res_size - copy_size); +#else + memset(&res_bytes[0], sign_fill, res_size - copy_size); + memcpy(&res_bytes[res_size - copy_size], &arg_bytes[arg_size - copy_size], copy_size); +#endif +} + +static inline void zig_big_truncate_big(void *res, const void *arg, bool res_is_signed, uint16_t res_bits, bool arg_is_signed, uint16_t arg_bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_size = zig_int_bytes(res_bits); + + if (res_is_signed != arg_is_signed) zig_unreachable(); + if (res_bits > arg_bits) zig_unreachable(); + + if (res_is_signed) { + uint16_t arg_byte_offset = UINT16_C(0); + +#if zig_big_endian + arg_byte_offset = zig_int_bytes(arg_bits) - res_size; +#endif + + memcpy(&res_bytes[0], &arg_bytes[arg_byte_offset], res_size); + } else { + uint16_t res_byte_offset = zig_shr_u16(res_bits - UINT16_C(1), UINT8_C(3)); + uint16_t arg_byte_offset = res_byte_offset; + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], res_byte_offset); +#else + res_byte_offset = res_size - UINT16_C(1) - res_byte_offset; + arg_byte_offset = zig_int_bytes(arg_bits) - UINT16_C(1) - arg_byte_offset; + + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#endif + + res_bytes[res_byte_offset] = zig_u8_truncate_u8( + arg_bytes[arg_byte_offset], + zig_u8_truncate_u8(res_bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1) + ); + res_byte_offset += UINT16_C(1); + arg_byte_offset += UINT16_C(1); + +#if zig_little_endian + memset(&res_bytes[res_byte_offset], zig_minInt_u8, res_size - res_byte_offset); +#else + memcpy(&res_bytes[res_byte_offset], &arg_bytes[arg_byte_offset], res_size - res_byte_offset); +#endif + } +} + +#define zig_big_casts(is, s, w, IntType) \ + static inline IntType zig_##s##w##_intCast_big(const void *arg, bool arg_is_signed, uint16_t arg_bits) { \ + IntType res; \ + zig_big_intCast_big(&res, arg, is, w, arg_is_signed, arg_bits); \ + return res; \ + } \ +\ + static inline void zig_big_intCast_##s##w(void *res, IntType arg, bool res_is_signed, uint16_t res_bits) { \ + zig_big_intCast_big(res, &arg, res_is_signed, res_bits, is, w); \ + } \ +\ + static inline IntType zig_##s##w##_truncate_big(const void *arg, uint8_t res_bits, bool arg_is_signed, uint16_t arg_bits) { \ + IntType res; \ + zig_big_truncate_big(&res, arg, is, res_bits, arg_is_signed, arg_bits); \ + return res; \ + } \ +\ + static inline void zig_big_truncate_##s##w(void *res, IntType arg, bool res_is_signed, uint16_t res_bits) { \ + zig_big_truncate_big(res, &arg, res_is_signed, res_bits, is, w); \ + } +zig_big_casts(false, u, 8, uint8_t) +zig_big_casts(true , i, 8, int8_t) +zig_big_casts(false, u, 16, uint16_t) +zig_big_casts(true , i, 16, int16_t) +zig_big_casts(false, u, 32, uint32_t) +zig_big_casts(true , i, 32, int32_t) +zig_big_casts(false, u, 64, uint64_t) +zig_big_casts(true , i, 64, int64_t) +zig_big_casts(false, u, 128, zig_u128) +zig_big_casts(true , i, 128, zig_i128) + +static inline void zig_big_bitCast_big(void *res, const void *arg, bool res_is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + +#if zig_big_endian + byte_offset = size - UINT16_C(1) - byte_offset; +#endif + + if (res_is_signed) { + int8_t signed_sign_byte = zig_i8_bitCast_u8(arg_bytes[byte_offset], remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_u8_bitCast_u8(arg_bytes[byte_offset], remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memcpy(&res_bytes[byte_offset], &arg_bytes[byte_offset], size - byte_offset); +#endif +} + +static inline int32_t zig_cmp_big_u8(const void *lhs, uint8_t rhs, bool is_signed, uint16_t bits) { + const uint8_t *lhs_bytes = lhs; + uint16_t byte_offset = 0; + bool do_signed = is_signed; + uint16_t remaining_bytes = zig_int_bytes(bits); + +#if zig_little_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 128 / CHAR_BIT ? rhs : UINT8_C(0); + int32_t limb_cmp; + +#if zig_little_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + if (do_signed) { + zig_i128 lhs_limb; + zig_i128 rhs_limb = zig_i128_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + limb_cmp = zig_cmp_i128(lhs_limb, rhs_limb); + do_signed = false; + } else { + zig_u128 lhs_limb; + zig_u128 rhs_limb = zig_u128_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + limb_cmp = zig_cmp_u128(lhs_limb, rhs_limb); + } + + if (limb_cmp != 0) return limb_cmp; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 64 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + if (do_signed) { + int64_t lhs_limb; + int64_t rhs_limb = zig_i64_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint64_t lhs_limb; + uint64_t rhs_limb = zig_u64_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 32 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + if (do_signed) { + int32_t lhs_limb; + int32_t rhs_limb = zig_i32_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint32_t lhs_limb; + uint32_t rhs_limb = zig_u32_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 16 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + if (do_signed) { + int16_t lhs_limb; + int16_t rhs_limb = zig_i16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint16_t lhs_limb; + uint16_t rhs_limb = zig_u16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 16 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + if (do_signed) { + int8_t lhs_limb; + int16_t lhs_cmp_limb; + int16_t rhs_cmp_limb = zig_i16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + lhs_cmp_limb = zig_i16_intCast_i8(lhs_limb); + if (lhs_cmp_limb != rhs_cmp_limb) return (lhs_cmp_limb > rhs_cmp_limb) - (lhs_cmp_limb < rhs_cmp_limb); + do_signed = false; + } else { + uint8_t lhs_limb; + uint8_t rhs_limb = rhs_byte; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return 0; +} + static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { const uint8_t *lhs_bytes = lhs; const uint8_t *rhs_bytes = rhs; @@ -2579,6 +3308,168 @@ static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_sign return 0; } +static inline void zig_not_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + if (remaining_bytes != 128 / CHAR_BIT || is_signed) { + zig_i128 res_limb; + zig_i128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i128(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + zig_u128 res_limb; + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u128(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + if (remaining_bytes != 64 / CHAR_BIT || is_signed) { + int64_t res_limb; + int64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i64(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint64_t res_limb; + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u64(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + if (remaining_bytes != 32 / CHAR_BIT || is_signed) { + int32_t res_limb; + int32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i32(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint32_t res_limb; + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u32(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + if (remaining_bytes != 16 / CHAR_BIT || is_signed) { + int16_t res_limb; + int16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i16(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint16_t res_limb; + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u16(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + if (remaining_bytes != 8 / CHAR_BIT || is_signed) { + int8_t res_limb; + int8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i8(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint8_t res_limb; + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u8(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + static inline void zig_and_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { uint8_t *res_bytes = res; const uint8_t *lhs_bytes = lhs; @@ -2816,13 +3707,415 @@ static inline void zig_xor_big(void *res, const void *lhs, const void *rhs, bool } } +static inline void zig_increment_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u128(&res_limb, res_limb, zig_make_u128(UINT64_C(0), UINT64_C(1)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u64(&res_limb, res_limb, UINT64_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u32(&res_limb, res_limb, UINT32_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u16(&res_limb, res_limb, UINT16_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u8(&res_limb, res_limb, UINT8_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_decrement_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u128(&res_limb, res_limb, zig_make_u128(UINT64_C(0), UINT64_C(1)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u64(&res_limb, res_limb, UINT64_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u32(&res_limb, res_limb, UINT32_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u16(&res_limb, res_limb, UINT16_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u8(&res_limb, res_limb, UINT8_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_abs_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + if (zig_signFill_big(arg, is_signed, bits) >= INT8_C(0)) { + memcpy(res, arg, remaining_bytes); + return; + } + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + bool overflow = true; + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u128(&res_limb, zig_not_u128(arg_limb, UINT8_C(128)), zig_make_u128(UINT64_C(0), overflow ? UINT64_C(1) : UINT64_C(0)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u64(&res_limb, zig_not_u64(arg_limb, UINT8_C(64)), overflow ? UINT64_C(1) : UINT64_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u32(&res_limb, zig_not_u32(arg_limb, UINT8_C(32)), overflow ? UINT32_C(1) : UINT32_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u16(&res_limb, zig_not_u16(arg_limb, UINT8_C(16)), overflow ? UINT16_C(1) : UINT16_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u8(&res_limb, zig_not_u8(arg_limb, UINT8_C(8)), overflow ? UINT8_C(1) : UINT8_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_min_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + memcpy(res, zig_cmp_big(lhs, rhs, is_signed, bits) < INT32_C(0) ? lhs : rhs, zig_int_bytes(bits)); +} + +static inline void zig_max_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + memcpy(res, zig_cmp_big(lhs, rhs, is_signed, bits) >= INT32_C(0) ? lhs : rhs, zig_int_bytes(bits)); +} + static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { uint8_t *res_bytes = res; const uint8_t *lhs_bytes = lhs; const uint8_t *rhs_bytes = rhs; uint16_t byte_offset = 0; uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); bool overflow = false; #if zig_big_endian @@ -3038,7 +4331,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo const uint8_t *rhs_bytes = rhs; uint16_t byte_offset = 0; uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); bool overflow = false; #if zig_big_endian @@ -3248,323 +4541,755 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo return overflow; } +static inline void zig_add_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_addo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow +} + static inline void zig_addw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { (void)zig_addo_big(res, lhs, rhs, is_signed, bits); } +static inline void zig_adds_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = zig_signFill_big(lhs, is_signed, bits); + + if (!zig_addo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); + } +} + +static inline void zig_sub_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_subo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow +} + static inline void zig_subw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { (void)zig_subo_big(res, lhs, rhs, is_signed, bits); } -zig_extern void __udivei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_div_trunc_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __udivei4(res, lhs, rhs, bits); - return; - } +static inline void zig_subs_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = is_signed ? zig_signFill_big(lhs, is_signed, bits) : -INT8_C(1); - zig_trap(); + if (!zig_subo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); + } } -static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_div_trunc_big(res, lhs, rhs, is_signed, bits); - return; +static inline bool zig_mulo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + const uint8_t *rhs_bytes = rhs; + uint16_t size = zig_int_bytes(bits); + uint16_t sign_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t lhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(lhs, is_signed, bits), UINT8_C(8)); + uint8_t rhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(rhs, is_signed, bits), UINT8_C(8)); + uint16_t lhs_byte_offset = sign_byte_offset; + uint16_t lhs_end_byte_offset = UINT16_C(0); + bool overflow = false; + +#if zig_big_endian + lhs_byte_offset = size - lhs_byte_offset; + lhs_end_byte_offset = size - lhs_end_byte_offset; +#endif + + while (lhs_byte_offset != lhs_end_byte_offset) { + uint16_t rhs_byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint16_t res_byte_offset; + uint16_t lhs_byte; + uint8_t res_byte = UINT8_C(0); + uint16_t mul_res = UINT16_C(0); + uint8_t carry = UINT8_C(0); + +#if zig_little_endian + lhs_byte_offset -= UINT16_C(1); +#else + rhs_byte_offset = size - rhs_byte_offset; + end_byte_offset = size - end_byte_offset; +#endif + + lhs_byte = zig_u16_intCast_u8(lhs_bytes[lhs_byte_offset]) ^ lhs_sign_fill; + +#if zig_big_endian + lhs_byte_offset += UINT16_C(1); +#endif + + res_byte_offset = lhs_byte_offset; + + while (res_byte_offset != end_byte_offset) { + bool res_byte_initialized = res_byte_offset != lhs_byte_offset; + +#if zig_big_endian + rhs_byte_offset -= UINT16_C(1); + res_byte_offset -= UINT16_C(1); +#endif + + if (res_byte_initialized) res_byte = res_bytes[res_byte_offset]; + carry = zig_addo_u8(&res_byte, res_byte, carry, UINT8_C(8)); + carry += zig_addo_u8(&res_byte, res_byte, zig_u8_intCast_u16( + zig_shr_u16(mul_res, UINT8_C(8)) + ), UINT8_C(8)); + mul_res = lhs_byte * zig_u16_intCast_u8(rhs_bytes[rhs_byte_offset] ^ rhs_sign_fill); + carry += zig_addo_u8(&res_bytes[res_byte_offset], res_byte, zig_u8_truncate_u16( + mul_res, + UINT8_C(8) + ), UINT8_C(8)); + +#if zig_little_endian + rhs_byte_offset += UINT16_C(1); + res_byte_offset += UINT16_C(1); +#endif + } + + while (rhs_byte_offset != end_byte_offset) { +#if zig_big_endian + rhs_byte_offset -= UINT16_C(1); +#endif + + carry = zig_addo_u8( + &res_byte, + zig_u8_intCast_u16(zig_shr_u16(mul_res, UINT8_C(8))), + carry, + UINT8_C(8) + ); + mul_res = lhs_byte * zig_u16_intCast_u8(rhs_bytes[rhs_byte_offset] ^ rhs_sign_fill); + carry += zig_addo_u8(&res_byte, res_byte, zig_u8_truncate_u16( + mul_res, + UINT8_C(8) + ), UINT8_C(8)); + overflow |= res_byte != UINT8_C(0); + +#if zig_little_endian + rhs_byte_offset += UINT16_C(1); +#endif + } + + overflow |= zig_shr_u16(mul_res, UINT8_C(8)) != UINT16_C(0); + overflow |= carry != UINT8_C(0); } - zig_trap(); +#if zig_little_endian + sign_byte_offset -= UINT64_C(1); +#else + sign_byte_offset = size - sign_byte_offset; +#endif + + if (lhs_sign_fill != rhs_sign_fill) { + uint16_t byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint8_t res_byte; + int8_t signed_res_byte; + uint8_t carry = UINT8_C(0); + +#if zig_big_endian + byte_offset = size - byte_offset; + end_byte_offset += UINT16_C(1); +#endif + + while (byte_offset != end_byte_offset) { +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + carry = zig_subo_u8(&res_byte, UINT8_C(0), carry, UINT8_C(8)); + carry += zig_subo_u8(&res_byte, res_byte, res_bytes[byte_offset], UINT8_C(8)); + carry += zig_subo_u8( + &res_bytes[byte_offset], + res_byte, + (lhs_sign_fill == UINT8_C(0) ? lhs_bytes : rhs_bytes)[byte_offset], + UINT8_C(8) + ); + +#if zig_little_endian + byte_offset += UINT16_C(1); +#endif + } + +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + signed_res_byte = zig_i8_bitCast_u8(res_bytes[byte_offset], UINT8_C(8)); + overflow |= signed_res_byte < INT8_C(0); + overflow |= zig_subo_i8(&signed_res_byte, INT8_C(0), signed_res_byte, UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_intCast_u8(carry), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + (lhs_sign_fill == UINT8_C(0) ? lhs_bytes : rhs_bytes)[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + res_bytes[byte_offset] = zig_i8_bitCast_u8(signed_res_byte, UINT8_C(8)); + } else if (lhs_sign_fill != UINT8_C(0)) { + uint16_t byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint8_t res_byte; + int8_t signed_res_byte; + uint8_t carry = UINT8_C(1); + +#if zig_big_endian + byte_offset = size - byte_offset; + end_byte_offset += UINT16_C(1); +#endif + + while (byte_offset != end_byte_offset) { +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + carry = zig_subo_u8(&res_byte, res_bytes[byte_offset], carry, UINT8_C(8)); + carry += zig_subo_u8(&res_byte, res_byte, lhs_bytes[byte_offset], UINT8_C(8)); + carry += zig_subo_u8(&res_bytes[byte_offset], res_byte, rhs_bytes[byte_offset], UINT8_C(8)); + +#if zig_little_endian + byte_offset += UINT16_C(1); +#endif + } + +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + signed_res_byte = zig_i8_bitCast_u8(res_bytes[byte_offset], UINT8_C(8)); + overflow |= signed_res_byte < INT8_C(0); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_intCast_u8(carry), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + lhs_bytes[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + rhs_bytes[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + res_bytes[byte_offset] = zig_i8_bitCast_u8(signed_res_byte, UINT8_C(8)); + } else if (is_signed) { + int8_t signed_res_byte = zig_i8_bitCast_u8(res_bytes[sign_byte_offset], UINT8_C(8)); + + overflow |= signed_res_byte < INT8_C(0); + } + + { + uint8_t truncate_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t fill_byte = UINT8_C(0); + + if (is_signed) { + int8_t sign_byte = zig_i8_bitCast_u8(res_bytes[sign_byte_offset], UINT8_C(8)); + int8_t truncated = zig_i8_truncate_i8(sign_byte, truncate_bits); + + overflow |= sign_byte != truncated; + res_bytes[sign_byte_offset] = zig_u8_bitCast_i8(truncated, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(truncated, UINT8_C(7)), UINT8_C(8)); + } else { + uint8_t sign_byte = res_bytes[sign_byte_offset]; + uint8_t truncated = zig_u8_truncate_u8(sign_byte, truncate_bits); + + overflow |= sign_byte != truncated; + res_bytes[sign_byte_offset] = truncated; + } + +#if zig_little_endian + sign_byte_offset += UINT16_C(1); + memset(&res_bytes[sign_byte_offset], fill_byte, size - sign_byte_offset); +#else + memset(&res_bytes[0], fill_byte, sign_byte_offset); +#endif + } + + return overflow; +} + +static inline void zig_mul_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_mulo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow } -static inline void zig_div_ceil_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - zig_trap(); +static inline void zig_mulw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + (void)zig_mulo_big(res, lhs, rhs, is_signed, bits); } -zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __umodei4(res, lhs, rhs, bits); - return; +static inline void zig_muls_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = zig_signFill_big(lhs, is_signed, bits) ^ zig_signFill_big(rhs, is_signed, bits); + + if (!zig_mulo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); } +} + +static inline void zig_divTrunc_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + if (is_signed) { + zig_extern void __divei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __divei5(res, lhs, rhs, temp, bits); + } else { + zig_extern void __udivei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __udivei5(res, lhs, rhs, temp, bits); + } +} - zig_trap(); +static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + if (is_signed) { + zig_extern void __modei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __modei5(res, lhs, rhs, temp, bits); + } else { + zig_extern void __umodei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __umodei5(res, lhs, rhs, temp, bits); + } } -static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_rem_big(res, lhs, rhs, is_signed, bits); - return; +static inline void zig_divFloor_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool decrement = false; + + if (is_signed) { + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + decrement = zig_u32_bitCast_i32(zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ), UINT8_C(32)) > zig_u32_bitCast_i32(zig_minInt_i32, UINT8_C(32)); } + zig_divTrunc_big(res, lhs, rhs, temp, is_signed, bits); + if (decrement) zig_decrement_big(res, is_signed, bits); +} - zig_trap(); +static inline void zig_divCeil_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool increment = false; + + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + increment = zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ) > INT32_C(0); + zig_divTrunc_big(res, lhs, rhs, temp, is_signed, bits); + if (increment) zig_increment_big(res, is_signed, bits); } -static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t skip_bits = remaining_bytes * 8 - bits; - uint16_t total_lz = 0; - uint16_t limb_lz; - (void)is_signed; +static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool fixup = false; -#if zig_little_endian - byte_offset = remaining_bytes; + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + if (is_signed && zig_u32_bitCast_i32(zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ), UINT8_C(32)) > zig_u32_bitCast_i32(zig_minInt_i32, UINT8_C(32))) zig_add_big(res, res, rhs, is_signed, bits); +} + +static inline void zig_shr_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = UINT16_C(0); + uint16_t lhs_byte_offset = zig_shr_u16(rhs, UINT8_C(3)); + uint16_t end_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t lhs_prev_byte; + uint8_t byte_shift = zig_u8_truncate_u16(rhs, UINT8_C(3)); + +#if zig_big_endian + res_byte_offset = size - res_byte_offset; + lhs_byte_offset = size - lhs_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - while (remaining_bytes >= 128 / CHAR_BIT) { + { +#if zig_big_endian + lhs_byte_offset -= UINT16_C(1); +#endif + + lhs_prev_byte = lhs_bytes[lhs_byte_offset]; + #if zig_little_endian - byte_offset -= 128 / CHAR_BIT; + lhs_byte_offset += UINT16_C(1); +#endif + } + + while (lhs_byte_offset != end_byte_offset) { +#if zig_big_endian + res_byte_offset -= UINT16_C(1); + lhs_byte_offset -= UINT16_C(1); #endif { - zig_u128 val_limb; + uint8_t lhs_byte = lhs_bytes[lhs_byte_offset]; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u128(val_limb, 128 - skip_bits); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_prev_byte) + ), byte_shift)); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 128 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 128 / CHAR_BIT; +#if zig_little_endian + res_byte_offset += UINT16_C(1); + lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 64 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 64 / CHAR_BIT; + { + uint8_t lhs_sign_fill = UINT8_C(0); + +#if zig_big_endian + res_byte_offset -= UINT16_C(1); #endif - { - uint64_t val_limb; + if (is_signed) { + int8_t signed_byte = zig_i8_bitCast_u8(lhs_prev_byte, UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u64(val_limb, 64 - skip_bits); + res_bytes[res_byte_offset] = zig_shr_i8(signed_byte, byte_shift); + lhs_sign_fill = zig_u8_bitCast_i8(zig_shr_i8(signed_byte, UINT8_C(7)), UINT8_C(8)); + } else { + res_bytes[res_byte_offset] = zig_shr_u8(lhs_prev_byte, byte_shift); } - total_lz += limb_lz; - if (limb_lz < 64 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 64 / CHAR_BIT; +#if zig_little_endian + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], lhs_sign_fill, size - res_byte_offset); +#else + memset(&res_bytes[0], lhs_sign_fill, res_byte_offset); #endif } +} + +static inline bool zig_shlo_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + uint8_t lhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(lhs, is_signed, bits), UINT8_C(8)); + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t lhs_byte_offset = UINT16_C(0); + uint16_t end_byte_offset = res_byte_offset - UINT16_C(1) - zig_shr_u16(rhs, UINT8_C(3)); + uint8_t lhs_prev_byte = lhs_sign_fill; + uint8_t byte_shift = UINT8_C(8) - zig_u8_truncate_u16(rhs, UINT8_C(3)); + bool overflow = false; - while (remaining_bytes >= 32 / CHAR_BIT) { #if zig_little_endian - byte_offset -= 32 / CHAR_BIT; + lhs_byte_offset = size - lhs_byte_offset; +#else + res_byte_offset = size - res_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - { - uint32_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u32(val_limb, 32 - skip_bits); - } + while (lhs_byte_offset != end_byte_offset) { +#if zig_little_endian + lhs_byte_offset -= UINT16_C(1); +#endif - total_lz += limb_lz; - if (limb_lz < 32 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 32 / CHAR_BIT; + overflow |= lhs_prev_byte != lhs_sign_fill; + lhs_prev_byte = lhs_bytes[lhs_byte_offset]; #if zig_big_endian - byte_offset += 32 / CHAR_BIT; + lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 16 / CHAR_BIT) { #if zig_little_endian - byte_offset -= 16 / CHAR_BIT; + end_byte_offset = UINT16_C(0); +#else + end_byte_offset = size; +#endif + + { + bool lhs_more_bytes = lhs_byte_offset != end_byte_offset; + +#if zig_little_endian + if (lhs_more_bytes) lhs_byte_offset -= UINT16_C(1); #endif { - uint16_t val_limb; + uint8_t lhs_byte = UINT8_C(0); + + if (lhs_more_bytes) lhs_byte = lhs_bytes[lhs_byte_offset]; + + if (is_signed) { + int16_t shifted = zig_shr_i16(zig_or_i16( + zig_shl_i16(zig_i16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_i16_intCast_u8(lhs_byte) + ), byte_shift); + int8_t truncated = zig_i8_truncate_i16( + shifted, + zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1) + ); + uint8_t fill = zig_u8_bitCast_i8(zig_shr_i8(truncated, UINT8_C(7)), UINT8_C(8)); + + overflow |= zig_i16_intCast_i8(truncated) != shifted; +#if zig_little_endian + memset(&res_bytes[res_byte_offset], fill, size - res_byte_offset); + res_byte_offset -= UINT16_C(1); +#else + memset(&res_bytes[0], fill, res_byte_offset); +#endif + res_bytes[res_byte_offset] = zig_u8_bitCast_i8(truncated, UINT8_C(8)); + } else { + uint16_t shifted = zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_byte) + ), byte_shift); + uint8_t truncated = zig_u8_truncate_u16( + shifted, + zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1) + ); + + overflow |= zig_u16_intCast_u8(truncated) != shifted; +#if zig_little_endian + memset(&res_bytes[res_byte_offset], zig_minInt_u8, size - res_byte_offset); + res_byte_offset -= UINT16_C(1); +#else + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#endif + res_bytes[res_byte_offset] = truncated; + } - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u16(val_limb, 16 - skip_bits); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 16 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 16 / CHAR_BIT; - #if zig_big_endian - byte_offset += 16 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + if (lhs_more_bytes) lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 8 / CHAR_BIT) { + while (lhs_byte_offset != end_byte_offset) { #if zig_little_endian - byte_offset -= 8 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); + lhs_byte_offset -= UINT16_C(1); #endif { - uint8_t val_limb; + uint8_t lhs_byte = lhs_bytes[lhs_byte_offset]; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u8(val_limb, 8 - skip_bits); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_byte) + ), byte_shift)); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 8 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 8 / CHAR_BIT; - #if zig_big_endian - byte_offset += 8 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + lhs_byte_offset += UINT16_C(1); #endif } - return total_lz; -} + { +#if zig_little_endian + res_byte_offset -= UINT16_C(1); +#endif -static inline uint16_t zig_ctz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t total_tz = 0; - uint16_t limb_tz; - (void)is_signed; + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + byte_shift + )); #if zig_big_endian - byte_offset = remaining_bytes; + res_byte_offset += UINT16_C(1); #endif + } - while (remaining_bytes >= 128 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 128 / CHAR_BIT; +#if zig_little_endian + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#else + memset(&res_bytes[res_byte_offset], zig_minInt_u8, size - res_byte_offset); #endif - { - zig_u128 val_limb; + return overflow; +} - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u128(val_limb, 128); - } +static inline void zig_shl_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + if (zig_shlo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: left shift overflowed bits +} - total_tz += limb_tz; - if (limb_tz < 128) return total_tz; - remaining_bytes -= 128 / CHAR_BIT; +static inline void zig_shlw_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + (void)zig_shlo_big(res, lhs, rhs, is_signed, bits); +} -#if zig_little_endian - byte_offset += 128 / CHAR_BIT; -#endif +#define zig_big_shls_builtin(w) \ + static inline uint##w##_t zig_shls_u##w##_big(uint##w##_t lhs, const void *rhs, \ + uint8_t lhs_bits, bool rhs_is_signed, uint16_t rhs_bits) { \ + uint##w##_t res; \ + const uint8_t *rhs_bytes = rhs; \ + if (zig_cmp_big_u8(rhs, lhs_bits, rhs_is_signed, rhs_bits) < INT32_C(0) && \ + !zig_shlo_u##w(&res, lhs, rhs_bytes[0], lhs_bits)) return res; \ + return lhs == INT##w##_C(0) ? zig_minInt_u(w, lhs_bits) : zig_maxInt_u(w, lhs_bits); \ + } \ +\ + static inline int##w##_t zig_shls_i##w##_big(int##w##_t lhs, const void *rhs, \ + uint8_t lhs_bits, bool rhs_is_signed, uint16_t rhs_bits) { \ + int##w##_t res; \ + const uint8_t *rhs_bytes = rhs; \ + if (zig_cmp_big_u8(rhs, lhs_bits, rhs_is_signed, rhs_bits) < INT32_C(0) && \ + !zig_shlo_i##w(&res, lhs, rhs_bytes[0], lhs_bits)) return res; \ + return lhs == INT##w##_C(0) ? INT##w##_C(0) : \ + lhs < INT##w##_C(0) ? zig_minInt_i(w, lhs_bits) : zig_maxInt_i(w, lhs_bits); \ + } \ +\ + static inline void zig_shls_big_u##w(void *res, const void *lhs, uint##w##_t rhs, bool is_signed, uint16_t bits) { \ + const uint8_t *lhs_bytes = lhs; \ + if (rhs < bits && !zig_shlo_big(res, lhs, zig_u16_intCast_u##w(rhs), is_signed, bits)) return; \ + switch (zig_cmp_big_u8(lhs, UINT8_C(0), is_signed, bits)) { \ + case -INT32_C(1): return zig_minInt_big(res, is_signed, bits); \ + case INT32_C(0): return zig_minInt_big(res, false, bits); \ + case INT32_C(1): return zig_maxInt_big(res, is_signed, bits); \ + default: zig_unreachable(); \ + } \ } +zig_big_shls_builtin(8) +zig_big_shls_builtin(16) +zig_big_shls_builtin(32) +zig_big_shls_builtin(64) + +static inline void zig_byteSwap_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_byte_offset = UINT16_C(0); + uint16_t arg_byte_offset = bits / CHAR_BIT; + uint16_t end_byte_offset = UINT16_C(1); + uint16_t size = zig_int_bytes(bits); - while (remaining_bytes >= 64 / CHAR_BIT) { #if zig_big_endian - byte_offset -= 64 / CHAR_BIT; + res_byte_offset = size - res_byte_offset; + arg_byte_offset = size - arg_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - { - uint64_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u64(val_limb, 64); - } + while (arg_byte_offset != end_byte_offset) { +#if zig_little_endian + arg_byte_offset -= UINT16_C(1); +#else + res_byte_offset -= UINT16_C(1); +#endif - total_tz += limb_tz; - if (limb_tz < 64) return total_tz; - remaining_bytes -= 64 / CHAR_BIT; + res_bytes[res_byte_offset] = arg_bytes[arg_byte_offset]; #if zig_little_endian - byte_offset += 64 / CHAR_BIT; + res_byte_offset += UINT16_C(1); +#else + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 32 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 32 / CHAR_BIT; + { +#if zig_little_endian + arg_byte_offset -= UINT16_C(1); +#else + res_byte_offset -= UINT16_C(1); #endif { - uint32_t val_limb; + uint8_t byte = arg_bytes[arg_byte_offset]; + uint8_t fill = is_signed + ? zig_u8_bitCast_i8(zig_shr_i8(zig_i8_bitCast_u8(byte, UINT8_C(8)), UINT8_C(7)), UINT8_C(8)) + : UINT8_C(0); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u32(val_limb, 32); + res_bytes[res_byte_offset] = byte; + +#if zig_little_endian + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], fill, size - res_byte_offset); +#else + memset(&res_bytes[0], fill, res_byte_offset); +#endif } + } +} - total_tz += limb_tz; - if (limb_tz < 32) return total_tz; - remaining_bytes -= 32 / CHAR_BIT; +static inline void zig_bitReverse_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = UINT16_C(0); + uint16_t arg_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t end_byte_offset = UINT16_C(0); + uint8_t arg_prev_byte; + uint8_t byte_shift = zig_u8_intCast_u16(zig_subw_u16(UINT16_C(0), bits, UINT8_C(3))); + +#if zig_big_endian + res_byte_offset = size - res_byte_offset; + arg_byte_offset = size - arg_byte_offset; + end_byte_offset = size - end_byte_offset; +#endif + { #if zig_little_endian - byte_offset += 32 / CHAR_BIT; + arg_byte_offset -= UINT16_C(1); +#endif + + arg_prev_byte = zig_bitReverse_u8(arg_bytes[arg_byte_offset], UINT8_C(8)); + +#if zig_big_endian + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 16 / CHAR_BIT) { + while (arg_byte_offset != end_byte_offset) { #if zig_big_endian - byte_offset -= 16 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); +#else + arg_byte_offset -= UINT16_C(1); #endif { - uint16_t val_limb; + uint8_t arg_byte = zig_bitReverse_u8(arg_bytes[arg_byte_offset], UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u16(val_limb, 16); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(arg_byte), UINT8_C(8)), + zig_u16_intCast_u8(arg_prev_byte) + ), byte_shift)); + arg_prev_byte = arg_byte; } - total_tz += limb_tz; - if (limb_tz < 16) return total_tz; - remaining_bytes -= 16 / CHAR_BIT; - #if zig_little_endian - byte_offset += 16 / CHAR_BIT; + res_byte_offset += UINT16_C(1); +#else + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 8 / CHAR_BIT) { + { + uint8_t arg_sign_fill = UINT8_C(0); + #if zig_big_endian - byte_offset -= 8 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); #endif - { - uint8_t val_limb; + if (is_signed) { + int8_t signed_byte = zig_i8_bitCast_u8(arg_prev_byte, UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u8(val_limb, 8); + res_bytes[res_byte_offset] = zig_shr_i8(signed_byte, byte_shift); + arg_sign_fill = zig_u8_bitCast_i8(zig_shr_i8(signed_byte, UINT8_C(7)), UINT8_C(8)); + } else { + res_bytes[res_byte_offset] = zig_shr_u8(arg_prev_byte, byte_shift); } - total_tz += limb_tz; - if (limb_tz < 8) return total_tz; - remaining_bytes -= 8 / CHAR_BIT; - #if zig_little_endian - byte_offset += 8 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], arg_sign_fill, size - res_byte_offset); +#else + memset(&res_bytes[0], arg_sign_fill, res_byte_offset); #endif } - - return total_tz; } -static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; +static inline uint16_t zig_popCount_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); + uint16_t remaining_bytes = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); uint16_t total_pc = 0; (void)is_signed; #if zig_big_endian - byte_offset = remaining_bytes; + byte_offset = zig_int_bytes(bits); #endif while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 128 / CHAR_BIT; #endif { - zig_u128 val_limb; + zig_u128 arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u128(val_limb, 128); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 128 / CHAR_BIT; @@ -3575,15 +5300,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 64 / CHAR_BIT; #endif { - uint64_t val_limb; + uint64_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u64(val_limb, 64); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 64 / CHAR_BIT; @@ -3594,15 +5321,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 32 / CHAR_BIT; #endif { - uint32_t val_limb; + uint32_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u32(val_limb, 32); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 32 / CHAR_BIT; @@ -3613,15 +5342,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 16 / CHAR_BIT; #endif { - uint16_t val_limb; + uint16_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u16(val_limb, 16); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 16 / CHAR_BIT; @@ -3632,15 +5363,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 8 / CHAR_BIT; #endif { - uint8_t val_limb; + uint8_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u8(val_limb, 8); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 8 / CHAR_BIT; @@ -3653,6 +5386,274 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ return total_pc; } +static inline uint16_t zig_ctz_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = UINT16_C(0); + uint16_t remaining_bytes = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + uint16_t total_tz = UINT16_C(0); + uint16_t limb_tz; + (void)is_signed; + +#if zig_big_endian + byte_offset = zig_int_bytes(bits); +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return total_tz; +} + +static inline uint16_t zig_clz_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t remaining_bytes = byte_offset; + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + bool sign_limb = true; + uint16_t total_lz = UINT16_C(0); + uint16_t limb_lz; + (void)is_signed; + +#if zig_big_endian + byte_offset = zig_int_bytes(bits) - remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(128) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(64) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(32) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(16) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(8) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return total_lz; +} + /* ========================= Floating Point Support ========================= */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ @@ -3687,29 +5688,29 @@ long double __cdecl nanl(char const* input); #define zig_make_special_f80(sign, name, arg, repr) sign zig_make_f80 (__builtin_##name, )(arg) #define zig_make_special_f128(sign, name, arg, repr) sign zig_make_f128(__builtin_##name, )(arg) #else -#define zig_make_special_f16(sign, name, arg, repr) zig_bitCast_f16 (repr) -#define zig_make_special_f32(sign, name, arg, repr) zig_bitCast_f32 (repr) -#define zig_make_special_f64(sign, name, arg, repr) zig_bitCast_f64 (repr) -#define zig_make_special_f80(sign, name, arg, repr) zig_bitCast_f80 (repr) -#define zig_make_special_f128(sign, name, arg, repr) zig_bitCast_f128(repr) +#define zig_make_special_f16(sign, name, arg, repr) zig_f16_bitCast_u16 (repr) +#define zig_make_special_f32(sign, name, arg, repr) zig_f32_bitCast_u32 (repr) +#define zig_make_special_f64(sign, name, arg, repr) zig_f64_bitCast_u64 (repr) +#define zig_make_special_f80(sign, name, arg, repr) zig_f80_bitCast_u128(repr) +#define zig_make_special_f128(sign, name, arg, repr) zig_f128_bitCast_u128(repr) #endif #define zig_has_f16 1 #define zig_libc_name_f16(name) __##name##h #define zig_init_special_f16(sign, name, arg, repr) zig_make_special_f16(sign, name, arg, repr) -#if FLT_MANT_DIG == 11 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && FLT_MANT_DIG == 11 typedef float zig_f16; #define zig_make_f16(fp, repr) fp##f -#elif DBL_MANT_DIG == 11 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && DBL_MANT_DIG == 11 typedef double zig_f16; #define zig_make_f16(fp, repr) fp -#elif LDBL_MANT_DIG == 11 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && LDBL_MANT_DIG == 11 typedef long double zig_f16; #define zig_make_f16(fp, repr) fp##l -#elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gcc)) +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gcc)) typedef _Float16 zig_f16; #define zig_make_f16(fp, repr) fp##f16 -#elif defined(__SIZEOF_FP16__) +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && defined(__SIZEOF_FP16__) typedef __fp16 zig_f16; #define zig_make_f16(fp, repr) fp##f16 #else @@ -3723,11 +5724,6 @@ typedef uint16_t zig_f16; #undef zig_init_special_f16 #define zig_init_special_f16(sign, name, arg, repr) repr #endif -#if defined(zig_darwin) && defined(zig_x86) -typedef uint16_t zig_compiler_rt_f16; -#else -typedef zig_f16 zig_compiler_rt_f16; -#endif #define zig_has_f32 1 #define zig_libc_name_f32(name) name##f @@ -3736,16 +5732,16 @@ typedef zig_f16 zig_compiler_rt_f16; #else #define zig_init_special_f32(sign, name, arg, repr) zig_make_special_f32(sign, name, arg, repr) #endif -#if FLT_MANT_DIG == 24 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && FLT_MANT_DIG == 24 typedef float zig_f32; #define zig_make_f32(fp, repr) fp##f -#elif DBL_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && DBL_MANT_DIG == 24 typedef double zig_f32; #define zig_make_f32(fp, repr) fp -#elif LDBL_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && LDBL_MANT_DIG == 24 typedef long double zig_f32; #define zig_make_f32(fp, repr) fp##l -#elif FLT32_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && FLT32_MANT_DIG == 24 typedef _Float32 zig_f32; #define zig_make_f32(fp, repr) fp##f32 #else @@ -3768,19 +5764,19 @@ typedef uint32_t zig_f32; #else #define zig_init_special_f64(sign, name, arg, repr) zig_make_special_f64(sign, name, arg, repr) #endif -#if FLT_MANT_DIG == 53 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT_MANT_DIG == 53 typedef float zig_f64; #define zig_make_f64(fp, repr) fp##f -#elif DBL_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && DBL_MANT_DIG == 53 typedef double zig_f64; #define zig_make_f64(fp, repr) fp -#elif LDBL_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && LDBL_MANT_DIG == 53 typedef long double zig_f64; #define zig_make_f64(fp, repr) fp##l -#elif FLT64_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT64_MANT_DIG == 53 typedef _Float64 zig_f64; #define zig_make_f64(fp, repr) fp##f64 -#elif FLT32X_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT32X_MANT_DIG == 53 typedef _Float32x zig_f64; #define zig_make_f64(fp, repr) fp##f32x #else @@ -3798,7 +5794,14 @@ typedef uint64_t zig_f64; #define zig_has_f80 1 #define zig_libc_name_f80(name) __##name##x #define zig_init_special_f80(sign, name, arg, repr) zig_make_special_f80(sign, name, arg, repr) -#if FLT_MANT_DIG == 64 +#ifdef ZIG_TARGET_SOFT_COMPILER_RT_F80_ABI +#undef zig_has_f80 +typedef struct { uint64_t mantissa; uint16_t exponent; } zig_f80; +#define zig_init_repr_f80(mantissa, exponent) { .mant##issa = mantissa, .expo##nent = exponent } +#define zig_make_repr_f80(mantissa, exponent) (zig_f80)zig_init_repr_f80(mantissa, exponent) +#define zig_mantissa_repr_f80(arg) (arg).mantissa +#define zig_exponent_repr_f80(arg) (arg).exponent +#elif FLT_MANT_DIG == 64 typedef float zig_f80; #define zig_make_f80(fp, repr) fp##f #elif DBL_MANT_DIG == 64 @@ -3818,68 +5821,91 @@ typedef __float80 zig_f80; #define zig_make_f80(fp, repr) fp##l #else #undef zig_has_f80 -#define zig_has_f80 0 -#define zig_repr_f80 u128 typedef zig_u128 zig_f80; +#define zig_init_repr_f80(mantissa, exponent) zig_init_u128(exponent, mantissa) +#define zig_make_repr_f80(mantissa, exponent) zig_make_u128(exponent, mantissa) +#define zig_mantissa_repr_f80(arg) zig_lo_u128(arg) +#define zig_exponent_repr_f80(arg) (uint16_t)zig_hi_u128(arg) +#endif +#ifndef zig_has_f80 +#define zig_has_f80 0 #define zig_make_f80(fp, repr) repr +#ifndef zig_make_repr_f80 +#define zig_make_repr_f80(mantissa, exponent) (zig_f80)zig_init_repr_f80(mantissa, exponent) +#endif #undef zig_make_special_f80 #define zig_make_special_f80(sign, name, arg, repr) repr #undef zig_init_special_f80 #define zig_init_special_f80(sign, name, arg, repr) repr #endif -#if defined(zig_gcc) && defined(zig_x86) -#define zig_f128_has_miscompilations 1 -#else -#define zig_f128_has_miscompilations 0 -#endif - #define zig_has_f128 1 -#define zig_libc_name_f128(name) name##q +#define zig_libc_name_f128(name) name##f128 #define zig_init_special_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr) -#if !zig_f128_has_miscompilations && FLT_MANT_DIG == 113 +#ifdef ZIG_TARGET_SOFT_COMPILER_RT_F128_ABI +#undef zig_has_f128 +#if zig_little_endian +typedef struct { uint64_t lo, hi; } zig_f128; +#else +typedef struct { uint64_t hi, lo; } zig_f128; +#endif +#define zig_init_repr_f128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_lo_repr_f128(arg) (arg).lo +#define zig_hi_repr_f128(arg) (arg).hi +#elif FLT_MANT_DIG == 113 typedef float zig_f128; #define zig_make_f128(fp, repr) fp##f -#elif !zig_f128_has_miscompilations && DBL_MANT_DIG == 113 +#elif DBL_MANT_DIG == 113 typedef double zig_f128; #define zig_make_f128(fp, repr) fp -#elif !zig_f128_has_miscompilations && LDBL_MANT_DIG == 113 +#elif LDBL_MANT_DIG == 113 typedef long double zig_f128; #define zig_make_f128(fp, repr) fp##l -#elif !zig_f128_has_miscompilations && FLT128_MANT_DIG == 113 +#elif FLT128_MANT_DIG == 113 typedef _Float128 zig_f128; #define zig_make_f128(fp, repr) fp##f128 -#elif !zig_f128_has_miscompilations && FLT64X_MANT_DIG == 113 +#elif FLT64X_MANT_DIG == 113 typedef _Float64x zig_f128; #define zig_make_f128(fp, repr) fp##f64x -#elif !zig_f128_has_miscompilations && defined(__SIZEOF_FLOAT128__) +#elif defined(__SIZEOF_FLOAT128__) typedef __float128 zig_f128; #define zig_make_f128(fp, repr) fp##q #undef zig_make_special_f128 #define zig_make_special_f128(sign, name, arg, repr) sign __builtin_##name##f128(arg) #else #undef zig_has_f128 -#define zig_has_f128 0 -#undef zig_make_special_f128 -#undef zig_init_special_f128 -#if defined(zig_darwin) || defined(zig_aarch64) -typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_v2u64; -zig_basic_operator(zig_v2u64, xor_v2u64, ^) -#define zig_repr_f128 v2u64 -typedef zig_v2u64 zig_f128; -#define zig_make_f128_zig_make_u128(hi, lo) (zig_f128){ lo, hi } -#define zig_make_f128_zig_init_u128 zig_make_f128_zig_make_u128 -#define zig_make_f128(fp, repr) zig_make_f128_##repr -#define zig_make_special_f128(sign, name, arg, repr) zig_make_f128_##repr -#define zig_init_special_f128(sign, name, arg, repr) zig_make_f128_##repr +#if defined(zig_x86_64) && defined(ZIG_TARGET_ABI_MSVC) +#if defined(zig_msvc) && !defined(__clang__) +#include +typedef __m128i zig_f128; +#define zig_init_repr_f128(hi, lo) { .m128i_u64 = { lo, hi } } +#define zig_lo_repr_f128(arg) (arg).m128i_u64[0] +#define zig_hi_repr_f128(arg) (arg).m128i_u64[1] +#else +typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_f128; +#define zig_init_repr_f128(hi, lo) { lo, hi } +#define zig_lo_repr_f128(arg) (arg)[0] +#define zig_hi_repr_f128(arg) (arg)[1] +#endif #else -#define zig_repr_f128 u128 typedef zig_u128 zig_f128; +#define zig_init_repr_f128(hi, lo) zig_init_u128(hi, lo) +#define zig_make_repr_f128(hi, lo) zig_make_u128(hi, lo) +#define zig_lo_repr_f128(arg) zig_lo_u128(arg) +#define zig_hi_repr_f128(arg) zig_hi_u128(arg) +#endif +#endif +#ifndef zig_has_f128 +#define zig_has_f128 0 #define zig_make_f128(fp, repr) repr +#ifndef zig_make_repr_f128 +#define zig_make_repr_f128(hi, lo) (zig_f128)zig_init_repr_f128(hi, lo) +#endif +#undef zig_make_special_f128 #define zig_make_special_f128(sign, name, arg, repr) repr +#undef zig_init_special_f128 #define zig_init_special_f128(sign, name, arg, repr) repr #endif -#endif #if !defined(zig_msvc) && defined(ZIG_TARGET_ABI_MSVC) /* Emulate msvc abi on a gnu compiler */ @@ -3892,84 +5918,141 @@ typedef zig_f128 zig_c_longdouble; typedef long double zig_c_longdouble; #endif -#define zig_bitCast_float(Type, ReprType) \ - static inline zig_##Type zig_bitCast_##Type(ReprType repr) { \ - zig_##Type result; \ - memcpy(&result, &repr, sizeof(result)); \ - return result; \ +#if __AVR__ +typedef signed char zig_FloatCompareResult; +#elif defined(zig_aarch64) +typedef signed int zig_FloatCompareResult; +#elif __SIZEOF_LONG__ >= __SIZEOF_POINTER__ +typedef signed long zig_FloatCompareResult; +#else +typedef signed long long zig_FloatCompareResult; +#endif + +#define zig_bitCast_float(w, iw, UnsignedReprType, SignedReprType) \ + static inline zig_f##w zig_f##w##_bitCast_u##iw(UnsignedReprType arg) { \ + zig_f##w res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return res; \ + } \ + static inline zig_f##w zig_f##w##_bitCast_i##iw(SignedReprType arg) { \ + zig_f##w res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return res; \ + } \ + static inline UnsignedReprType zig_u##iw##_bitCast_f##w(zig_f##w arg) { \ + UnsignedReprType res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return zig_u##iw##_truncate_u##iw(res, w); \ + } \ + static inline SignedReprType zig_i##iw##_bitCast_f##w(zig_f##w arg) { \ + SignedReprType res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return zig_i##iw##_truncate_i##iw(res, w); \ + } +zig_bitCast_float(16, 16, uint16_t, int16_t) +zig_bitCast_float(32, 32, uint32_t, int32_t) +zig_bitCast_float(64, 64, uint64_t, int64_t) +#if zig_has_f80 +zig_bitCast_float(80, 128, zig_u128, zig_i128) +#else +static inline zig_f80 zig_f80_bitCast_u128(zig_u128 arg) { + return zig_make_repr_f80(zig_lo_u128(arg), (uint16_t)zig_hi_u128(arg)); +} +static inline zig_f80 zig_f80_bitCast_i128(zig_i128 arg) { + return zig_make_repr_f80(zig_lo_i128(arg), (uint16_t)zig_hi_i128(arg)); +} +static inline zig_u128 zig_u128_bitCast_f80(zig_f80 arg) { + return zig_make_u128(zig_exponent_repr_f80(arg), zig_mantissa_repr_f80(arg)); +} +static inline zig_i128 zig_i128_bitCast_f80(zig_f80 arg) { + return zig_make_i128((int16_t)zig_exponent_repr_f80(arg), zig_mantissa_repr_f80(arg)); +} +#endif +static inline zig_f80 zig_f80_bitCast_big(const void *arg) { + return zig_f80_bitCast_u128(zig_u128_truncate_big(arg, UINT8_C(80), false, UINT16_C(80))); +} +static inline void zig_big_bitCast_f80(void *res, zig_f80 arg, bool res_is_signed, uint16_t res_bits) { + if (res_is_signed) { + zig_big_truncate_i128(res, zig_i128_bitCast_f80(arg), res_is_signed, res_bits); + } else { + zig_big_truncate_u128(res, zig_u128_bitCast_f80(arg), res_is_signed, res_bits); } -zig_bitCast_float(f16, uint16_t) -zig_bitCast_float(f32, uint32_t) -zig_bitCast_float(f64, uint64_t) -zig_bitCast_float(f80, zig_u128) -zig_bitCast_float(f128, zig_u128) +} +#if zig_has_f128 +zig_bitCast_float(128, 128, zig_u128, zig_i128) +#else +static inline zig_f128 zig_f128_bitCast_u128(zig_u128 arg) { + return zig_make_repr_f128(zig_hi_u128(arg), zig_lo_u128(arg)); +} +static inline zig_f128 zig_f128_bitCast_i128(zig_i128 arg) { + return zig_make_repr_f128((uint64_t)zig_hi_i128(arg), zig_lo_i128(arg)); +} +static inline zig_u128 zig_u128_bitCast_f128(zig_f128 arg) { + return zig_make_u128(zig_hi_repr_f128(arg), zig_lo_repr_f128(arg)); +} +static inline zig_i128 zig_i128_bitCast_f128(zig_f128 arg) { + return zig_make_i128((int64_t)zig_hi_repr_f128(arg), zig_lo_repr_f128(arg)); +} +#endif -#define zig_convert_builtin(ExternResType, ResType, operation, ExternArgType, ArgType, version) \ - zig_extern ExternResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ExternArgType); \ +#define zig_convert_float_00(ResType, operation, ArgType, version) \ + zig_extern ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ + zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ArgType arg); \ + return zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ + zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(arg) +#define zig_convert_float_01(ResType, operation, ArgType, version) \ + zig_convert_float_00(ResType, operation, ArgType, version) +#define zig_convert_float_10(ResType, operation, ArgType, version) \ + zig_convert_float_00(ResType, operation, ArgType, version) +#define zig_convert_float_11(ResType, operation, ArgType, version) \ + return (ResType)arg +#define zig_convert_float(res_when, ResType, operation, arg_when, ArgType, version) \ static inline ResType zig_expand_concat(zig_expand_concat(zig_##operation, \ zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType)(ArgType arg) { \ - ResType res; \ - ExternResType extern_res; \ - ExternArgType extern_arg; \ - memcpy(&extern_arg, &arg, sizeof(extern_arg)); \ - extern_res = zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(extern_arg); \ - memcpy(&res, &extern_res, sizeof(res)); \ - return extern_res; \ + zig_expand_concat(zig_expand_concat(zig_convert_float_, zig_has_##res_when), \ + zig_has_##arg_when)(ResType, operation, ArgType, version); \ } -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f32, zig_f32, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f80, zig_f80, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f80, zig_f80, 2) -#ifdef __ARM_EABI__ +#define zig_convert_floats(SmallType, BigType) \ + zig_convert_float(SmallType, zig_##SmallType, trunc, BigType, zig_##BigType, 2) \ + zig_convert_float(BigType, zig_##BigType, extend, SmallType, zig_##SmallType, 2) +zig_convert_floats(f16, f32) +zig_convert_floats(f16, f64) +zig_convert_floats(f16, f80) +zig_convert_floats(f16, f128) +zig_convert_floats(f32, f64) +zig_convert_floats(f32, f80) +zig_convert_floats(f32, f128) +zig_convert_floats(f64, f80) +zig_convert_floats(f64, f128) +zig_convert_floats(f80, f128) -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_d2f(zig_f64); -static inline zig_f32 zig_truncdfsf(zig_f64 arg) { return __aeabi_d2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_f2d(zig_f32); -static inline zig_f64 zig_extendsfdf(zig_f32 arg) { return __aeabi_f2d(arg); } - -#else /* __ARM_EABI__ */ - -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_f32, zig_f32, 2) - -#endif /* __ARM_EABI__ */ - -#define zig_float_negate_builtin_0(w, c, sb) \ - zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, c sb)) -#define zig_float_negate_builtin_1(w, c, sb) -arg -#define zig_float_negate_builtin(w, c, sb) \ +#define zig_float_negate_builtin_0(w, sb) \ + zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, sb)) +#define zig_float_negate_builtin_1(w, sb) -arg +#define zig_float_negate_builtin(w, sb) \ static inline zig_f##w zig_neg_f##w(zig_f##w arg) { \ - return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, c, sb); \ + return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, sb); \ } -zig_float_negate_builtin(16, , UINT16_C(1) << 15 ) -zig_float_negate_builtin(32, , UINT32_C(1) << 31 ) -zig_float_negate_builtin(64, , UINT64_C(1) << 63 ) -zig_float_negate_builtin(80, zig_make_u128, (UINT64_C(1) << 15, UINT64_C(0))) -zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) +zig_float_negate_builtin(16, UINT16_C(1) << 15) +zig_float_negate_builtin(32, UINT32_C(1) << 31) +zig_float_negate_builtin(64, UINT64_C(1) << 63) + +#undef zig_float_negate_builtin_0 +#define zig_float_negate_builtin_0(w, sb) \ + zig_make_repr_f##w(zig_mantissa_repr_f##w(arg), zig_xor_u16(zig_exponent_repr_f##w(arg), sb)) +zig_float_negate_builtin(80, UINT16_C(1) << 15) + +#undef zig_float_negate_builtin_0 +#define zig_float_negate_builtin_0(w, sb) \ + zig_make_repr_f##w(zig_xor_u64(zig_hi_repr_f##w(arg), sb), zig_lo_repr_f##w(arg)) +zig_float_negate_builtin(128, UINT64_C(1) << 63) #define zig_float_less_builtin_0(Type, operation) \ - zig_extern int32_t zig_expand_concat(zig_expand_concat(__##operation, \ + zig_extern zig_FloatCompareResult zig_expand_concat(zig_expand_concat(__##operation, \ zig_compiler_rt_abbrev_zig_##Type), 2)(zig_##Type, zig_##Type); \ static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \ + return (int32_t)zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \ } #define zig_float_less_builtin_1(Type, operation) \ static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ @@ -3994,13 +6077,52 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) return lhs operator rhs; \ } +#define zig_float_builtins(w) \ + zig_common_float_builtins(w) \ + zig_convert_float(f##w, zig_f##w, float, int128, zig_i128, ) \ + zig_convert_float(f##w, zig_f##w, floatun, int128, zig_u128, ) #define zig_common_float_builtins(w) \ - zig_convert_builtin( int64_t, int64_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_i128, zig_i128, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_u128, zig_u128, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int64_t, int64_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, zig_i128, zig_i128, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, zig_u128, zig_u128, ) \ + zig_convert_float(always, int32_t, fix, f##w, zig_f##w, ) \ + zig_convert_float(always, int64_t, fix, f##w, zig_f##w, ) \ + zig_convert_float(int128, zig_i128, fix, f##w, zig_f##w, ) \ + zig_convert_float(always, uint32_t, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(always, uint64_t, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(int128, zig_u128, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(f##w, zig_f##w, float, always, int32_t, ) \ + zig_convert_float(f##w, zig_f##w, float, always, int64_t, ) \ + zig_convert_float(f##w, zig_f##w, floatun, always, uint32_t, ) \ + zig_convert_float(f##w, zig_f##w, floatun, always, uint64_t, ) \ +\ + static inline void zig_expand_concat(zig_expand_concat(zig_fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(void *res, zig_f##w arg, uint16_t bits) { \ + zig_extern void zig_expand_concat(zig_expand_concat(__fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(uint8_t *res, uintptr_t bits, zig_f##w arg); \ + zig_expand_concat(zig_expand_concat(__fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(res, bits, arg); \ + } \ +\ + static inline void zig_expand_concat(zig_expand_concat(zig_fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(void *res, zig_f##w arg, uint16_t bits) { \ + zig_extern void zig_expand_concat(zig_expand_concat(__fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(uint8_t *res, uintptr_t bits, zig_f##w arg); \ + zig_expand_concat(zig_expand_concat(__fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(res, bits, arg); \ + } \ +\ + static inline zig_f##w zig_expand_concat(zig_floatei, \ + zig_compiler_rt_abbrev_zig_f##w)(void *res, uint16_t bits) { \ + zig_extern zig_f##w zig_expand_concat(__floatei, \ + zig_compiler_rt_abbrev_zig_f##w)(const uint8_t *arg, uintptr_t bits); \ + return zig_expand_concat(__floatei, zig_compiler_rt_abbrev_zig_f##w)(res, bits); \ + } \ +\ + static inline zig_f##w zig_expand_concat(zig_floatunei, \ + zig_compiler_rt_abbrev_zig_f##w)(void *res, uint16_t bits) { \ + zig_extern zig_f##w zig_expand_concat(__floatunei, \ + zig_compiler_rt_abbrev_zig_f##w)(const uint8_t *arg, uintptr_t bits); \ + return zig_expand_concat(__floatunei, zig_compiler_rt_abbrev_zig_f##w)(res, bits); \ + } \ +\ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, cmp) \ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, ne) \ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, eq) \ @@ -4031,82 +6153,48 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmax)))(zig_f##w, zig_max_f##w, zig_libc_name_f##w(fmax), (zig_f##w x, zig_f##w y), (x, y)) \ zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fma)))(zig_f##w, zig_fma_f##w, zig_libc_name_f##w(fma), (zig_f##w x, zig_f##w y, zig_f##w z), (x, y, z)) \ \ - static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divTrunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_trunc_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ - static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divFloor_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_floor_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ - static inline zig_f##w zig_div_ceil_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divCeil_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_ceil_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ - return zig_sub_f##w(lhs, zig_mul_f##w(zig_div_floor_f##w(lhs, rhs), rhs)); \ + return zig_sub_f##w(lhs, zig_mul_f##w(zig_divFloor_f##w(lhs, rhs), rhs)); \ } -zig_common_float_builtins(16) -zig_common_float_builtins(32) -zig_common_float_builtins(64) -zig_common_float_builtins(80) -zig_common_float_builtins(128) - -#define zig_float_builtins(w) \ - zig_convert_builtin( int32_t, int32_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint32_t, uint32_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint64_t, uint64_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int32_t, int32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint32_t, uint32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint64_t, uint64_t, ) zig_float_builtins(16) -zig_float_builtins(80) -zig_float_builtins(128) - -#ifdef __ARM_EABI__ - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_f2iz(zig_f32); -static inline int32_t zig_fixsfsi(zig_f32 arg) { return __aeabi_f2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_f2uiz(zig_f32); -static inline uint32_t zig_fixunssfsi(zig_f32 arg) { return __aeabi_f2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_f2ulz(zig_f32); -static inline uint64_t zig_fixunssfdi(zig_f32 arg) { return __aeabi_f2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_i2f(int32_t); -static inline zig_f32 zig_floatsisf(int32_t arg) { return __aeabi_i2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ui2f(uint32_t); -static inline zig_f32 zig_floatunsisf(uint32_t arg) { return __aeabi_ui2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ul2f(uint64_t); -static inline zig_f32 zig_floatundisf(uint64_t arg) { return __aeabi_ul2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_d2iz(zig_f64); -static inline int32_t zig_fixdfsi(zig_f64 arg) { return __aeabi_d2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_d2uiz(zig_f64); -static inline uint32_t zig_fixunsdfsi(zig_f64 arg) { return __aeabi_d2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_d2ulz(zig_f64); -static inline uint64_t zig_fixunsdfdi(zig_f64 arg) { return __aeabi_d2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_i2d(int32_t); -static inline zig_f64 zig_floatsidf(int32_t arg) { return __aeabi_i2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ui2d(uint32_t); -static inline zig_f64 zig_floatunsidf(uint32_t arg) { return __aeabi_ui2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ul2d(uint64_t); -static inline zig_f64 zig_floatundidf(uint64_t arg) { return __aeabi_ul2d(arg); } - -#else /* __ARM_EABI__ */ - zig_float_builtins(32) zig_float_builtins(64) - -#endif /* __ARM_EABI__ */ +zig_float_builtins(80) +#if defined(zig_x86_32) +zig_common_float_builtins(128) +static inline zig_f128 zig_floattitf(zig_i128 arg) { + extern zig_f128 __floattitf(zig_f128 arg); + return __floattitf(zig_f128_bitCast_i128(arg)); +} +static inline zig_f128 zig_floatuntitf(zig_u128 arg) { + extern zig_f128 __floatuntitf(zig_f128 arg); + return __floatuntitf(zig_f128_bitCast_u128(arg)); +} +#elif defined(zig_x86_64) && defined(zig_windows) +zig_common_float_builtins(128) +static inline zig_f128 zig_floattitf(zig_i128 arg) { + extern zig_f128 __floattitf(zig_i128 arg); + return __floattitf(arg); +} +static inline zig_f128 zig_floatuntitf(zig_u128 arg) { + extern zig_f128 __floatuntitf(uint64_t arg_lo, uint64_t arg_hi); + return __floatuntitf(zig_lo_u128(arg), zig_hi_u128(arg)); +} +#else +zig_float_builtins(128) +#endif /* ============================ Atomics Support ============================= */ @@ -4410,19 +6498,19 @@ typedef int zig_memory_order; } \ static inline void zig_msvc_atomic_store_##ZigType(Type volatile* obj, Type value) { \ (void)_InterlockedExchange##suffix((SigType volatile*)obj, (SigType)value); \ - } \ + } \ static inline Type zig_msvc_atomic_load_zig_memory_order_relaxed_##ZigType(Type volatile* obj) { \ return __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ } \ static inline Type zig_msvc_atomic_load_zig_memory_order_acquire_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ + Type value = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - return val; \ + return value; \ } \ static inline Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ + Type value = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - return val; \ + return value; \ } zig_msvc_atomics( u8, uint8_t, char, 8, 8) @@ -4465,14 +6553,14 @@ zig_msvc_atomics(i64, int64_t, __int64, 64, 64) zig_##Type result; \ SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ + memcpy(&result, &initial, sizeof(result)); \ return result; \ } \ static inline zig_##Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##Type(zig_##Type volatile* obj) { \ zig_##Type result; \ SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ + memcpy(&result, &initial, sizeof(result)); \ return result; \ } @@ -4502,9 +6590,9 @@ static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p32(void volat } static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p32(void volatile* obj) { - void* val = (void*)__iso_volatile_load32(obj); + void* value = (void*)__iso_volatile_load32(obj); _ReadWriteBarrier(); - return val; + return value; } static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p32(void volatile* obj) { @@ -4532,9 +6620,9 @@ static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p64(void volat } static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p64(void volatile* obj) { - void* val = (void*)__iso_volatile_load64(obj); + void* value = (void*)__iso_volatile_load64(obj); _ReadWriteBarrier(); - return val; + return value; } static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p64(void volatile* obj) { diff --git a/src/Air.zig b/src/Air.zig index fbaa370132a6044191d71a7b68d79915584fd979..ad4526f0760417f5b90819864a73c62e7f6c00a3 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -1907,7 +1907,7 @@ pub const NullTerminatedString = enum(u32) { pub fn toSlice(nts: NullTerminatedString, air: Air) [:0]const u8 { if (nts == .none) return ""; const bytes = std.mem.sliceAsBytes(air.extra.items[@backingInt(nts)..]); - return bytes[0..std.mem.indexOfScalar(u8, bytes, 0).? :0]; + return bytes[0..std.mem.findScalar(u8, bytes, 0).? :0]; } }; diff --git a/src/Air/Legalize.zig b/src/Air/Legalize.zig index 535d9394654a130ef856342f3390473d6664cf93..64fd462b7bd8e041a65c3ec89616db830776349b 100644 --- a/src/Air/Legalize.zig +++ b/src/Air/Legalize.zig @@ -2906,12 +2906,18 @@ fn packedAggregateInitBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Erro const orig_ty_pl = l.air_instructions.items(.data)[@backingInt(orig_inst)].ty_pl; const agg_ty = orig_ty_pl.ty.toType(); const agg_field_count = agg_ty.structFieldCount(zcu); + var opv_field_count: u32 = 0; + for (0..agg_field_count) |field_idx| { + const field_ty = agg_ty.fieldType(field_idx, zcu); + const field_bits: u16 = @intCast(field_ty.bitSize(zcu)); + if (field_bits == 0) opv_field_count += 1; + } var bfa_buf: [4 * 32 + 2]Air.Inst.Index = undefined; var bfa_state: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), gpa); const bfa = bfa_state.allocator(); - const inst_buf = try bfa.alloc(Air.Inst.Index, 4 * agg_field_count + 2); + const inst_buf = try bfa.alloc(Air.Inst.Index, 4 * (agg_field_count - opv_field_count) + 2); defer bfa.free(inst_buf); var main_block: Block = .init(inst_buf); @@ -2927,6 +2933,7 @@ fn packedAggregateInitBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Erro field_idx -= 1; const field_ty = agg_ty.fieldType(field_idx, zcu); const field_bits: u16 = @intCast(field_ty.bitSize(zcu)); + if (field_bits == 0) continue; assert(field_bits < num_bits); const field_uint_ty = try pt.intType(.unsigned, field_bits); const field_bit_size_ref: Air.Inst.Ref = .fromValue(try pt.intValue(shift_ty, field_bits)); diff --git a/src/Air/Liveness.zig b/src/Air/Liveness.zig index 520f71f313fc6e4b1a4c64860b4ce7f040391c26..3940ae27b8446d71c053e938dbbb9344b56daa7e 100644 --- a/src/Air/Liveness.zig +++ b/src/Air/Liveness.zig @@ -351,7 +351,7 @@ const Analysis = struct { extra: std.ArrayList(u32), fn addExtra(a: *Analysis, extra: anytype) Allocator.Error!u32 { - const field_count = std.meta.fieldNames(@TypeOf(extra)).len; + const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len; try a.extra.ensureUnusedCapacity(a.gpa, field_count); return addExtraAssumeCapacity(a, extra); } @@ -1012,7 +1012,7 @@ fn analyzeInstBlock( const block_scope = data.block_scopes.get(inst).?; const num_deaths = data.live_set.count() - block_scope.live_set.count(); - try a.extra.ensureUnusedCapacity(gpa, num_deaths + std.meta.fieldNames(Block).len); + try a.extra.ensureUnusedCapacity(gpa, num_deaths + @typeInfo(Block).@"struct".field_names.len); const extra_index = a.addExtraAssumeCapacity(Block{ .death_count = num_deaths, }); @@ -1275,7 +1275,7 @@ fn analyzeInstCondBr( // Write the mirrored deaths to `extra` const then_death_count = @as(u32, @intCast(then_mirrored_deaths.items.len)); const else_death_count = @as(u32, @intCast(else_mirrored_deaths.items.len)); - try a.extra.ensureUnusedCapacity(gpa, std.meta.fieldNames(CondBr).len + then_death_count + else_death_count); + try a.extra.ensureUnusedCapacity(gpa, @typeInfo(CondBr).@"struct".field_names.len + then_death_count + else_death_count); const extra_index = a.addExtraAssumeCapacity(CondBr{ .then_death_count = then_death_count, .else_death_count = else_death_count, diff --git a/src/Builtin.zig b/src/Builtin.zig index 7975f2b04bf7c1ca82c3dc786221f903be884cc4..218a1f44875185ed67fa046976f9481fc811cfed 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -7,7 +7,7 @@ is_test: bool, single_threaded: bool, link_libc: bool, link_libcpp: bool, -optimize_mode: std.lang.OptimizeMode, +optimize_mode: std.lang.Optimize, error_tracing: bool, valgrind: bool, sanitize_thread: bool, @@ -64,7 +64,9 @@ pub fn append(opts: @This(), buffer: *std.array_list.Managed(u8)) Allocator.Erro \\pub const unwind_tables: std.lang.UnwindTables = .{f}; \\pub const is_test = {}; \\pub const single_threaded = {}; + \\/// Deprecated; to be removed in 0.18.0. Use `target.abi` instead. \\pub const abi: std.Target.Abi = .{f}; + \\/// Deprecated; to be removed in 0.18.0. Use `target.cpu` instead. \\pub const cpu: std.Target.Cpu = .{{ \\ .arch = .{f}, \\ .model = &std.Target.{f}.cpu.{f}, @@ -95,6 +97,7 @@ pub fn append(opts: @This(), buffer: *std.array_list.Managed(u8)) Allocator.Erro try buffer.print( \\ }}), \\}}; + \\/// Deprecated; to be removed in 0.18.0. Use `target.os` instead. \\pub const os: std.Target.Os = .{{ \\ .tag = .{f}, \\ .version_range = .{{ @@ -238,8 +241,11 @@ pub fn append(opts: @This(), buffer: *std.array_list.Managed(u8)) Allocator.Erro const link_libc = opts.link_libc; try buffer.print( + \\/// Deprecated; to be removed in 0.18.0. Use `target.ofmt` instead. \\pub const object_format: std.Target.ObjectFormat = .{f}; - \\pub const mode: std.lang.OptimizeMode = .{f}; + \\/// Deprecated, to be removed after 0.18.0 + \\pub const mode = optimize; + \\pub const optimize: std.lang.Optimize = .{f}; \\pub const link_libc = {}; \\pub const link_libcpp = {}; \\pub const have_error_return_tracing = {}; diff --git a/src/Compilation.zig b/src/Compilation.zig index 293b553d233ce437470ab229ad14c721e33ef56b..f6b30ef3f9c1c91abf29381d6b9d2b273ef6a424 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -172,7 +172,7 @@ verbose_link: bool, link_depfile: ?[]const u8, disable_c_depfile: bool, stack_report: bool, -debug_compiler_runtime_libs: ?std.lang.OptimizeMode, +debug_compiler_runtime_libs: ?std.lang.Optimize, debug_compile_errors: bool, /// Do not check this field directly. Instead, use the `debugIncremental` wrapper function. debug_incremental: bool, @@ -1232,7 +1232,6 @@ pub const cache_helpers = struct { hh.add(mod.sanitize_thread); hh.add(mod.fuzz); hh.add(mod.unwind_tables); - hh.add(mod.structured_cfg); hh.add(mod.no_builtin); hh.addListOfBytes(mod.cc_argv); } @@ -1506,7 +1505,7 @@ pub const CreateOptions = struct { verbose_llvm_bc: ?[]const u8 = null, link_depfile: ?[]const u8 = null, verbose_llvm_cpu_features: bool = false, - debug_compiler_runtime_libs: ?std.lang.OptimizeMode = null, + debug_compiler_runtime_libs: ?std.lang.Optimize = null, debug_compile_errors: bool = false, debug_incremental: bool = false, /// Normally when you create a `Compilation`, Zig will automatically build @@ -2134,6 +2133,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, comp.config.any_fuzz = any_fuzz; if (opt_zcu) |zcu| { + // Finish initializing the `zcu` after the fields on `comp` have been initialized. + zcu.initAfterCompilation(); + // Populate `zcu.module_roots`. const active = zcu.acquire(); defer active.release(); @@ -2160,7 +2162,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, .framework_dirs = options.framework_dirs, .rpath_list = options.rpath_list, .symbol_wrap_set = options.symbol_wrap_set, - .repro = options.linker_repro orelse (options.root_mod.optimize_mode != .Debug), + .repro = options.linker_repro orelse (options.root_mod.optimize_mode != .debug), .allow_shlib_undefined = options.linker_allow_shlib_undefined, .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false, .compress_debug_sections = options.linker_compress_debug_sections orelse .none, @@ -2911,7 +2913,20 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE // The linker progress node is set up here instead of in `performAllTheWork`, because // we also want it around during `flush`. if (comp.bin_file) |lf| { - comp.link_prog_node = main_progress_node.start("Linking", 0); + // mirrors logic in `Compilation.flush`: + // Always: linker flush + var initial_estimated_total: usize = 1; + const llvm = if (comp.zcu) |zcu| zcu.llvm_object != null else false; + // For llvm: "LLVM Emit Object" and "Parse Object" with the zcu object + if (llvm) { + initial_estimated_total += 2; + } + // Prelink + if (!lf.post_prelink or llvm) { + initial_estimated_total += 1; + } + + comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total); lf.startProgress(comp.link_prog_node); } defer if (comp.bin_file) |lf| { @@ -3189,8 +3204,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error break :p try p.toStringZ(arena); }, - .is_debug = comp.root_mod.optimize_mode == .Debug, - .is_small = comp.root_mod.optimize_mode == .ReleaseSmall, + .is_debug = comp.root_mod.optimize_mode == .debug, + .is_small = comp.root_mod.optimize_mode == .small, .time_report = if (comp.time_report) |*p| p else null, .sanitize_thread = comp.config.any_sanitize_thread, .fuzz = comp.config.any_fuzz, @@ -3660,11 +3675,11 @@ pub fn saveState(comp: *Compilation) !void { addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values())); addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind))); addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index))); - addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.tag))); - addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.offset))); + addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.tag))); + addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.offset))); // TODO handle the union safety field - //addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.pointee))); - addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.addend))); + //addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.pointee))); + addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.addend))); addBuf(&bufs, @ptrCast(wasm.uav_fixups.items)); addBuf(&bufs, @ptrCast(wasm.nav_fixups.items)); addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items)); @@ -4061,7 +4076,14 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { ref = refs.get(r.referencer).?; } } - @panic("referenced transitive analysis errors, but none actually emitted"); + if (comp.debugIncremental()) { + std.debug.print("skipping compiler panic to allow incremental debug server usage", .{}); + try bundle.addRootErrorMessage(.{ + .msg = try bundle.addString("compiler bug: referenced transitive analysis errors, but none actually emitted"), + }); + } else { + @panic("referenced transitive analysis errors, but none actually emitted"); + } } }; @@ -4744,7 +4766,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const optimize_mode = std.lang.OptimizeMode.ReleaseSmall; + const optimize_mode: std.lang.Optimize = .small; const output_mode = std.lang.OutputMode.Exe; const resolved_target: Module.ResolvedTarget = .{ .result = std.zig.system.resolveTargetQuery(io, .{ @@ -5910,8 +5932,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // them being defined matches the behavior of how MSVC calls rc.exe which is the more // relevant behavior in this case. switch (rc_src.owner.optimize_mode) { - .Debug, .ReleaseSafe => {}, - .ReleaseFast, .ReleaseSmall => try argv.append("-DNDEBUG"), + .debug, .safe => {}, + .fast, .small => try argv.append("-DNDEBUG"), } try argv.appendSlice(rc_src.extra_flags); try argv.appendSlice(&.{ "--", rc_src.src_path, out_res_path }); @@ -6006,26 +6028,30 @@ fn spawnZigRc( multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? }); defer multi_reader.deinit(); - const stdout = multi_reader.fileReader(0); - const MessageHeader = std.zig.Server.Message.Header; + const stdout = multi_reader.reader(0); var eos_err: error{EndOfStream}!void = {}; + var client: std.zig.Client = .{ + .in = stdout, + .out = undefined, + }; + while (true) { - const header = stdout.interface.takeStruct(MessageHeader, .little) catch |err| switch (err) { - error.EndOfStream => break, - error.ReadFailed => return stdout.err.?, - }; - const body = stdout.interface.take(header.bytes_len) catch |err| switch (err) { + const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { + error.Timeout => unreachable, error.EndOfStream => |e| { + if (client.in.bufferedLen() == 0) break; // Better to report the crash with stderr below, but we set // this in case the child exits successfully while violating // this protocol. eos_err = e; break; }, - error.ReadFailed => return stdout.err.?, + else => |e| return e, }; + const body = client.in.take(header.bytes_len) catch unreachable; + switch (header.tag) { // We expect exactly one ErrorBundle, and if any error_bundle header is // sent then it's a fatal error. @@ -6178,11 +6204,11 @@ fn addCommonCCArgs( // LLVM IR files don't support these flags. if (ext != .ll and ext != .bc) { switch (mod.optimize_mode) { - .Debug => {}, - .ReleaseSafe => { + .debug => {}, + .safe => { try argv.append("-D_FORTIFY_SOURCE=2"); }, - .ReleaseFast, .ReleaseSmall => { + .fast, .small => { try argv.append("-DNDEBUG"); }, } @@ -6333,7 +6359,7 @@ fn addCommonCCArgs( } } - if (mod.optimize_mode != .Debug) { + if (mod.optimize_mode != .debug) { try argv.append("-Werror=date-time"); } }, @@ -6412,18 +6438,18 @@ fn addCommonCCArgs( } switch (mod.optimize_mode) { - .Debug => { + .debug => { // Clang has -Og for compatibility with GCC, but currently it is just equivalent // to -O1. Besides potentially impairing debugging, -O1/-Og significantly // increases compile times. try argv.append("-O0"); }, - .ReleaseSafe => { + .safe => { // See the comment in the BuildModeFastRelease case for why we pass -O2 rather // than -O3 here. try argv.append("-O2"); }, - .ReleaseFast => { + .fast => { // Here we pass -O2 rather than -O3 because, although we do the equivalent of // -O3 in Zig code, the justification for the difference here is that Zig // has better detection and prevention of undefined behavior, so -O3 is safer for @@ -6431,7 +6457,7 @@ fn addCommonCCArgs( // running in -O2 and thus the -O3 path has been tested less. try argv.append("-O2"); }, - .ReleaseSmall => { + .small => { try argv.append("-Os"); }, } @@ -6641,6 +6667,8 @@ pub fn addCCArgs( // Only compiled files support these flags. switch (ext) { + .assembly, + .assembly_with_cpp, .c, .h, .cpp, @@ -7254,7 +7282,6 @@ fn buildOutputFromZig( .unwind_tables = comp.root_mod.unwind_tables, .pic = comp.root_mod.pic, .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, .no_builtin = true, .code_model = comp.root_mod.code_model, .error_tracing = false, @@ -7403,7 +7430,6 @@ pub fn build_crt_file( // Some CRT objects (e.g. musl's rcrt1.o and Scrt1.o) are opinionated about PIC. .pic = options.pic orelse comp.root_mod.pic, .optimize_mode = comp.compilerRtOptMode(), - .structured_cfg = comp.root_mod.structured_cfg, // Some libcs (e.g. musl) are opinionated about -fno-builtin. .no_builtin = options.no_builtin orelse comp.root_mod.no_builtin, .code_model = comp.root_mod.code_model, @@ -7557,15 +7583,15 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { /// This decides the optimization mode for all zig-provided libraries, including /// compiler-rt, libcxx, libc, libunwind, etc. -pub fn compilerRtOptMode(comp: Compilation) std.lang.OptimizeMode { +pub fn compilerRtOptMode(comp: Compilation) std.lang.Optimize { if (comp.debug_compiler_runtime_libs) |mode| { return mode; } const target = &comp.root_mod.resolved_target.result; switch (comp.root_mod.optimize_mode) { - .Debug, .ReleaseSafe => return target_util.defaultCompilerRtOptimizeMode(target), - .ReleaseFast => return .ReleaseFast, - .ReleaseSmall => return .ReleaseSmall, + .debug, .safe => return target_util.defaultCompilerRtOptimizeMode(target), + .fast => return .fast, + .small => return .small, } } diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index ad0d709425cfaccd284cd929bc7329604a325213..85915ded1b97d4e324a1cebbdb1385758ebea6f0 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -59,7 +59,7 @@ export_memory: bool, shared_memory: bool, is_test: bool, debug_format: DebugFormat, -root_optimize_mode: std.lang.OptimizeMode, +root_optimize_mode: std.lang.Optimize, root_strip: bool, root_error_tracing: bool, dll_export_fns: bool, @@ -80,7 +80,7 @@ pub const Options = struct { is_test: bool, have_zcu: bool, emit_bin: bool, - root_optimize_mode: ?std.lang.OptimizeMode = null, + root_optimize_mode: ?std.lang.Optimize = null, root_strip: ?bool = null, root_error_tracing: ?bool = null, link_mode: ?std.lang.LinkMode = null, @@ -196,7 +196,7 @@ pub fn resolve(options: Options) ResolveError!Config { break :b options.use_lib_llvm orelse true; }; - const root_optimize_mode = options.root_optimize_mode orelse .Debug; + const root_optimize_mode = options.root_optimize_mode orelse .debug; // Make a decision on whether to use Clang or Aro for translate-c and compiling C files. const c_frontend: CFrontend = b: { @@ -357,7 +357,7 @@ pub fn resolve(options: Options) ResolveError!Config { if (!use_lib_llvm and options.emit_bin) break :b false; // Prefer LLVM for release builds. - if (root_optimize_mode != .Debug) break :b true; + if (root_optimize_mode != .debug) break :b true; // load_dynamic_library standalone test not passing on this combination // https://github.com/ziglang/zig/issues/24080 @@ -486,7 +486,7 @@ pub fn resolve(options: Options) ResolveError!Config { const root_strip = b: { if (options.root_strip) |x| break :b x; - if (root_optimize_mode == .ReleaseSmall) break :b true; + if (root_optimize_mode == .small) break :b true; if (!target_util.hasDebugInfo(target)) break :b true; break :b false; }; @@ -512,8 +512,8 @@ pub fn resolve(options: Options) ResolveError!Config { if (root_strip) break :b false; if (!backend_supports_error_tracing) break :b false; break :b switch (root_optimize_mode) { - .Debug => true, - .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false, + .debug => true, + .safe, .fast, .small => false, }; }; diff --git a/src/IncrementalDebugServer.zig b/src/IncrementalDebugServer.zig index 4d34812ae507191ea3799f12209d482008e14b93..cbbe07ba3d212b5e485159e089d90c2d6f9a75ef 100644 --- a/src/IncrementalDebugServer.zig +++ b/src/IncrementalDebugServer.zig @@ -130,7 +130,7 @@ fn serveStream( try stream_writer.writeAll("zig> "); const untrimmed = try stream_reader.takeSentinel('\n'); const cmd_and_arg = std.mem.trim(u8, untrimmed, " \t\r\n"); - const cmd: []const u8, const arg: []const u8 = if (std.mem.indexOfScalar(u8, cmd_and_arg, ' ')) |i| + const cmd: []const u8, const arg: []const u8 = if (std.mem.findScalar(u8, cmd_and_arg, ' ')) |i| .{ cmd_and_arg[0..i], cmd_and_arg[i + 1 ..] } else .{ cmd_and_arg, "" }; @@ -244,7 +244,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const const ty: Type = .fromInterned(type_ip_index); const ty_name = ty.containerTypeName(ip).toSlice(ip); const success = switch (@as(u2, @intFromBool(anchor_start)) << 1 | @intFromBool(anchor_end)) { - 0b00 => std.mem.indexOf(u8, ty_name, query) != null, + 0b00 => std.mem.find(u8, ty_name, query) != null, 0b01 => std.mem.endsWith(u8, ty_name, query), 0b10 => std.mem.startsWith(u8, ty_name, query), 0b11 => std.mem.eql(u8, ty_name, query), @@ -265,7 +265,7 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const const nav = ip.getNav(nav_index); const nav_fqn = nav.fqn.toSlice(ip); const success = switch (@as(u2, @intFromBool(anchor_start)) << 1 | @intFromBool(anchor_end)) { - 0b00 => std.mem.indexOf(u8, nav_fqn, query) != null, + 0b00 => std.mem.find(u8, nav_fqn, query) != null, 0b01 => std.mem.endsWith(u8, nav_fqn, query), 0b10 => std.mem.startsWith(u8, nav_fqn, query), 0b11 => std.mem.eql(u8, nav_fqn, query), @@ -286,21 +286,34 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const const referencer = (ref orelse break :ref "").referencer; break :ref printAnalUnit(referencer, &ref_str_buf); }; - const has_err: []const u8 = err: { - if (zcu.failed_analysis.contains(unit)) break :err "true"; - if (zcu.transitive_failed_analysis.contains(unit)) break :err "true (transitive)"; - break :err "false"; - }; try w.print( \\last update generation: {d} \\current referencer: {s} - \\has error: {s} \\ , .{ unit_info.last_update_gen, ref_str, - has_err, }); + if (zcu.failed_analysis.get(unit)) |err_msg| { + try w.print("analysis result: failure ({q})\n", .{err_msg.msg}); + } else if (zcu.transitive_failed_analysis.get(unit)) |reason| { + switch (reason) { + .astgen_error => try w.writeAll("analysis result: transitive failure (astgen error)\n"), + .dependency_loop => try w.writeAll("analysis result: transitive failure (dependency loop)\n"), + .lost_tracking => try w.writeAll("analysis result: transitive failure (lost tracking for zir inst)\n"), + .failed_unit => |other_unit| { + var buf: [32]u8 = undefined; + try w.print("analysis result: transitive failure (failed unit: {s})\n", .{printAnalUnit(other_unit, &buf)}); + }, + .func_nav_val_changed => |func_index| try w.print("analysis result: transitive failure (owner nav of func '{d}' changed value)\n", .{@backingInt(func_index)}), + } + } else { + try w.writeAll("analysis result: success\n"); + } + if (unit.unwrap() == .func) { + const nav_id = zcu.intern_pool.indexToKey(unit.unwrap().func).func.owner_nav; + try w.print("owner nav: {d}\n", .{@backingInt(nav_id)}); + } } else if (std.mem.eql(u8, cmd_str, "unit_dependencies")) { const unit = parseAnalUnit(arg_str) orelse return w.writeAll("malformed anal unit"); const unit_info = zcu.incremental_debug_state.units.get(unit) orelse return w.writeAll("unknown anal unit"); @@ -365,7 +378,7 @@ fn parseIndex(str: []const u8) ?u32 { return std.fmt.parseInt(u32, str, 10) catch null; } fn parseAnalUnit(str: []const u8) ?AnalUnit { - const split_idx = std.mem.indexOfScalar(u8, str, ' ') orelse return null; + const split_idx = std.mem.findScalar(u8, str, ' ') orelse return null; const kind = str[0..split_idx]; const idx_str = str[split_idx + 1 ..]; if (std.mem.eql(u8, kind, "comptime")) { diff --git a/src/InternPool.zig b/src/InternPool.zig index 5a28a997418a52a40a06c324d610348ab5c17800..a5c3bdd044920a3fa745249467879385ed20fbec 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1737,7 +1737,7 @@ pub const String = enum(u32) { } pub fn toNullTerminatedString(string: String, len: u64, ip: *const InternPool) NullTerminatedString { - assert(std.mem.indexOfScalar(u8, string.toSlice(len, ip), 0) == null); + assert(std.mem.findScalar(u8, string.toSlice(len, ip), 0) == null); assert(string.at(len, ip) == 0); return @fromBackingInt(@intCast(@backingInt(string))); } @@ -1864,7 +1864,7 @@ pub const NullTerminatedString = enum(u32) { pub fn toUnsigned(string: NullTerminatedString, ip: *const InternPool) ?u32 { const slice = string.toSlice(ip); if (slice.len > 1 and slice[0] == '0') return null; - if (std.mem.indexOfScalar(u8, slice, '_')) |_| return null; + if (std.mem.findScalar(u8, slice, '_')) |_| return null; return std.fmt.parseUnsigned(u32, slice, 10) catch null; } @@ -4193,7 +4193,7 @@ pub const Index = enum(u32) { }; } - /// This function is used in the debugger pretty formatters in tools/ to fetch the + /// This function is used in the debugger pretty formatters in lib/lldb/ to fetch the /// Tag to encoding mapping to facilitate fancy debug printing for this type. fn dbHelper(self: *Index, tag_to_encoding_map: *struct { const DataIsIndex = struct { data: Index }; @@ -4219,26 +4219,17 @@ pub const Index = enum(u32) { type_inferred_error_set: DataIsIndex, simple_type: void, type_function: struct { - const @"data.flags.has_comptime_bits" = opaque {}; - const @"data.flags.has_noalias_bits" = opaque {}; - const @"data.flags.cc.extraLen()" = opaque {}; const @"data.params_len" = opaque {}; data: *Tag.TypeFunction, - @"trailing.comptime_bits.len": *@"data.flags.has_comptime_bits", - @"trailing.noalias_bits.len": *@"data.flags.has_noalias_bits", - @"trailing.cc_bits.len": *@"data.flags.cc.extraLen()", @"trailing.param_types.len": *@"data.params_len", - trailing: struct { comptime_bits: []u32, noalias_bits: []u32, cc_bits: []u32, param_types: []Index }, + trailing: struct { param_types: []Index }, }, type_tuple: struct { const @"data.fields_len" = opaque {}; data: *TypeTuple, @"trailing.types.len": *@"data.fields_len", @"trailing.values.len": *@"data.fields_len", - trailing: struct { - types: []Index, - values: []Index, - }, + trailing: struct { types: []Index, values: []Index }, }, type_struct: struct { data: *Tag.TypeStruct }, @@ -4350,7 +4341,7 @@ pub const Index = enum(u32) { const encoding = @field(Tag.encodings, tag_name); if (@hasField(@TypeOf(encoding), "trailing")) { const trailing_info = @typeInfo(encoding.trailing).@"struct"; - for (trailing_info.field_names, trailing_info.field_types) |field_name, field_type| { + for (trailing_info.field_names, trailing_info.field_types) |trailing_field_name, trailing_field_type| { struct { fn checkConfig(name: []const u8) void { if (!@hasField(@TypeOf(encoding.config), name)) @compileError("missing field: " ++ @typeName(Tag) ++ ".encodings." ++ tag_name ++ ".config.@\"" ++ name ++ "\""); @@ -4359,22 +4350,30 @@ pub const Index = enum(u32) { } fn checkField(name: []const u8, Type: type) void { switch (@typeInfo(Type)) { - .int => {}, - .@"enum" => {}, - .@"struct" => |info| assert(info.layout == .@"packed"), + .int, .@"enum" => return, + .@"struct" => |info| switch (info.layout) { + .auto => unreachable, + .@"extern" => { + for (info.field_names, info.field_types) |field_name, field_type| checkField(name ++ "." ++ field_name, field_type); + return; + }, + .@"packed" => return, + }, .optional => |info| { checkConfig(name ++ ".?"); checkField(name ++ ".?", info.child); + return; }, - .pointer => |info| { - assert(info.size == .slice); + .pointer => |info| if (info.size == .slice) { checkConfig(name ++ ".len"); checkField(name ++ "[0]", info.child); + return; }, - else => @compileError("unsupported type: " ++ @typeName(Tag) ++ ".encodings." ++ tag_name ++ "." ++ name ++ ": " ++ @typeName(Type)), + else => {}, } + @compileError("unsupported type: " ++ @typeName(Tag) ++ ".encodings." ++ tag_name ++ "." ++ name ++ ": " ++ @typeName(Type)); } - }.checkField("trailing." ++ field_name, field_type); + }.checkField("trailing." ++ trailing_field_name, trailing_field_type); } } }, @@ -5186,17 +5185,18 @@ pub const Tag = enum(u8) { .trailing = struct { param_comptime_bits: ?[]u32, param_noalias_bits: ?[]u32, - param_cc_bits: ?[]u32, - param_type: []Index, + spirv_kernel_options: ?extern struct { x: u32, y: u32, z: u32 }, + spirv_mesh_options: ?extern struct { max_primitives: u32, max_vertices: u32 }, + param_types: []Index, }, .config = .{ .@"trailing.param_comptime_bits.?" = .@"payload.flags.has_comptime_bits", .@"trailing.param_comptime_bits.?.len" = .@"(payload.params_len + 31) / 32", .@"trailing.param_noalias_bits.?" = .@"payload.flags.has_noalias_bits", .@"trailing.param_noalias_bits.?.len" = .@"(payload.params_len + 31) / 32", - .@"trailing.param_cc_bits.?" = .@"payload.flags.cc.extraLen() != 0", - .@"trailing.param_cc_bits.?.len" = .@"payload.flags.cc.extraLen()", - .@"trailing.param_type.len" = .@"payload.params_len", + .@"trailing.spirv_kernel_options.?" = .@"payload.flags.cc.tag == .spirv_kernel or payload.flags.cc.tag == .spirv_task", + .@"trailing.spirv_mesh_options.?" = .@"payload.flags.cc.tag == .spirv_mesh", + .@"trailing.param_types.len" = .@"payload.params_len", }, }, @@ -5225,7 +5225,7 @@ pub const Tag = enum(u8) { .@"trailing.field_defaults.?" = .@"payload.flags.any_field_defaults", .@"trailing.field_defaults.?.len" = .@"payload.fields_len", .@"trailing.field_aligns.?" = .@"payload.flags.any_field_aligns", - .@"trailing.field_aligns.?.len" = .@"payload.fields_len", + .@"trailing.field_aligns.?.len" = .@"(payload.fields_len + 3) / 4", .@"trailing.field_is_comptime_bits.?" = .@"payload.flags.any_comptime_fields", .@"trailing.field_is_comptime_bits.?.len" = .@"(payload.fields_len + 31) / 32", .@"trailing.field_runtime_order.?" = .@"payload.flags.layout == .auto", @@ -5254,7 +5254,7 @@ pub const Tag = enum(u8) { .@"trailing.captures.?.len" = .@"trailing.captures_len.?", .@"trailing.field_types.len" = .@"payload.fields_len", .@"trailing.field_aligns.?" = .@"payloads.flags.any_field_aligns", - .@"trailing.field_aligns.?.len" = .@"payload.fields_len", + .@"trailing.field_aligns.?.len" = .@"(payload.fields_len + 3) / 4", }, }, .type_union_packed_auto = union_packed_encoding, @@ -11428,7 +11428,7 @@ pub fn getOrPutTrailingString( .tid = tid, .index = strings.mutate.len - 1, }).wrap(ip)))); - const has_embedded_null = std.mem.indexOfScalar(u8, key, 0) != null; + const has_embedded_null = std.mem.findScalar(u8, key, 0) != null; switch (embedded_nulls) { .no_embedded_nulls => assert(!has_embedded_null), .maybe_embedded_nulls => if (has_embedded_null) { diff --git a/src/Module.zig b/src/Module.zig index c351d9eaf4bb29baa41306fa0b80cf3f42276e08..0567c07a6021f74c13a04c8ff74c6cd509d83633 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -26,7 +26,7 @@ fully_qualified_name: []const u8, deps: Deps = .{}, resolved_target: ResolvedTarget, -optimize_mode: std.lang.OptimizeMode, +optimize_mode: std.lang.Optimize, code_model: std.lang.CodeModel, single_threaded: bool, error_tracing: bool, @@ -42,8 +42,6 @@ sanitize_thread: bool, fuzz: bool, unwind_tables: std.lang.UnwindTables, cc_argv: []const []const u8, -/// (SPIR-V) whether to generate a structured control flow graph or not -structured_cfg: bool, no_builtin: bool, pub const Deps = std.array_hash_map.String(*Module); @@ -67,7 +65,7 @@ pub const CreateOptions = struct { pub const Inherited = struct { /// If this is null then `parent` must be non-null. resolved_target: ?ResolvedTarget = null, - optimize_mode: ?std.lang.OptimizeMode = null, + optimize_mode: ?std.lang.Optimize = null, code_model: ?std.lang.CodeModel = null, single_threaded: ?bool = null, error_tracing: ?bool = null, @@ -85,7 +83,6 @@ pub const CreateOptions = struct { sanitize_c: ?std.zig.SanitizeC = null, sanitize_thread: ?bool = null, fuzz: ?bool = null, - structured_cfg: ?bool = null, no_builtin: ?bool = null, }; }; @@ -144,7 +141,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { if (options.inherited.valgrind) |x| break :b x; if (options.parent) |p| break :b p.valgrind; if (strip) break :b false; - break :b optimize_mode == .Debug; + break :b optimize_mode == .debug; }; const single_threaded = b: { @@ -212,7 +209,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { const omit_frame_pointer = b: { if (options.inherited.omit_frame_pointer) |x| break :b x; if (options.parent) |p| break :b p.omit_frame_pointer; - if (optimize_mode == .ReleaseSmall) { + if (optimize_mode == .small) { // On x86, in most cases, keeping the frame pointer usually results in smaller binary size. // This has to do with how instructions for memory access via the stack base pointer register (when keeping the frame pointer) // are smaller than instructions for memory access via the stack pointer register (when omitting the frame pointer). @@ -251,21 +248,21 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { }; const is_safe_mode = switch (optimize_mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, + .debug, .safe => true, + .fast, .small => false, }; const sanitize_c: std.zig.SanitizeC = b: { if (options.inherited.sanitize_c) |x| break :b x; if (options.parent) |p| break :b p.sanitize_c; break :b switch (optimize_mode) { - .Debug => .full, + .debug => .full, // It's recommended to use the minimal runtime in production // environments due to the security implications of the full runtime. // The minimal runtime doesn't provide much benefit over simply // trapping, however, so we do that instead. - .ReleaseSafe => .trap, - .ReleaseFast, .ReleaseSmall => .off, + .safe => .trap, + .fast, .small => .off, }; }; @@ -320,17 +317,6 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { break :sp target_util.default_stack_protector_buffer_size; }; - const structured_cfg = b: { - if (options.inherited.structured_cfg) |x| break :b x; - if (options.parent) |p| break :b p.structured_cfg; - // We always want a structured control flow in shaders. This option is - // only relevant for OpenCL kernels. - break :b switch (target.os.tag) { - .opencl => false, - else => true, - }; - }; - const no_builtin = b: { if (options.inherited.no_builtin) |x| break :b x; if (options.parent) |p| break :b p.no_builtin; @@ -411,7 +397,6 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { .fuzz = fuzz, .unwind_tables = unwind_tables, .cc_argv = options.cc_argv, - .structured_cfg = structured_cfg, .no_builtin = no_builtin, }; return mod; @@ -450,7 +435,6 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*M .fuzz = undefined, .unwind_tables = undefined, .cc_argv = undefined, - .structured_cfg = undefined, .no_builtin = undefined, }; return mod; @@ -489,7 +473,6 @@ pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: std.zig.Directories) .stack_protector = 0, .red_zone = false, .sanitize_c = .off, - .structured_cfg = false, .no_builtin = false, }; return new; diff --git a/src/RangeSet.zig b/src/RangeSet.zig index 3033e8510394cbef68b815601f4eea545fb4feae..291b8ee4e5f001ac715113d63ea30d3f6e0bb6d8 100644 --- a/src/RangeSet.zig +++ b/src/RangeSet.zig @@ -1,6 +1,6 @@ const RangeSet = @This(); -ranges: std.MultiArrayList(Range), +list: std.MultiArrayList(Range), pub const Range = struct { first: Value, @@ -8,41 +8,36 @@ pub const Range = struct { src: LazySrcLoc, }; -pub const empty: RangeSet = .{ .ranges = .empty }; +pub const empty: RangeSet = .{ .list = .empty }; pub fn deinit(self: *RangeSet, allocator: Allocator) void { - self.ranges.deinit(allocator); + self.list.deinit(allocator); self.* = undefined; } -pub fn ensureUnusedCapacity(self: *RangeSet, allocator: Allocator, additional_count: usize) Allocator.Error!void { - return self.ranges.ensureUnusedCapacity(allocator, additional_count); +pub fn ensureUnusedCapacity(set: *RangeSet, allocator: Allocator, additional_count: usize) Allocator.Error!void { + return set.list.ensureUnusedCapacity(allocator, additional_count); } -pub fn addAssumeCapacity(set: *RangeSet, new: Range, ty: Type, zcu: *Zcu) ?LazySrcLoc { +pub fn addAssumeCapacity(set: *RangeSet, new: Range, ty: Type, zcu: *Zcu) ?Range { assert(new.first.typeOf(zcu).eql(ty)); assert(new.last.typeOf(zcu).eql(ty)); assert(new.first.compareScalar(.lte, new.last, ty, zcu)); - const idx = std.sort.lowerBound(Value, set.ranges.items(.last), @as(SearchCtx, .{ + const idx = std.sort.lowerBound(Value, set.list.items(.last), @as(SearchCtx, .{ .val = new.first, .zcu = zcu, }), compare); - if (idx != set.ranges.len and // `new.first` is *not* greater than all `old.last` - new.last.compareScalar(.gte, set.ranges.items(.first)[idx], ty, zcu)) + if (idx != set.list.len and // `new.first` is *not* greater than all `old.last` + new.last.compareScalar(.gte, set.list.items(.first)[idx], ty, zcu)) { - return set.ranges.items(.src)[idx]; // `new` overlaps with existing range. + return set.list.get(idx); // `new` overlaps with existing range. } - set.ranges.insertAssumeCapacity(idx, new); + set.list.insertAssumeCapacity(idx, new); return null; } -pub fn add(set: *RangeSet, allocator: Allocator, new: Range, ty: Type, zcu: *Zcu) Allocator.Error!?LazySrcLoc { - try set.ensureUnusedCapacity(allocator, 1); - return set.addAssumeCapacity(new, ty, zcu); -} - pub fn spans( set: *RangeSet, allocator: Allocator, @@ -53,13 +48,13 @@ pub fn spans( ) Allocator.Error!bool { assert(first.typeOf(zcu).eql(ty)); assert(last.typeOf(zcu).eql(ty)); - if (set.ranges.len == 0) return false; + if (set.list.len == 0) return false; - assert(std.sort.isSorted(Value, set.ranges.items(.first), @as(SortCtx, .{ .ty = ty, .zcu = zcu }), lessThan)); - assert(std.sort.isSorted(Value, set.ranges.items(.last), @as(SortCtx, .{ .ty = ty, .zcu = zcu }), lessThan)); + assert(std.sort.isSorted(Value, set.list.items(.first), @as(SortCtx, .{ .ty = ty, .zcu = zcu }), lessThan)); + assert(std.sort.isSorted(Value, set.list.items(.last), @as(SortCtx, .{ .ty = ty, .zcu = zcu }), lessThan)); - if (!set.ranges.items(.first)[0].eql(first, ty, zcu) or - !set.ranges.items(.last)[set.ranges.len - 1].eql(last, ty, zcu)) + if (!set.list.items(.first)[0].eql(first, ty, zcu) or + !set.list.items(.last)[set.list.len - 1].eql(last, ty, zcu)) { return false; } @@ -75,8 +70,8 @@ pub fn spans( // look for gaps for ( - set.ranges.items(.first)[1..], - set.ranges.items(.last)[0 .. set.ranges.len - 1], + set.list.items(.first)[1..], + set.list.items(.last)[0 .. set.list.len - 1], ) |cur_first, prev_last| { // prev_last + 1 == cur_first counter.copy(prev_last.toBigInt(&space, zcu)); diff --git a/src/Sema.zig b/src/Sema.zig index 20df87823ce2703925d26d0f5e7020415b00d7ce..920bf997512c7c59bcca6715c7cf30c4f02e9bb1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -532,20 +532,20 @@ pub const Block = struct { fn wantSafeTypes(block: *const Block) bool { return block.want_safety orelse switch (block.ownerModule().optimize_mode) { - .Debug => true, - .ReleaseSafe => true, - .ReleaseFast => false, - .ReleaseSmall => false, + .debug => true, + .safe => true, + .fast => false, + .small => false, }; } fn wantSafety(block: *const Block) bool { if (block.isComptime()) return false; // runtime safety checks are pointless in comptime blocks return block.want_safety orelse switch (block.ownerModule().optimize_mode) { - .Debug => true, - .ReleaseSafe => true, - .ReleaseFast => false, - .ReleaseSmall => false, + .debug => true, + .safe => true, + .fast => false, + .small => false, }; } @@ -1472,7 +1472,7 @@ fn analyzeBodyInner( i += 1; continue; }, - .astgen_error => return error.AnalysisFail, + .astgen_error => return sema.failTransitive(.astgen_error), .float_op_result_ty => try sema.zirFloatOpResultType(block, extended), }; }, @@ -2247,7 +2247,7 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) ?Value { .inferred_alloc_comptime => unreachable, // assertion failure else => {}, } - // LLVM fails to eliminate this `classify` call in ReleaseFast, which hurts performance, so + // LLVM fails to eliminate this `classify` call in -Ofast, which hurts performance, so // we must explicitly check for `std.debug.runtime_safety`. if (std.debug.runtime_safety) switch (sema.typeOf(inst).classify(zcu)) { .no_possible_value => unreachable, // values of this type do not exist @@ -2352,6 +2352,10 @@ pub fn failWithUseOfUndef(sema: *Sema, block: *Block, src: LazySrcLoc, vector_in }); } +pub fn failWithUndefSliceLen(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError { + return sema.fail(block, src, "use of slice with undefined length here causes illegal behavior", .{}); +} + pub fn failWithDivideByZero(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError { return sema.fail(block, src, "division by zero here causes illegal behavior", .{}); } @@ -2697,13 +2701,15 @@ fn failWithTypeMismatch(sema: *Sema, block: *Block, src: LazySrcLoc, expected: T }); } -pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg) error{ AnalysisFail, OutOfMemory } { +pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg) SemaError { @branchHint(.cold); const zcu = sema.pt.zcu; const comp = zcu.comp; const gpa = comp.gpa; const io = comp.io; + assert(sema.err == null); + if (build_options.enable_debug_extensions and comp.debug_compile_errors) { var wip_errors: std.zig.ErrorBundle.Wip = undefined; wip_errors.init(gpa) catch @panic("out of memory"); @@ -2729,17 +2735,11 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg err_msg.reference_trace_root = sema.owner.toOptional(); - const gop = try zcu.failed_analysis.getOrPut(gpa, sema.owner); - if (gop.found_existing) { - // If there are multiple errors for the same Decl, prefer the first one added. - sema.err = null; - err_msg.destroy(gpa); - } else { - sema.err = err_msg; - gop.value_ptr.* = err_msg; - } + try zcu.failed_analysis.putNoClobber(gpa, sema.owner, err_msg); + assert(!zcu.transitive_failed_analysis.contains(sema.owner)); - return error.AnalysisFail; + sema.err = err_msg; + return error.AlreadyReported; } /// Given an ErrorMsg, modify its message and source location to the given values, turning the @@ -3117,9 +3117,14 @@ fn zirRefDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try sema.validateDeref(block, src, operand, operand_ty); const ptr_info = operand_ty.ptrInfo(zcu); - return switch (ptr_info.flags.size) { - .many, .slice => unreachable, // cannot be dereferenced - .c => single_ptr: { + return single_ptr: switch (ptr_info.flags.size) { + .many => unreachable, // cannot be dereferenced directly + .slice => { + const slice_val = sema.resolveValue(operand).?; + const slice = zcu.intern_pool.indexToKey(slice_val.toIntern()).slice; + break :single_ptr .fromValue(try pt.sliceToArrayPtr(slice)); + }, + .c => { const single_ptr_ty = try pt.ptrType(p: { var p = ptr_info; p.flags.size = .one; @@ -3153,18 +3158,26 @@ fn validateDeref( ) CompileError!void { const pt = sema.pt; const zcu = pt.zcu; + const ip = &zcu.intern_pool; if (ty.zigTypeTag(zcu) != .pointer) { return sema.fail(block, src, "cannot dereference non-pointer type '{f}'", .{ty.fmt(pt)}); - } else switch (ty.ptrSize(zcu)) { - .one, .c => {}, + } + const size = ty.ptrSize(zcu); + switch (size) { .many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{f}'", .{ty.fmt(pt)}), - .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{ty.fmt(pt)}), + .one, .c, .slice => {}, } if (sema.resolveValue(ref)) |val| { // Error for deref of undef pointer, unless the pointee is OPV in which case it's legal. if (val.isUndef(zcu) and ty.childType(zcu).classify(zcu) != .one_possible_value) { return sema.fail(block, src, "cannot dereference undefined value", .{}); } + // We need a defined slice length for the array type the slice should be dereferenced to. + if (size == .slice and ip.indexToKey(val.toIntern()).slice.len == .undef_usize) { + return sema.fail(block, src, "cannot dereference slice with undefined length", .{}); + } + } else if (size == .slice) { + return sema.fail(block, src, "index syntax required to access runtime-known slice", .{}); } } @@ -3186,10 +3199,12 @@ fn ensureResultUsed( const zcu = pt.zcu; switch (ty.zigTypeTag(zcu)) { .void, .noreturn => return, - .error_set => return sema.fail(block, src, "error set is ignored", .{}), + .error_set => { + return sema.fail(block, src, "error set of type '{f}' is ignored", .{ty.fmt(pt)}); + }, .error_union => { const msg = msg: { - const msg = try sema.errMsg(src, "error union is ignored", .{}); + const msg = try sema.errMsg(src, "error union of type '{f}' is ignored", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{}); break :msg msg; @@ -4745,11 +4760,14 @@ fn failWithBadMemberAccess( .@"enum" => "enum", else => unreachable, }; - if (agg_ty.typeDeclInst(zcu)) |inst| if ((inst.resolve(ip) orelse return error.AnalysisFail) == .main_struct_inst) { - return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{ - agg_ty.fmt(pt), field_name.fmt(ip), - }); - }; + if (agg_ty.typeDeclInst(zcu)) |inst| { + const inst_index = inst.resolve(ip) orelse return sema.failTransitive(.{ .lost_tracking = inst }); + if (inst_index == .main_struct_inst) { + return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{ + agg_ty.fmt(pt), field_name.fmt(ip), + }); + } + } return sema.fail(block, field_src, "{s} '{f}' has no member named '{f}'", .{ kw_name, agg_ty.fmt(pt), field_name.fmt(ip), @@ -5997,7 +6015,14 @@ fn lookupInNamespace( const pt = sema.pt; const zcu = pt.zcu; - try pt.ensureNamespaceUpToDate(namespace_index); + pt.ensureNamespaceUpToDate(namespace_index) catch |err| switch (err) { + error.LostZirContainerDecl => { + const namespace = zcu.namespacePtr(namespace_index); + const ns_ty: Type = .fromInterned(namespace.owner_type); + return sema.failTransitive(.{ .lost_tracking = ns_ty.typeDeclInstAllowGeneratedTag(zcu).? }); + }, + else => |e| return e, + }; const namespace = zcu.namespacePtr(namespace_index); @@ -6062,7 +6087,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref const stack_trace_ty = try sema.getStdLangType(block.nodeOffset(.zero), .StackTrace); const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { - error.AnalysisFail => @panic("std.lang.StackTrace is corrupt"), + error.AlreadyReported => @panic("std.lang.StackTrace is corrupt"), error.ComptimeReturn, error.ComptimeBreak => unreachable, error.OutOfMemory, error.Canceled => |e| return e, }; @@ -6724,7 +6749,9 @@ fn analyzeCall( const fn_nav: InternPool.Nav, const fn_zir: Zir, const fn_tracked_inst: InternPool.TrackedInst.Index, const fn_zir_inst: Zir.Inst.Index, const fn_zir_info: Zir.FnInfo = if (func_val) |f| b: { const info = ip.indexToKey(f.toIntern()).func; const nav = ip.getNav(info.owner_nav); - const resolved_func_inst = info.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail; + const resolved_func_inst = info.zir_body_inst.resolveFull(ip) orelse { + return sema.failTransitive(.{ .lost_tracking = info.zir_body_inst }); + }; const file = zcu.fileByIndex(resolved_func_inst.file); const zir_info = file.zir.?.getFnInfo(resolved_func_inst.inst); break :b .{ nav, file.zir.?, info.zir_body_inst, resolved_func_inst.inst, zir_info }; @@ -8355,7 +8382,10 @@ fn zirFunc( const cc: std.lang.CallingConvention = if (has_body) cc: { const func_decl_nav = sema.owner.unwrap().nav_val; const fn_is_exported = exported: { - const decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(ip) orelse return error.AnalysisFail; + const decl_ti = ip.getNav(func_decl_nav).analysis.?.zir_index; + const decl_inst = decl_ti.resolve(ip) orelse { + return sema.failTransitive(.{ .lost_tracking = decl_ti }); + }; const zir_decl = sema.code.getDeclaration(decl_inst); break :exported zir_decl.linkage == .@"export"; }; @@ -8501,6 +8531,7 @@ const calling_conventions_supporting_var_args = [_]std.lang.CallingConvention.Ta .x86_64_win, .x86_sysv, .x86_win, + .x86_mingw, .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win, @@ -10760,7 +10791,7 @@ fn finishSwitchBr( .@"enum" => if (else_is_named_only or !item_ty.isNonexhaustiveEnum(zcu) or tagged_union_originally) { - try branch_hints.ensureUnusedCapacity(gpa, @intCast(validated_switch.seen_enum_fields.len)); + try branch_hints.ensureUnusedCapacity(gpa, @intCast(validated_switch.seen.enum_fields.len)); break :check_enumerable .{ undefined, undefined }; }, .error_set => if (!operand_ty.isAnyError(zcu)) { @@ -10881,13 +10912,13 @@ fn finishSwitchBr( try branch_hints.append(gpa, prong_hint); try cases_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr.Case).@"struct".field_names.len + - (validated_switch.seen_enum_fields.len + 1 - zir_switch.totalItemsLen()) + // +1 because totalItemsLen includes the _ + (validated_switch.seen.enum_fields.len + 1 - zir_switch.totalItemsLen()) + // +1 because totalItemsLen includes the _ case_block.instructions.items.len); const extra_case = cases_extra.addManyAsArrayAssumeCapacity( @typeInfo(Air.SwitchBr.Case).@"struct".field_names.len, ); var items_len: u32 = 0; - for (validated_switch.seen_enum_fields, 0..) |seen_field, field_i| { + for (validated_switch.seen.enum_fields, 0..) |seen_field, field_i| { if (seen_field != null) continue; const item_val = try pt.enumValueFieldIndex(item_ty, @intCast(field_i)); const item_ref: Air.Inst.Ref = .fromValue(item_val); @@ -10920,7 +10951,7 @@ fn finishSwitchBr( } if (tagged_union_originally) { const union_obj = zcu.typeToUnion(operand_ty).?; - for (validated_switch.seen_enum_fields, 0..) |seen_field, field_i| { + for (validated_switch.seen.enum_fields, 0..) |seen_field, field_i| { if (seen_field != null) continue; const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_i]); if (!field_ty.isNoReturn(zcu)) break :analyze_body true; @@ -11004,17 +11035,21 @@ fn finishSwitchBr( } const ValidatedSwitchBlock = struct { - seen_enum_fields: []const ?LazySrcLoc, - seen_errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc), - seen_ranges: std.MultiArrayList(RangeSet.Range).Slice, - true_src: ?LazySrcLoc, - false_src: ?LazySrcLoc, - void_src: ?LazySrcLoc, - + seen: Seen, case_vals: []const Air.Inst.Ref, else_case: Zir.UnwrappedSwitchBlock.Case.Else, else_err_ty: ?Type, + const Seen = struct { + enum_fields: []?LazySrcLoc, + errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc), + sparse_values: std.AutoHashMapUnmanaged(InternPool.Index, LazySrcLoc), + ranges: RangeSet, + true_src: ?LazySrcLoc, + false_src: ?LazySrcLoc, + void_src: ?LazySrcLoc, + }; + fn iterateUnhandledItems( validated_switch: *const ValidatedSwitchBlock, /// May be `undefined` if `item_ty` isn't an `error_set`. @@ -11023,28 +11058,26 @@ const ValidatedSwitchBlock = struct { min_int: Value, ) UnhandledIterator { return .{ + .error_names = error_names, + .seen = &validated_switch.seen, + .next_idx = 0, .next_val = min_int, - .error_names = error_names, - .seen_enum_fields = validated_switch.seen_enum_fields, - .seen_errors = &validated_switch.seen_errors, - .seen_ranges = validated_switch.seen_ranges, - .seen_true = validated_switch.true_src != null, - .seen_false = validated_switch.false_src != null, - .seen_void = validated_switch.void_src != null, + .handled_true = validated_switch.seen.true_src != null, + .handled_false = validated_switch.seen.false_src != null, + .handled_void = validated_switch.seen.void_src != null, }; } const UnhandledIterator = struct { + error_names: InternPool.NullTerminatedString.Slice, + seen: *const Seen, + next_idx: u32, next_val: ?Value, - error_names: InternPool.NullTerminatedString.Slice, - seen_enum_fields: []const ?LazySrcLoc, - seen_errors: *const std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc), - seen_ranges: std.MultiArrayList(RangeSet.Range).Slice, - seen_true: bool, - seen_false: bool, - seen_void: bool, + handled_true: bool, + handled_false: bool, + handled_void: bool, fn next(it: *UnhandledIterator, sema: *Sema, item_ty: Type) CompileError!?Value { const pt = sema.pt; @@ -11052,7 +11085,7 @@ const ValidatedSwitchBlock = struct { const ip = &zcu.intern_pool; switch (item_ty.zigTypeTag(zcu)) { .@"enum" => { - for (it.seen_enum_fields[it.next_idx..], it.next_idx..) |seen_field, field_i| { + for (it.seen.enum_fields[it.next_idx..], it.next_idx..) |seen_field, field_i| { if (seen_field != null) continue; it.next_idx = @intCast(field_i + 1); return try pt.enumValueFieldIndex(item_ty, @intCast(field_i)); @@ -11061,7 +11094,7 @@ const ValidatedSwitchBlock = struct { }, .error_set => { for (it.error_names.get(ip)[it.next_idx..], it.next_idx..) |err_name, name_i| { - if (it.seen_errors.contains(err_name)) continue; + if (it.seen.errors.contains(err_name)) continue; it.next_idx = @intCast(name_i + 1); return .fromInterned(try pt.intern(.{ .err = .{ .ty = item_ty.toIntern(), @@ -11077,14 +11110,14 @@ const ValidatedSwitchBlock = struct { .@"union", .@"struct" => item_ty.backingIntType(zcu), else => unreachable, }; - while (it.next_idx < it.seen_ranges.len and - cur_val.eql(it.seen_ranges.items(.first)[it.next_idx], int_ty, zcu)) + while (it.next_idx < it.seen.ranges.list.len and + cur_val.eql(it.seen.ranges.list.items(.first)[it.next_idx], int_ty, zcu)) { defer it.next_idx += 1; const incr = try arith.incrementDefinedInt( sema, int_ty, - it.seen_ranges.items(.last)[it.next_idx], + it.seen.ranges.list.items(.last)[it.next_idx], ); if (incr.overflow) { it.next_val = null; @@ -11101,19 +11134,19 @@ const ValidatedSwitchBlock = struct { }; }, .bool => { - if (!it.seen_true) { - it.seen_true = true; + if (!it.handled_true) { + it.handled_true = true; return .true; } - if (!it.seen_false) { - it.seen_false = true; + if (!it.handled_false) { + it.handled_false = true; return .false; } return null; }, .void => { - if (!it.seen_void) { - it.seen_void = true; + if (!it.handled_void) { + it.handled_void = true; return .void; } return null; @@ -11186,14 +11219,8 @@ fn validateSwitchBlock( operand_ty.assertHasLayout(zcu); const union_obj = ip.loadUnionType(operand_ty.toIntern()); switch (union_obj.tag_usage) { - .tagged => { - break :item_ty .fromInterned(union_obj.enum_tag_type); - }, - .none => { - if (union_obj.layout == .@"packed") { - break :item_ty operand_ty; - } - }, + .tagged => break :item_ty .fromInterned(union_obj.enum_tag_type), + .none => if (union_obj.layout == .@"packed") break :item_ty operand_ty, .safety => {}, } return sema.failWithOwnedErrorMsg(block, msg: { @@ -11208,27 +11235,47 @@ fn validateSwitchBlock( .@"struct" => { operand_ty.assertHasLayout(zcu); - const layout = operand_ty.containerLayout(zcu); - if (layout == .@"packed") { - break :item_ty operand_ty; - } + if (operand_ty.containerLayout(zcu) == .@"packed") break :item_ty operand_ty; return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(operand_src, "switch on struct with {t} layout", .{layout}); + const msg = try sema.errMsg(operand_src, "switch on non-packed struct", .{}); errdefer msg.destroy(sema.gpa); - if (operand_ty.srcLocOrNull(zcu)) |struct_src| { - try sema.errNote(struct_src, msg, "consider 'packed struct' here", .{}); - } + try sema.addDeclaredHereNote(msg, operand_ty); break :msg msg; }); }, - .pointer => { - if (!operand_ty.isSlice(zcu)) { - break :item_ty operand_ty; - } - }, + .pointer => if (!operand_ty.isSlice(zcu)) break :item_ty operand_ty, - else => {}, + .optional => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(operand_src, "switch on optional type '{f}'", .{ + operand_ty.fmt(pt), + }); + errdefer msg.destroy(gpa); + try sema.errNote(operand_src, msg, "consider using '.?', 'orelse', or 'if'", .{}); + break :msg msg; + }), + + .error_union => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(operand_src, "switch on error union type '{f}'", .{ + operand_ty.fmt(pt), + }); + errdefer msg.destroy(gpa); + try sema.errNote(operand_src, msg, "consider using 'try', 'catch', or 'if'", .{}); + break :msg msg; + }), + + .noreturn, + .float, + .comptime_float, + .array, + .vector, + .undefined, + .null, + .@"opaque", + .frame, + .@"anyframe", + .spirv, + => {}, } return sema.fail(block, operand_src, "switch on type '{f}'", .{operand_ty.fmt(pt)}); }; @@ -11253,13 +11300,15 @@ fn validateSwitchBlock( var case_vals: std.ArrayList(Air.Inst.Ref) = try .initCapacity(arena, zir_switch.item_infos.len); // Duplicate checking variables later also used for `inline else`. - var seen_enum_fields: []?LazySrcLoc = &.{}; - var seen_errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc) = .empty; - var seen_sparse_values: std.AutoHashMapUnmanaged(InternPool.Index, LazySrcLoc) = .empty; - var range_set: RangeSet = .empty; - var true_src: ?LazySrcLoc = null; - var false_src: ?LazySrcLoc = null; - var void_src: ?LazySrcLoc = null; + var seen: ValidatedSwitchBlock.Seen = .{ + .enum_fields = &.{}, + .errors = .empty, + .sparse_values = .empty, + .ranges = .empty, + .true_src = null, + .false_src = null, + .void_src = null, + }; var else_err_ty: ?Type = null; @@ -11267,20 +11316,20 @@ fn validateSwitchBlock( switch (item_ty.zigTypeTag(zcu)) { .@"enum" => { - seen_enum_fields = try arena.alloc(?LazySrcLoc, item_ty.enumFieldCount(zcu)); - @memset(seen_enum_fields, null); - // `range_set` is used for non-exhaustive enum values that do not + seen.enum_fields = try arena.alloc(?LazySrcLoc, item_ty.enumFieldCount(zcu)); + @memset(seen.enum_fields, null); + // `seen.ranges` is used for non-exhaustive enum values that do not // correspond to any tags. Since this is rare, we only allocate on // demand in `validateSwitchItem`. }, .error_set => { - try seen_errors.ensureUnusedCapacity(arena, zir_switch.totalItemsLen()); + try seen.errors.ensureUnusedCapacity(arena, zir_switch.totalItemsLen()); }, .int, .comptime_int, .@"union", .@"struct" => { - try range_set.ensureUnusedCapacity(arena, zir_switch.totalItemsLen()); + try seen.ranges.ensureUnusedCapacity(arena, zir_switch.totalItemsLen()); }, .enum_literal, .@"fn", .pointer, .type => { - try seen_sparse_values.ensureUnusedCapacity(arena, zir_switch.totalItemsLen()); + try seen.sparse_values.ensureUnusedCapacity(arena, zir_switch.totalItemsLen()); }, .bool, .void => {}, @@ -11323,7 +11372,7 @@ fn validateSwitchBlock( case_vals.appendAssumeCapacity(.none); } else { const item, extra_index = try sema.resolveSwitchItem(block, item_src, item_ty, item_info, extra_index, switch_inst, prong_info.is_comptime_unreach); - try sema.validateSwitchItemOrRange(block, item_src, item.val, null, item_ty, seen_enum_fields, &seen_errors, &seen_sparse_values, &range_set, &true_src, &false_src, &void_src); + try sema.validateSwitchItemOrRange(block, item_src, item.val, null, item_ty, &seen); case_vals.appendAssumeCapacity(item.ref); } } @@ -11338,7 +11387,7 @@ fn validateSwitchBlock( const last_src = block.src(.{ .switch_case_item_range_last = range_offset }); const first_item, extra_index = try sema.resolveSwitchItem(block, first_src, item_ty, range_info[0], extra_index, switch_inst, prong_info.is_comptime_unreach); const last_item, extra_index = try sema.resolveSwitchItem(block, last_src, item_ty, range_info[1], extra_index, switch_inst, prong_info.is_comptime_unreach); - try sema.validateSwitchItemOrRange(block, range_src, first_item.val, last_item.val, item_ty, seen_enum_fields, &seen_errors, &seen_sparse_values, &range_set, &true_src, &false_src, &void_src); + try sema.validateSwitchItemOrRange(block, range_src, first_item.val, last_item.val, item_ty, &seen); case_vals.appendSliceAssumeCapacity(&.{ first_item.ref, last_item.ref }); } } @@ -11369,13 +11418,13 @@ fn validateSwitchBlock( // Validate for missing special prongs. switch (item_ty.zigTypeTag(zcu)) { .@"enum" => { - const all_tags_handled = for (seen_enum_fields) |seen_src| { + const all_tags_handled = for (seen.enum_fields) |seen_src| { if (seen_src == null) break false; } else true; if (has_else) { if (all_tags_handled) { - if (item_ty.isNonexhaustiveEnum(zcu)) { + if (operand_ty.isNonexhaustiveEnum(zcu)) { if (has_under) return sema.fail( block, else_prong_src, @@ -11397,7 +11446,7 @@ fn validateSwitchBlock( .{}, ); errdefer msg.destroy(sema.gpa); - for (seen_enum_fields, 0..) |seen_src, i| { + for (seen.enum_fields, 0..) |seen_src, i| { if (seen_src != null) continue; const field_name = item_ty.enumFieldName(i, zcu); @@ -11449,7 +11498,7 @@ fn validateSwitchBlock( var seen_errors_from_set: u32 = 0; for (error_names.get(ip)) |error_name| { - if (seen_errors.contains(error_name)) { + if (seen.errors.contains(error_name)) { seen_errors_from_set += 1; } else if (!has_else) { const msg = maybe_msg orelse blk: { @@ -11491,7 +11540,7 @@ fn validateSwitchBlock( var names: InferredErrorSet.NameMap = .{}; try names.ensureUnusedCapacity(sema.arena, error_names.len); for (error_names.get(ip)) |error_name| { - if (seen_errors.contains(error_name)) continue; + if (seen.errors.contains(error_name)) continue; names.putAssumeCapacityNoClobber(error_name, {}); } // No need to keep the hash map metadata correct; here we @@ -11509,7 +11558,7 @@ fn validateSwitchBlock( }; const min_int = try int_ty.minInt(pt, int_ty); const max_int = try int_ty.maxInt(pt, int_ty); - if (try range_set.spans(arena, min_int, max_int, int_ty, zcu)) { + if (try seen.ranges.spans(arena, min_int, max_int, int_ty, zcu)) { if (has_else) { return sema.fail( block, @@ -11542,8 +11591,8 @@ fn validateSwitchBlock( }, .bool, .void => |type_tag| { const all_values_handled = switch (type_tag) { - .bool => true_src != null and false_src != null, - .void => void_src != null, + .bool => seen.true_src != null and seen.false_src != null, + .void => seen.void_src != null, else => unreachable, }; if (has_else) { @@ -11570,13 +11619,7 @@ fn validateSwitchBlock( } return .{ - .seen_enum_fields = seen_enum_fields, - .seen_errors = seen_errors, - .seen_ranges = range_set.ranges.slice(), - .true_src = true_src, - .false_src = false_src, - .void_src = void_src, - + .seen = seen, .case_vals = case_vals.items, .else_case = else_case, .else_err_ty = else_err_ty, @@ -11754,7 +11797,7 @@ fn resolveSwitchBlock( .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline }; if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_ref); if (tagged_union_originally) { - for (validated_switch.seen_enum_fields, 0..) |maybe_seen, field_i| { + for (validated_switch.seen.enum_fields, 0..) |maybe_seen, field_i| { if (maybe_seen != null) continue; if (!operand_ty.unionFieldTypeByIndex(field_i, zcu).isNoReturn(zcu)) break; } else { @@ -12276,10 +12319,11 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( dummy_captures, .{ .override = item_srcs }, ) catch |err| switch (err) { - error.AnalysisFail => { - const msg = sema.err orelse return error.AnalysisFail; - try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{}); - return error.AnalysisFail; + error.AlreadyReported => |e| { + if (sema.err) |msg| { + try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{}); + } + return e; }, else => |e| return e, }; @@ -12315,11 +12359,12 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( dummy_captures, .{ .override = item_srcs }, ) catch |err| switch (err) { - error.AnalysisFail => { - const msg = sema.err orelse return error.AnalysisFail; - try sema.errNote(capture_src, msg, "this coercion is only possible when capturing by value", .{}); - try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{}); - return error.AnalysisFail; + error.AlreadyReported => |e| { + if (sema.err) |msg| { + try sema.errNote(capture_src, msg, "this coercion is only possible when capturing by value", .{}); + try sema.reparentOwnedErrorMsg(capture_src, msg, "capture group with incompatible types", .{}); + } + return e; }, else => |e| return e, }; @@ -12559,13 +12604,7 @@ fn validateSwitchItemOrRange( item_val: Value, opt_last_val: ?Value, item_ty: Type, - seen_enum_fields: []?LazySrcLoc, - seen_errors: *std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc), - seen_sparse_values: *std.AutoHashMapUnmanaged(InternPool.Index, LazySrcLoc), - range_set: *RangeSet, - true_src: *?LazySrcLoc, - false_src: *?LazySrcLoc, - void_src: *?LazySrcLoc, + seen: *ValidatedSwitchBlock.Seen, ) CompileError!void { const pt = sema.pt; const zcu = pt.zcu; @@ -12574,88 +12613,117 @@ fn validateSwitchItemOrRange( .@"enum" => { const int = ip.indexToKey(item_val.toIntern()).enum_tag.int; if (ip.loadEnumType(item_ty.toIntern()).tagValueIndex(ip, int)) |field_index| { - const maybe_prev_src = seen_enum_fields[field_index]; - seen_enum_fields[field_index] = item_src; + const maybe_prev_src = seen.enum_fields[field_index]; + seen.enum_fields[field_index] = item_src; break :maybe_prev_src maybe_prev_src; } else { - break :maybe_prev_src try range_set.add(sema.arena, .{ + try seen.ranges.ensureUnusedCapacity(sema.arena, 1); + break :maybe_prev_src if (seen.ranges.addAssumeCapacity(.{ .first = .fromInterned(int), .last = .fromInterned(int), .src = item_src, - }, .fromInterned(ip.typeOf(int)), zcu); + }, .fromInterned(ip.typeOf(int)), zcu)) |prev| prev.src else null; } }, .error_set => { const error_name = ip.indexToKey(item_val.toIntern()).err.name; - break :maybe_prev_src if (seen_errors.fetchPutAssumeCapacity(error_name, item_src)) |prev| + break :maybe_prev_src if (seen.errors.fetchPutAssumeCapacity(error_name, item_src)) |prev| prev.value else null; }, .int, .comptime_int => { - if (opt_last_val) |last_val| { - const first_val = item_val; + const first_val = item_val; + const last_val: Value = last_val: { + const last_val = opt_last_val orelse break :last_val item_val; if (try first_val.compareAll(.gt, last_val, item_ty, pt)) { return sema.fail(block, item_src, "range start value is greater than the end value", .{}); } - break :maybe_prev_src range_set.addAssumeCapacity(.{ - .first = first_val, - .last = last_val, - .src = item_src, - }, item_ty, zcu); - } else { - break :maybe_prev_src range_set.addAssumeCapacity(.{ - .first = item_val, - .last = item_val, - .src = item_src, - }, item_ty, zcu); + break :last_val last_val; + }; + if (seen.ranges.addAssumeCapacity(.{ + .first = first_val, + .last = last_val, + .src = item_src, + }, item_ty, zcu)) |prev_range| { + const overlap_start = first_val.numberMax(prev_range.first, zcu); + const overlap_end = last_val.numberMin(prev_range.last, zcu); + if (overlap_start.eql(overlap_end, item_ty, zcu)) { + return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(item_src, "duplicate switch value '{f}'", .{ + overlap_start.fmtValueSema(pt, sema), + }); + errdefer msg.destroy(sema.gpa); + if (prev_range.first.eql(prev_range.last, item_ty, zcu)) { + try sema.errNote(prev_range.src, msg, "previous value here", .{}); + } else { + try sema.errNote(prev_range.src, msg, "previous value inside range here", .{}); + } + break :msg msg; + }); + } + assert(!prev_range.first.eql(prev_range.last, item_ty, zcu)); + return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(item_src, "duplicate switch ranges", .{}); + errdefer msg.destroy(sema.gpa); + if (first_val.eql(prev_range.first, item_ty, zcu) and + last_val.eql(prev_range.last, item_ty, zcu)) + { + try sema.errNote(prev_range.src, msg, "previous range here", .{}); + } else { + try sema.errNote(prev_range.src, msg, "overlaps with previous range here", .{}); + try sema.errNote(prev_range.src, msg, "ranges overlap from '{f}' to '{f}'", .{ + overlap_start.fmtValueSema(pt, sema), overlap_end.fmtValueSema(pt, sema), + }); + } + break :msg msg; + }); } + break :maybe_prev_src null; }, .@"union", .@"struct" => { const backing_int_val = ip.indexToKey(item_val.toIntern()).bitpack.backing_int_val; - break :maybe_prev_src range_set.addAssumeCapacity(.{ + break :maybe_prev_src if (seen.ranges.addAssumeCapacity(.{ .first = .fromInterned(backing_int_val), .last = .fromInterned(backing_int_val), .src = item_src, - }, item_ty.backingIntType(zcu), zcu); + }, item_ty.backingIntType(zcu), zcu)) |prev| prev.src else null; }, .enum_literal, .@"fn", .pointer, .type => { - break :maybe_prev_src if (seen_sparse_values.fetchPutAssumeCapacity(item_val.toIntern(), item_src)) |prev| + break :maybe_prev_src if (seen.sparse_values.fetchPutAssumeCapacity(item_val.toIntern(), item_src)) |prev| prev.value else null; }, .bool => { if (item_val.toBool()) { - if (true_src.*) |prev_src| break :maybe_prev_src prev_src; - true_src.* = item_src; + if (seen.true_src) |prev_src| break :maybe_prev_src prev_src; + seen.true_src = item_src; } else { - if (false_src.*) |prev_src| break :maybe_prev_src prev_src; - false_src.* = item_src; + if (seen.false_src) |prev_src| break :maybe_prev_src prev_src; + seen.false_src = item_src; } break :maybe_prev_src null; }, .void => { - if (void_src.*) |prev_src| break :maybe_prev_src prev_src; - void_src.* = item_src; + if (seen.void_src) |prev_src| break :maybe_prev_src prev_src; + seen.void_src = item_src; break :maybe_prev_src null; }, else => unreachable, // should have already checked for invalid types }; if (maybe_prev_src) |prev_src| { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg( - item_src, - "duplicate switch value", - .{}, - ); + const msg = try sema.errMsg(item_src, "duplicate switch value '{f}'", .{ + item_val.fmtValueSema(pt, sema), + }); errdefer msg.destroy(sema.gpa); - try sema.errNote( - prev_src, - msg, - "previous value here", - .{}, - ); + try sema.errNote(prev_src, msg, "previous value here", .{}); + if (item_ty.zigTypeTag(zcu) == .type) { + try sema.addDeclaredHereNote(msg, item_val.toType()); + } else { + try sema.addDeclaredHereNote(msg, item_ty); + } break :msg msg; }); } @@ -17171,7 +17239,14 @@ fn typeInfoNamespaceDecls( const ip = &zcu.intern_pool; const namespace_index = opt_namespace_index.unwrap() orelse return; - try pt.ensureNamespaceUpToDate(namespace_index); + pt.ensureNamespaceUpToDate(namespace_index) catch |err| switch (err) { + error.LostZirContainerDecl => { + const namespace = zcu.namespacePtr(namespace_index); + const ns_ty: Type = .fromInterned(namespace.owner_type); + return sema.failTransitive(.{ .lost_tracking = ns_ty.typeDeclInstAllowGeneratedTag(zcu).? }); + }, + else => |e| return e, + }; const namespace = zcu.namespacePtr(namespace_index); const gop = try seen_namespaces.getOrPut(namespace); @@ -17897,11 +17972,12 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } // TODO Add compile error for @optimizeFor occurring too late in a scope. sema.analyzeUnreachable(block, src, true) catch |err| switch (err) { - error.AnalysisFail => { - const msg = sema.err orelse return err; - if (!mem.eql(u8, msg.msg, "runtime safety check not allowed in naked function")) return err; - try sema.errNote(src, msg, "the end of a naked function is implicitly unreachable", .{}); - return err; + error.AlreadyReported => |e| { + if (sema.err) |msg| { + if (!mem.eql(u8, msg.msg, "runtime safety check not allowed in naked function")) return err; + try sema.errNote(src, msg, "the end of a naked function is implicitly unreachable", .{}); + } + return e; }, else => |e| return e, }; @@ -18317,11 +18393,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const elem_ty = blk: { const air_inst = sema.resolveInst(extra.data.elem_type); - const ty = sema.analyzeAsType(block, elem_ty_src, .type, air_inst) catch |err| { - if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) { - try sema.errNote(elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{}); - } - return err; + const ty = sema.analyzeAsType(block, elem_ty_src, .type, air_inst) catch |err| switch (err) { + error.AlreadyReported => |e| { + if (sema.err) |msg| { + if (sema.typeOf(air_inst).isSinglePointer(zcu)) { + try sema.errNote(elem_ty_src, msg, "use '.*' to dereference pointer", .{}); + } + } + return e; + }, + else => |e| return e, }; assert(!ty.isGenericPoison()); break :blk ty; @@ -21103,7 +21184,10 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const dest_scalar_ty = dest_ty.scalarType(zcu); const operand_scalar_ty = operand_ty.scalarType(zcu); - _ = try sema.checkIntType(block, src, dest_scalar_ty); + switch (dest_scalar_ty.zigTypeTag(zcu)) { + .comptime_int, .int => {}, + else => return sema.fail(block, src, "expected integer result type, found '{f}'", .{dest_scalar_ty.fmt(pt)}), + } try sema.checkFloatType(block, operand_src, operand_scalar_ty); if (sema.resolveValue(operand)) |operand_val| { @@ -21279,7 +21363,10 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const dest_scalar_ty = dest_ty.scalarType(zcu); const operand_scalar_ty = operand_ty.scalarType(zcu); - try sema.checkFloatType(block, src, dest_scalar_ty); + switch (dest_scalar_ty.zigTypeTag(zcu)) { + .comptime_float, .float => {}, + else => return sema.fail(block, src, "expected float result type, found '{f}'", .{dest_scalar_ty.fmt(pt)}), + } _ = try sema.checkIntType(block, operand_src, operand_scalar_ty); if (sema.resolveValue(operand)) |operand_val| { @@ -21594,16 +21681,16 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err); if (result == .disjoint) { // Error must be zero. - try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code); + try sema.addSafetyCheckCall(block, src, is_zero, .@"panic.unexpectedErrorCode", &.{err_code_inst}); } else { // Error must be in destination set or zero. const has_value = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst); const ok = try block.addBinOp(.bit_or, has_value, is_zero); - try sema.addSafetyCheck(block, src, ok, .invalid_error_code); + try sema.addSafetyCheckCall(block, src, ok, .@"panic.unexpectedErrorCode", &.{err_code_inst}); } } else { const ok = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst); - try sema.addSafetyCheck(block, src, ok, .invalid_error_code); + try sema.addSafetyCheckCall(block, src, ok, .@"panic.unexpectedErrorCode", &.{err_code_inst}); } } @@ -23460,7 +23547,9 @@ fn analyzeShuffle( // `InternPool.Index` values using the known operands. for (mask_shuffle_two, mask_ip_index) |in, *out| { const val: Value = switch (in.unwrap()) { - .undef => try pt.undefValue(elem_ty), + // Special case zero bit types: there is no undefined value for OPV elements. + // Only affects the case where `!a_rt and !b_rt` since `a_coerced` and `b_coerced`'s types are also OPV for OPV elements. + .undef => try elem_ty.onePossibleValue(pt) orelse try pt.undefValue(elem_ty), .a_elem => |idx| try maybe_a_val.?.elemValue(pt, idx), .b_elem => |idx| try maybe_b_val.?.elemValue(pt, idx), }; @@ -23509,6 +23598,9 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C const a = try sema.coerce(block, vec_ty, sema.resolveInst(extra.a), a_src); const b = try sema.coerce(block, vec_ty, sema.resolveInst(extra.b), b_src); + // special case zero bit types + if (try vec_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); + const maybe_pred = sema.resolveValue(pred); const maybe_a = sema.resolveValue(a); const maybe_b = sema.resolveValue(b); @@ -24873,7 +24965,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A } else cc: { if (has_body) { const func_decl_nav = sema.owner.unwrap().nav_val; - const func_decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(&zcu.intern_pool) orelse return error.AnalysisFail; + const func_decl_ti = ip.getNav(func_decl_nav).analysis.?.zir_index; + const func_decl_inst = func_decl_ti.resolve(&zcu.intern_pool) orelse { + return sema.failTransitive(.{ .lost_tracking = func_decl_ti }); + }; const zir_decl = sema.code.getDeclaration(func_decl_inst); if (zir_decl.linkage == .@"export") { break :cc target.cCallingConvention() orelse { @@ -25458,10 +25553,10 @@ fn zirRoundOpType(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDa return .generic_poison_type; }; - const float_ty = dest_ty.optEuBaseType(zcu); - switch (float_ty.scalarType(zcu).zigTypeTag(zcu)) { - .float, .comptime_float => return .fromType(float_ty), - else => return .comptime_float_type, + const dest_base_ty = dest_ty.optEuBaseType(zcu); + switch (dest_base_ty.scalarType(zcu).zigTypeTag(zcu)) { + .float, .comptime_float => return .fromType(dest_base_ty), + else => return .generic_poison_type, } } @@ -25640,7 +25735,6 @@ pub fn explainWhyTypeIsNotExtern( .@"opaque", .bool, - .float, .@"anyframe", => unreachable, // these *are* allowed @@ -25649,6 +25743,7 @@ pub fn explainWhyTypeIsNotExtern( try sema.errNote(src_loc, msg, "SPIR-V runtime arrays must be the last field of an extern struct", .{}); }, + .float => try sema.errNote(src_loc, msg, "'{f}' is not extern compatible on this target", .{ty.fmt(pt)}), .pointer => if (ty.isSlice(zcu)) { try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); } else { @@ -28174,9 +28269,94 @@ fn coerceExtra( }, else => {}, }, - .one => {}, + // []T to *[n]T + .one => slice_to_array_ptr: { + if (!inst_ty.isSlice(zcu)) break :slice_to_array_ptr; + if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :slice_to_array_ptr; + const array_ty: Type = .fromInterned(dest_info.child); + if (array_ty.zigTypeTag(zcu) != .array) break :slice_to_array_ptr; + const inst_val = maybe_inst_val orelse { + if (!opts.report_err) return error.NotCoercible; + return sema.fail( + block, + inst_src, + "coercion from slice to array pointer type '{f}' requires length to be known at compile-time", + .{dest_ty.fmt(pt)}, + ); + }; + + const slice: InternPool.Key.Slice = slice: { + switch (ip.indexToKey(inst_val.toIntern())) { + .undef => {}, + .slice => |slice| if (slice.len != .undef_usize) break :slice slice, + else => unreachable, + } + if (!opts.report_err) return error.NotCoercible; + return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(inst_src, "slice with undefined length cannot cast into array pointer type '{f}'", .{ + dest_ty.fmt(pt), + }); + errdefer msg.destroy(gpa); + try sema.errNote(inst_src, msg, "length of slice must be defined and match length of array type", .{}); + break :msg msg; + }); + }; + const slice_len = Value.fromInterned(slice.len).toUnsignedInt(zcu); + if (array_ty.arrayLen(zcu) != slice_len) { + if (!opts.report_err) return error.NotCoercible; + return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(inst_src, "slice of length {d} cannot cast into array pointer type '{f}'", .{ + slice_len, dest_ty.fmt(pt), + }); + errdefer msg.destroy(gpa); + try sema.errNote(inst_src, msg, "length of slice must match length of array type", .{}); + break :msg msg; + }); + } + + const inst_elem_ty = inst_ty.childType(zcu); + const dest_elem_ty = array_ty.childType(zcu); + const dest_is_mut = !dest_info.flags.is_const; + switch (try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, dest_is_mut, target, dest_ty_src, inst_src, null)) { + .ok => {}, + else => |elem_res| { + in_memory_result = .{ .ptr_child = .{ + .child = try elem_res.dupe(sema.arena), + .actual = inst_elem_ty, + .wanted = dest_elem_ty, + } }; + break :slice_to_array_ptr; + }, + } + + if (array_ty.sentinel(zcu)) |array_sentinel| { + if (inst_ty.sentinel(zcu)) |slice_sentinel| { + if (array_sentinel.toIntern() != + (try pt.getCoerced(slice_sentinel, dest_elem_ty)).toIntern()) + { + in_memory_result = .{ .ptr_sentinel = .{ + .actual = slice_sentinel, + .wanted = array_sentinel, + .ty = dest_elem_ty, + } }; + break :slice_to_array_ptr; + } + } else { + in_memory_result = .{ .ptr_sentinel = .{ + .actual = .@"unreachable", + .wanted = array_sentinel, + .ty = dest_elem_ty, + } }; + break :slice_to_array_ptr; + } + } + + const array_ptr = try pt.sliceToArrayPtr(slice); + return sema.coerceCompatiblePtrs(block, dest_ty, .fromValue(array_ptr), inst_src); + }, .slice => to_slice: { if (inst_ty.zigTypeTag(zcu) == .array) { + if (!opts.report_err) return error.NotCoercible; return sema.fail( block, inst_src, @@ -28204,6 +28384,7 @@ fn coerceExtra( // pointer to tuple to slice if (!dest_info.flags.is_const) { + if (!opts.report_err) return error.NotCoercible; const err_msg = err_msg: { const err_msg = try sema.errMsg(inst_src, "cannot cast pointer to tuple to '{f}'", .{dest_ty.fmt(pt)}); errdefer err_msg.destroy(sema.gpa); @@ -28299,6 +28480,7 @@ fn coerceExtra( if (maybe_inst_val) |val| { const result_val = try val.floatCast(dest_ty, pt); if (!val.eql(try result_val.floatCast(inst_ty, pt), inst_ty, zcu)) { + if (!opts.report_err) return error.NotCoercible; return sema.fail( block, inst_src, @@ -28356,12 +28538,15 @@ fn coerceExtra( break :fits result_big_int.toConst().eql(operand_big_int); }, }; - if (!fits) return sema.fail( - block, - inst_src, - "type '{f}' cannot represent integer value '{f}'", - .{ dest_ty.fmt(pt), val.fmtValue(pt) }, - ); + if (!fits) { + if (!opts.report_err) return error.NotCoercible; + return sema.fail( + block, + inst_src, + "type '{f}' cannot represent integer value '{f}'", + .{ dest_ty.fmt(pt), val.fmtValue(pt) }, + ); + } return .fromValue(result_val); }, else => {}, @@ -28372,6 +28557,7 @@ fn coerceExtra( const val = sema.resolveValue(inst).?; const string = zcu.intern_pool.indexToKey(val.toIntern()).enum_literal; const field_index = dest_ty.enumFieldIndex(string, zcu) orelse { + if (!opts.report_err) return error.NotCoercible; return sema.fail(block, inst_src, "no field named '{f}' in enum '{f}'", .{ string.fmt(&zcu.intern_pool), dest_ty.fmt(pt), }); @@ -29622,7 +29808,7 @@ fn coerceVarArgParam( .array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), .float => float: { const target = zcu.getTarget(); - const double_bits = target.cTypeBitSize(.double); + const double_bits = target.cTypeBitSize(.double) orelse break :float inst; const inst_bits = uncasted_ty.floatBits(target); if (inst_bits >= double_bits) break :float inst; switch (double_bits) { @@ -29638,21 +29824,21 @@ fn coerceVarArgParam( if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) { .signed => .int, .unsigned => .uint, - })) break :int try sema.coerce(block, switch (uncasted_info.signedness) { + }) orelse break :int inst) break :int try sema.coerce(block, switch (uncasted_info.signedness) { .signed => .c_int, .unsigned => .c_uint, }, inst, inst_src); if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) { .signed => .long, .unsigned => .ulong, - })) break :int try sema.coerce(block, switch (uncasted_info.signedness) { + }).?) break :int try sema.coerce(block, switch (uncasted_info.signedness) { .signed => .c_long, .unsigned => .c_ulong, }, inst, inst_src); if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) { .signed => .longlong, .unsigned => .ulonglong, - })) break :int try sema.coerce(block, switch (uncasted_info.signedness) { + }).?) break :int try sema.coerce(block, switch (uncasted_info.signedness) { .signed => .c_longlong, .unsigned => .c_ulonglong, }, inst, inst_src); @@ -30048,6 +30234,19 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul } }; return false; } + + if (inst_info.packed_offset.host_size != dest_info.packed_offset.host_size or + inst_info.packed_offset.bit_offset != dest_info.packed_offset.bit_offset) + { + in_memory_result.* = .{ .ptr_bit_range = .{ + .actual_host = inst_info.packed_offset.host_size, + .wanted_host = dest_info.packed_offset.host_size, + .actual_offset = inst_info.packed_offset.bit_offset, + .wanted_offset = dest_info.packed_offset.bit_offset, + } }; + return false; + } + if (inst_info.flags.alignment == .none and dest_info.flags.alignment == .none) return true; if (len0) return true; @@ -30068,19 +30267,6 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul } }; return false; } - - if (inst_info.packed_offset.host_size != dest_info.packed_offset.host_size or - inst_info.packed_offset.bit_offset != dest_info.packed_offset.bit_offset) - { - in_memory_result.* = .{ .ptr_bit_range = .{ - .actual_host = inst_info.packed_offset.host_size, - .wanted_host = dest_info.packed_offset.host_size, - .actual_offset = inst_info.packed_offset.bit_offset, - .wanted_offset = dest_info.packed_offset.bit_offset, - } }; - return false; - } - return true; } @@ -30606,7 +30792,10 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M if (pt.zcu.analysis_in_progress.contains(unit)) { return sema.failWithDependencyLoop(unit, &reason); } - try pt.ensureMemoizedStateUpToDate(stage, &reason); + pt.ensureMemoizedStateUpToDate(stage, &reason) catch |err| switch (err) { + error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = unit }), + else => |e| return e, + }; } pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void { @@ -30642,9 +30831,15 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: switch (kind) { .type => { try zcu.ensureNavValAnalysisQueued(nav_index); - return pt.ensureNavTypeUpToDate(nav_index, &reason); + return pt.ensureNavTypeUpToDate(nav_index, &reason) catch |err| switch (err) { + error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = anal_unit }), + else => |e| return e, + }; + }, + .fully => return pt.ensureNavValUpToDate(nav_index, &reason) catch |err| switch (err) { + error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = anal_unit }), + else => |e| return e, }, - .fully => return pt.ensureNavValUpToDate(nav_index, &reason), } } @@ -30856,7 +31051,18 @@ fn analyzeLoad( const comptime_only = switch (elem_ty.classify(zcu)) { .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) { .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}), - else => return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{elem_ty.fmt(pt)}), + else => { + // Loading an uninstantiable type always invokes Illegal Behavior. + if (block.isComptime()) { + return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{elem_ty.fmt(pt)}); + } else if (block.wantSafety()) { + try sema.safetyPanic(block, src, .load_uninstantiable_type); + return .unreachable_value; + } else { + _ = try block.addNoOp(.unreach); + return .unreachable_value; + } + }, }, .one_possible_value => return .fromValue((try elem_ty.onePossibleValue(pt)).?), .runtime => false, @@ -30864,8 +31070,11 @@ fn analyzeLoad( }; if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { - if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| { - return Air.internedToRef(elem_val.toIntern()); + if (switch (ptr_ty.ptrSize(zcu)) { + .slice => try sema.maybeDerefSliceAsArray(block, src, ptr_val), + else => try sema.pointerDeref(block, src, ptr_val, ptr_ty), + }) |elem_val| { + return .fromValue(elem_val); } } @@ -33707,7 +33916,10 @@ fn ensureFuncIesResolved( return sema.failWithDependencyLoop(.wrap(.{ .func = func_index }), &reason); } - try pt.ensureFuncBodyUpToDate(func_index, &reason); + pt.ensureFuncBodyUpToDate(func_index, &reason) catch |err| switch (err) { + error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .func = func_index }) }), + else => |e| return e, + }; } pub fn resolveInferredErrorSetPtr( @@ -33821,7 +34033,7 @@ pub fn getTmpAir(sema: Sema) Air { } pub fn addExtra(sema: *Sema, extra: anytype) Allocator.Error!u32 { - const field_count = std.meta.fieldNames(@TypeOf(extra)).len; + const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len; try sema.air_extra.ensureUnusedCapacity(sema.gpa, field_count); return sema.addExtraAssumeCapacity(extra); } @@ -34536,7 +34748,6 @@ fn maybeDerefSliceAsArray( ) CompileError!?Value { const pt = sema.pt; const zcu = pt.zcu; - const ip = &zcu.intern_pool; const slice_ty = slice_val.typeOf(zcu); assert(slice_ty.zigTypeTag(zcu) == .pointer); switch (slice_ty.ptrInfo(zcu).flags.size) { @@ -34544,26 +34755,14 @@ fn maybeDerefSliceAsArray( .one => return sema.pointerDeref(block, src, slice_val, slice_ty), .many, .c => unreachable, } - const slice = switch (ip.indexToKey(slice_val.toIntern())) { + const slice = switch (zcu.intern_pool.indexToKey(slice_val.toIntern())) { .undef => return sema.failWithUseOfUndef(block, src, null), .slice => |slice| slice, else => unreachable, }; - const elem_ty = Type.fromInterned(slice.ty).childType(zcu); - const len = Value.fromInterned(slice.len).toUnsignedInt(zcu); - const array_ty = try pt.arrayType(.{ - .child = elem_ty.toIntern(), - .len = len, - }); - const ptr_ty = try pt.ptrType(p: { - var p = Type.fromInterned(slice.ty).ptrInfo(zcu); - p.flags.size = .one; - p.child = array_ty.toIntern(); - p.sentinel = .none; - break :p p; - }); - const casted_ptr = try pt.getCoerced(Value.fromInterned(slice.ptr), ptr_ty); - return sema.pointerDeref(block, src, casted_ptr, ptr_ty); + if (slice.len == .undef_usize) return sema.failWithUndefSliceLen(block, src); + const casted_ptr = try pt.sliceToArrayPtr(slice); + return sema.pointerDeref(block, src, casted_ptr, casted_ptr.typeOf(zcu)); } fn analyzeUnreachable(sema: *Sema, block: *Block, src: LazySrcLoc, safety_check: bool) !void { @@ -34668,7 +34867,7 @@ pub fn resolveNavPtrModifiers( const linksection_body = zir_decl.linksection_body orelse break :ls .none; const linksection_ref = try sema.resolveInlineBody(block, linksection_body, decl_inst); const bytes = try sema.toConstString(block, section_src, linksection_ref, .{ .simple = .@"linksection" }); - if (std.mem.indexOfScalar(u8, bytes, 0) != null) { + if (std.mem.findScalar(u8, bytes, 0) != null) { return sema.fail(block, section_src, "linksection cannot contain null bytes", .{}); } else if (bytes.len == 0) { return sema.fail(block, section_src, "linksection cannot be empty", .{}); @@ -34843,7 +35042,9 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.StdLangDecl) CompileError!Typ }), // `fn (anyerror) noreturn` - .@"panic.unwrapError" => try pt.funcType(.{ + .@"panic.unwrapError", + .@"panic.unexpectedErrorCode", + => try pt.funcType(.{ .param_types = &.{.anyerror_type}, .return_type = .noreturn_type, }), @@ -34882,12 +35083,60 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.StdLangDecl) CompileError!Typ .@"panic.copyLenMismatch", .@"panic.memcpyAlias", .@"panic.noreturnReturned", + .@"panic.loadUninstantiableType", => try pt.funcType(.{ .param_types = &.{}, .return_type = .noreturn_type, }), - else => unreachable, + .StackTrace, + .CallingConvention, + .SourceLocation, + .Signedness, + .AddressSpace, + .VaList, + .CallModifier, + .AtomicOrder, + .AtomicRmwOp, + .ReduceOp, + .FloatMode, + .PrefetchOptions, + .ExportOptions, + .ExternOptions, + .BranchHint, + .assembly, + .@"assembly.Clobbers", + .Type, + .@"Type.Fn", + .@"Type.Fn.ParamAttributes", + .@"Type.Fn.Attributes", + .@"Type.Int", + .@"Type.Float", + .@"Type.Pointer", + .@"Type.Pointer.Size", + .@"Type.Pointer.Attributes", + .@"Type.Array", + .@"Type.Vector", + .@"Type.Optional", + .@"Type.ErrorUnion", + .@"Type.ErrorSet", + .@"Type.Enum", + .@"Type.Enum.Mode", + .@"Type.Union", + .@"Type.Union.FieldAttributes", + .@"Type.Struct", + .@"Type.Struct.FieldAttributes", + .@"Type.ContainerLayout", + .@"Type.Opaque", + .@"Type.Spirv", + .@"Type.Spirv.Image", + .@"Type.Spirv.Image.Usage", + .@"Type.Spirv.Image.Format", + .@"Type.Spirv.Image.Dimensionality", + .@"Type.Spirv.Image.Depth", + .@"Type.Spirv.Image.Access", + .panic, + => unreachable, // not a function (`decl.kind() != .func`) }; } @@ -34926,7 +35175,9 @@ pub fn setTypeName( }, .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()), .func => { - const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); + const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse { + return sema.failTransitive(.{ .lost_tracking = ip.funcZirBodyInst(sema.func_index) }); + }); const zir_tags = sema.code.instructions.items(.tag); var aw: std.Io.Writer.Allocating = .init(gpa); @@ -35042,7 +35293,10 @@ fn zirStructDecl( }; try sema.addTypeReferenceEntry(src, ty); - try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); + pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)) catch |err| switch (err) { + error.LostZirContainerDecl => unreachable, // we literally just tracked it + else => |e| return e, + }; return .fromType(ty); } @@ -35115,7 +35369,10 @@ fn zirUnionDecl( }; try sema.addTypeReferenceEntry(src, ty); - try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); + pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)) catch |err| switch (err) { + error.LostZirContainerDecl => unreachable, // we literally just tracked it + else => |e| return e, + }; return .fromType(ty); } @@ -35167,7 +35424,10 @@ fn zirEnumDecl( }; try sema.addTypeReferenceEntry(src, ty); - try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); + pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)) catch |err| switch (err) { + error.LostZirContainerDecl => unreachable, // we literally just tracked it + else => |e| return e, + }; return .fromType(ty); } @@ -35216,7 +35476,10 @@ fn zirOpaqueDecl( }; try sema.addTypeReferenceEntry(src, ty); - try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); + pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)) catch |err| switch (err) { + error.LostZirContainerDecl => unreachable, // we literally just tracked it + else => |e| return e, + }; return .fromType(ty); } @@ -35257,5 +35520,31 @@ pub fn failWithDependencyLoop( } // A dependency loop error will be reported. Mark us all as transitive failures. - return error.AnalysisFail; + return sema.failTransitive(.dependency_loop); +} + +/// Marks the owner of `sema` as having failed semantic failed *without* an error message, and +/// returns failure. This function is suitable to call when any one of the following is true: +/// +/// * `sema.owner` is guaranteed to be unreferenced on this update, for instance because it uses a +/// dead `InternPool.TrackedInst`. +/// +/// * There is guaranteed to be a compile error if this unit is referenced. In practice, this means +/// that either there is an error elsewhere in the pipeline (e.g. AstGen), or we depend on another +/// `AnalUnit` which has itself failed. +pub fn failTransitive(sema: *Sema, reason: Zcu.TransitiveFailureReason) SemaError { + assert(sema.err == null); + const zcu = sema.pt.zcu; + const unit = sema.owner; + + log.debug("transitive failure analyzing '{f}' ({t})", .{ zcu.fmtAnalUnit(unit), reason }); + + assert(!zcu.failed_analysis.contains(unit)); + try zcu.transitive_failed_analysis.putNoClobber( + zcu.comp.gpa, + unit, + if (build_options.enable_debug_extensions) reason, + ); + + return error.AlreadyReported; } diff --git a/src/Sema/LowerZon.zig b/src/Sema/LowerZon.zig index f807043d8ecd7bbf6c628feb877d25c92212d08c..dd8c91c244518ac23d1d5d0be6caa30861f2c4c7 100644 --- a/src/Sema/LowerZon.zig +++ b/src/Sema/LowerZon.zig @@ -320,7 +320,7 @@ fn failUnsupportedResultType( self: *LowerZon, ty: Type, opt_note: ?[]const u8, -) error{ AnalysisFail, OutOfMemory } { +) Zcu.SemaError { @branchHint(.cold); const sema = self.sema; const gpa = sema.gpa; @@ -338,7 +338,7 @@ fn fail( node: Zoir.Node.Index, comptime format: []const u8, args: anytype, -) error{ AnalysisFail, OutOfMemory } { +) Zcu.SemaError { @branchHint(.cold); const err_msg = try Zcu.ErrorMsg.create(self.sema.pt.zcu.gpa, self.nodeSrc(node), format, args); try self.sema.pt.zcu.errNote(self.import_loc, err_msg, "imported here", .{}); diff --git a/src/Sema/type_resolution.zig b/src/Sema/type_resolution.zig index ef8e24c86744023e52bef9d9c2d0f1f029936852..1e089955e59e2efcbd3b40185cab8289460c956f 100644 --- a/src/Sema/type_resolution.zig +++ b/src/Sema/type_resolution.zig @@ -116,7 +116,10 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) { return sema.failWithDependencyLoop(.wrap(.{ .type_layout = ty.toIntern() }), reason); } - try pt.ensureTypeLayoutUpToDate(ty, reason); + pt.ensureTypeLayoutUpToDate(ty, reason) catch |err| switch (err) { + error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .type_layout = ty.toIntern() }) }), + else => |e| return e, + }; }, // values, not types @@ -166,7 +169,10 @@ pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type, src: LazySrcLoc) Sema return sema.failWithDependencyLoop(.wrap(.{ .struct_defaults = ty.toIntern() }), &reason); } - try pt.ensureStructDefaultsUpToDate(ty, &reason); + pt.ensureStructDefaultsUpToDate(ty, &reason) catch |err| switch (err) { + error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .struct_defaults = ty.toIntern() }) }), + else => |e| return e, + }; } /// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type. @@ -188,7 +194,9 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { const struct_obj = ip.loadStructType(struct_ty.toIntern()); assert(struct_obj.want_layout); - const zir_index = struct_obj.zir_index.resolve(ip) orelse return error.AnalysisFail; + const zir_index = struct_obj.zir_index.resolve(ip) orelse { + return sema.failTransitive(.{ .lost_tracking = struct_obj.zir_index }); + }; var block: Block = .{ .parent = null, @@ -364,7 +372,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { const a = struct_obj.field_aligns.get(ip)[field_idx]; if (a != .none) break :a a; } - break :a field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu); + break :a field_ty.abiAlignment(zcu); }; align_out.* = field_align; if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) { @@ -606,7 +614,7 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { struct_ty.assertHasLayout(zcu); const layout_unit: InternPool.AnalUnit = .wrap(.{ .type_layout = struct_ty.toIntern() }); if (zcu.failed_analysis.contains(layout_unit) or zcu.transitive_failed_analysis.contains(layout_unit)) { - return error.AnalysisFail; + return sema.failTransitive(.{ .failed_unit = layout_unit }); } const struct_obj = ip.loadStructType(struct_ty.toIntern()); @@ -656,7 +664,9 @@ fn resolveStructDefaultsInner( assert(struct_obj.field_defaults.len > 0); // We'll need to map the struct decl instruction to provide result types - const zir_index = struct_obj.zir_index.resolve(ip) orelse return error.AnalysisFail; + const zir_index = struct_obj.zir_index.resolve(ip) orelse { + return sema.failTransitive(.{ .lost_tracking = struct_obj.zir_index }); + }; try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); const field_types = struct_obj.field_types.get(ip); @@ -713,7 +723,9 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { const union_obj = ip.loadUnionType(union_ty.toIntern()); assert(union_obj.want_layout); - const zir_index = union_obj.zir_index.resolve(ip) orelse return error.AnalysisFail; + const zir_index = union_obj.zir_index.resolve(ip) orelse { + return sema.failTransitive(.{ .lost_tracking = union_obj.zir_index }); + }; var block: Block = .{ .parent = null, @@ -1212,7 +1224,9 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { }; const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index; - const zir_index = tracked_inst.resolve(ip) orelse return error.AnalysisFail; + const zir_index = tracked_inst.resolve(ip) orelse { + return sema.failTransitive(.{ .lost_tracking = tracked_inst }); + }; var block: Block = .{ .parent = null, diff --git a/src/Type.zig b/src/Type.zig index e60726ced3ff48df988eff1505786071c596ff2a..466a707b998294905c7d068acc1f2c98193232dc 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -957,12 +957,27 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { if (vector_type.len == 0) return .@"1"; switch (zcu.comp.getZigBackend()) { else => { - const elem_bits: u32 = @intCast(Type.fromInterned(vector_type.child).bitSize(zcu)); + const elem_ty: Type = .fromInterned(vector_type.child); + switch (if (elem_ty.isRuntimeFloat()) + std.zig.target.compilerRtFloatAbi(target, elem_ty.floatBits(target)) + else + .hard) { + .hard => {}, + .soft => return elem_ty.abiAlignment(zcu), + } + const elem_bits: u32 = @intCast(elem_ty.bitSize(zcu)); if (elem_bits == 0) return .@"1"; const bytes = ((elem_bits * vector_type.len) + 7) / 8; - return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes)); + const arch = target.cpu.arch; + return .fromByteUnits(std.math.ceilPowerOfTwoAssert( + u32, + if (arch.isArm() or arch.isAARCH64() or arch == .s390x) + @min(bytes, target.stackAlignment()) + else + bytes, + )); }, - .stage2_c, .stage2_wasm => return Type.fromInterned(vector_type.child).defaultStructFieldAlignment(.auto, zcu), + .stage2_c, .stage2_wasm => return Type.fromInterned(vector_type.child).abiAlignment(zcu), .stage2_x86_64 => { if (vector_type.child == .bool_type) { if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .@"64"; @@ -1018,19 +1033,33 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { .c_ulonglong => cTypeAlign(target, .ulonglong), .c_longdouble => cTypeAlign(target, .longdouble), - .f16 => .@"2", - .f32 => if (target.os.tag == .opengl) .@"4" else cTypeAlign(target, .float), - .f64 => if (target.os.tag == .opengl) .@"8" else switch (target.cTypeBitSize(.double)) { - 64 => cTypeAlign(target, .double), - else => .@"8", - }, - .f80 => switch (target.cTypeBitSize(.longdouble)) { - 80 => cTypeAlign(target, .longdouble), - else => Type.u80.abiAlignment(zcu), - }, - .f128 => switch (target.cTypeBitSize(.longdouble)) { - 128 => cTypeAlign(target, .longdouble), - else => .@"16", + .f16 => .fromByteUnits(std.zig.target.intAlignment(target, 16)), // repr: u16 + .f32 => if (target.cTypeBitSize(.float) == 32) + cTypeAlign(target, .float) // abi: c_float, + else + .fromByteUnits(std.zig.target.intAlignment(target, 32)), // repr: u32, + .f64 => if (target.cTypeBitSize(.double) == 64) + cTypeAlign(target, .double) // abi: c_double, + else + .fromByteUnits(std.zig.target.intAlignment(target, 64)), // repr: u64, + .f80 => if (target.cTypeBitSize(.longdouble) == 80) + cTypeAlign(target, .longdouble) // abi: c_longdouble, + else + .fromByteUnits(switch (std.zig.target.compilerRtFloatAbi(target, 80)) { + .hard => std.zig.target.intAlignment(target, 80), // repr: u80, + .soft => @max( + std.zig.target.intAlignment(target, 64), // mantissa: u64, + std.zig.target.intAlignment(target, 16), // exponent: u16, + ), + }), + .f128 => if (target.cTypeBitSize(.longdouble) == 128) + cTypeAlign(target, .longdouble) // abi: c_longdouble, + else switch (std.zig.target.compilerRtFloatAbi(target, 128)) { + .hard => if (target.cpu.arch.isX86()) + .@"16" // abi: c___float128, + else + .fromByteUnits(std.zig.target.intAlignment(target, 128)), // repr: u128, + .soft => .fromByteUnits(std.zig.target.intAlignment(target, 64)), // lo: u64, hi: u64, }, .generic_poison => unreachable, @@ -1111,7 +1140,13 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { .vector_type => |vec| { const elem_ty: Type = .fromInterned(vec.child); const bytes = switch (zcu.comp.getZigBackend()) { - else => @divCeil(vec.len * elem_ty.bitSize(zcu), 8), + else => switch (if (elem_ty.isRuntimeFloat()) + std.zig.target.compilerRtFloatAbi(target, elem_ty.floatBits(target)) + else + .hard) { + .hard => @divCeil(vec.len * elem_ty.bitSize(zcu), 8), + .soft => vec.len * elem_ty.abiSize(zcu), + }, .stage2_c, .stage2_wasm => vec.len * elem_ty.abiSize(zcu), .stage2_x86_64 => switch (elem_ty.toIntern()) { .bool_type => @divCeil(vec.len, 8), @@ -1167,25 +1202,44 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { .anyerror, .adhoc_inferred_error_set => errorAbiSize(zcu), .usize, .isize => ptrAbiSize(target), - .c_char => target.cTypeByteSize(.char), - .c_short => target.cTypeByteSize(.short), - .c_ushort => target.cTypeByteSize(.ushort), - .c_int => target.cTypeByteSize(.int), - .c_uint => target.cTypeByteSize(.uint), - .c_long => target.cTypeByteSize(.long), - .c_ulong => target.cTypeByteSize(.ulong), - .c_longlong => target.cTypeByteSize(.longlong), - .c_ulonglong => target.cTypeByteSize(.ulonglong), - .c_longdouble => target.cTypeByteSize(.longdouble), + .c_char => target.cTypeByteSize(.char).?, + .c_short => target.cTypeByteSize(.short).?, + .c_ushort => target.cTypeByteSize(.ushort).?, + .c_int => target.cTypeByteSize(.int).?, + .c_uint => target.cTypeByteSize(.uint).?, + .c_long => target.cTypeByteSize(.long).?, + .c_ulong => target.cTypeByteSize(.ulong).?, + .c_longlong => target.cTypeByteSize(.longlong).?, + .c_ulonglong => target.cTypeByteSize(.ulonglong).?, + .c_longdouble => target.cTypeByteSize(.longdouble).?, - .f16 => 2, - .f32 => 4, - .f64 => 8, - .f80 => switch (target.cTypeBitSize(.longdouble)) { - 80 => target.cTypeByteSize(.longdouble), - else => Type.u80.abiSize(zcu), + .f16 => std.zig.target.intByteSize(target, 16), // repr: u16 + .f32 => if (target.cTypeBitSize(.float) == 32) + target.cTypeByteSize(.float).? // abi: c_float, + else + std.zig.target.intByteSize(target, 32), // repr: u32, + .f64 => if (target.cTypeBitSize(.double) == 64) + target.cTypeByteSize(.double).? // abi: c_double, + else + std.zig.target.intByteSize(target, 64), // repr: u64, + .f80 => if (target.cTypeBitSize(.longdouble) == 80) + target.cTypeByteSize(.longdouble).? // abi: c_longdouble, + else switch (std.zig.target.compilerRtFloatAbi(target, 80)) { + .hard => std.zig.target.intByteSize(target, 80), // repr: u80, + .soft => ty.abiAlignment(zcu).forward( + std.zig.target.intByteSize(target, 64) + // mantissa: u64, + std.zig.target.intByteSize(target, 16), // exponent: u16 + ), + }, + .f128 => if (target.cTypeBitSize(.longdouble) == 128) + target.cTypeByteSize(.longdouble).? // abi: c_longdouble, + else switch (std.zig.target.compilerRtFloatAbi(target, 128)) { + .hard => if (target.cpu.arch.isX86()) + 16 // abi: c___float128, + else + std.zig.target.intByteSize(target, 128), // repr: u128, + .soft => std.zig.target.intByteSize(target, 64) * 2, // lo: u64, hi: u64, }, - .f128 => 16, .anyopaque => unreachable, .generic_poison => unreachable, @@ -1733,7 +1787,7 @@ pub fn isInt(self: Type, zcu: *const Zcu) bool { /// Returns true if and only if the type is a fixed-width, signed integer. pub fn isSignedInt(ty: Type, zcu: *const Zcu) bool { return switch (ty.toIntern()) { - .c_char_type => zcu.getTarget().cCharSignedness() == .signed, + .c_char_type => zcu.getTarget().cCharSignedness().? == .signed, .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true, else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) { .int_type => |int_type| int_type.signedness == .signed, @@ -1745,7 +1799,7 @@ pub fn isSignedInt(ty: Type, zcu: *const Zcu) bool { /// Returns true if and only if the type is a fixed-width, unsigned integer. pub fn isUnsignedInt(ty: Type, zcu: *const Zcu) bool { return switch (ty.toIntern()) { - .c_char_type => zcu.getTarget().cCharSignedness() == .unsigned, + .c_char_type => zcu.getTarget().cCharSignedness().? == .unsigned, .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true, else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) { .int_type => |int_type| int_type.signedness == .unsigned, @@ -1776,15 +1830,15 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { }, .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() }, .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() }, - .c_char_type => return .{ .signedness = zcu.getTarget().cCharSignedness(), .bits = target.cTypeBitSize(.char) }, - .c_short_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.short) }, - .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ushort) }, - .c_int_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.int) }, - .c_uint_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.uint) }, - .c_long_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.long) }, - .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulong) }, - .c_longlong_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.longlong) }, - .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong) }, + .c_char_type => return .{ .signedness = target.cCharSignedness().?, .bits = target.cTypeBitSize(.char).? }, + .c_short_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.short).? }, + .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ushort).? }, + .c_int_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.int).? }, + .c_uint_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.uint).? }, + .c_long_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.long).? }, + .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulong).? }, + .c_longlong_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.longlong).? }, + .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong).? }, else => switch (ip.indexToKey(ty.toIntern())) { .int_type => |int_type| return int_type, .struct_type => { @@ -1882,7 +1936,7 @@ pub fn floatBits(ty: Type, target: *const Target) u16 { .f64_type => 64, .f80_type => 80, .f128_type, .comptime_float_type => 128, - .c_longdouble_type => target.cTypeBitSize(.longdouble), + .c_longdouble_type => target.cTypeBitSize(.longdouble).?, else => unreachable, }; @@ -2147,13 +2201,6 @@ pub fn isVector(ty: Type, zcu: *const Zcu) bool { return ty.zigTypeTag(zcu) == .vector; } -/// Returns 0 if not a vector, otherwise returns @bitSizeOf(Element) * vector_len. -pub fn totalVectorBits(ty: Type, zcu: *Zcu) u64 { - if (!ty.isVector(zcu)) return 0; - const v = zcu.intern_pool.indexToKey(ty.toIntern()).vector_type; - return v.len * Type.fromInterned(v.child).bitSize(zcu); -} - pub fn isArrayOrVector(ty: Type, zcu: *const Zcu) bool { return switch (ty.zigTypeTag(zcu)) { .array, .vector => true, @@ -2416,34 +2463,6 @@ pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment }; } -/// Returns the alignment a struct field of type `field_ty` will be given if no alignment is -/// explicitly specified. However, in an `extern struct`, a higher alignment may be available due -/// to the struct's full layout (i.e. a field might coincidentally be more aligned). -/// -/// Asserts that the layout of `field_ty` is resolved. Asserts that `layout` is not `.@"packed"`. -pub fn defaultStructFieldAlignment( - field_ty: Type, - layout: std.lang.Type.ContainerLayout, - zcu: *const Zcu, -) Alignment { - const overalign_big_int = switch (layout) { - .@"packed" => unreachable, - .auto => zcu.getTarget().ofmt == .c, - .@"extern" => true, - }; - const abi_align = field_ty.abiAlignment(zcu); - assert(abi_align != .none); - // We check for anything over 64 here, because the C backend will lower e.g. u64 to a 128-bit - // integer, which has 16-byte alignment. - if (overalign_big_int and - ((field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits > 64) or - (field_ty.toIntern() == .f80_type and zcu.getTarget().cTypeBitSize(.longdouble) != 80))) - { - return abi_align.maxStrict(if (zcu.getTarget().cpu.arch == .s390x) .@"8" else .@"16"); - } - return abi_align; -} - pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) ?Value { const ip = &zcu.intern_pool; switch (ip.indexToKey(ty.toIntern())) { @@ -2961,8 +2980,7 @@ pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator } const actual_field_align = switch (field_align) { .none => switch (ip.indexToKey(aggregate_ty.toIntern())) { - .tuple_type, .union_type => field_ty.abiAlignment(zcu), - .struct_type => field_ty.defaultStructFieldAlignment(.auto, zcu), + .struct_type, .tuple_type, .union_type => field_ty.abiAlignment(zcu), .ptr_type => Type.usize.abiAlignment(zcu), else => unreachable, }, @@ -3122,7 +3140,6 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool .@"opaque", .bool, - .float, .@"anyframe", => true, @@ -3144,6 +3161,10 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool 24, 48 => zcu.getTarget().cpu.arch == .ez80, else => false, }, + .float => switch (ty.floatBits(zcu.getTarget())) { + else => true, + 80 => zcu.getTarget().cTypeBitSize(.longdouble) == 80, + }, .@"fn" => { if (position != .other) return false; return validateExternCallconv(ty.fnCallingConvention(zcu)); @@ -3600,5 +3621,5 @@ pub fn smallestUnsignedBits(max: u64) u16 { pub const packed_struct_layout_version = 2; fn cTypeAlign(target: *const Target, c_type: Target.CType) Alignment { - return Alignment.fromByteUnits(target.cTypeAlignment(c_type)); + return .fromByteUnits(target.cTypeAlignment(c_type).?); } diff --git a/src/Value.zig b/src/Value.zig index dfc124659c3f6d9fb3be15430a5734ff2a3fe194..a5b685c7913117befb984dfb85dd5d7f081e5721 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -611,12 +611,7 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *const Zcu) T { return switch (zcu.intern_pool.indexToKey(val.toIntern())) { .int => |int| switch (int.storage) { .big_int => |big_int| big_int.toFloat(T, .nearest_even)[0], - inline .u64, .i64 => |x| { - if (T == f80) { - @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); - } - return @floatFromInt(x); - }, + inline .u64, .i64 => |x| @floatFromInt(x), }, .float => |float| switch (float.storage) { inline else => |x| @floatCast(x), @@ -959,7 +954,7 @@ pub fn anyScalarIsZero(val: Value, zcu: *Zcu) bool { .bytes => |str| { const len = Type.fromInterned(agg.ty).vectorLen(zcu); const slice = str.toSlice(len, &zcu.intern_pool); - return std.mem.indexOfScalar(u8, slice, 0) != null; + return std.mem.findScalar(u8, slice, 0) != null; }, .elems => |elems| { for (elems) |elem| { diff --git a/src/Zcu.zig b/src/Zcu.zig index d3c180b63eb8854ec8598cdb3099bba7a41fb2b3..5f64440990c95be60453ee38c1dde3d2850a058f 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -182,7 +182,10 @@ analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg) = .empty, /// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed. -transitive_failed_analysis: std.array_hash_map.Auto(AnalUnit, void) = .empty, +transitive_failed_analysis: std.array_hash_map.Auto( + AnalUnit, + if (build_options.enable_debug_extensions) TransitiveFailureReason else void, +) = .empty, /// This `Nav` succeeded analysis, but failed codegen. /// This may be a simple "value" `Nav`, or it may be a function. /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. @@ -351,6 +354,18 @@ pub const DependencyReason = struct { type_layout_reason: Sema.type_resolution.LayoutResolveReason, }; +/// These are not required for anything, but when the compiler is built with debug extensions, we +/// store these in `Zcu.transitive_failed_analysis` and surface them in the incremental debug server +/// (see `src/IncrementalDebugServer.zig`) because they are a useful debugging aid for bugs in +/// incremental compilation. +pub const TransitiveFailureReason = union(enum) { + astgen_error, + dependency_loop, + lost_tracking: InternPool.TrackedInst.Index, + failed_unit: AnalUnit, + func_nav_val_changed: InternPool.Index, +}; + pub const IncrementalDebugState = struct { /// All container types in the ZCU, even dead ones. /// Value is the generation the type was created on. @@ -488,6 +503,7 @@ pub const StdLangDecl = enum { @"panic.castToNull", @"panic.incorrectAlignment", @"panic.invalidErrorCode", + @"panic.unexpectedErrorCode", @"panic.integerOutOfBounds", @"panic.integerOverflow", @"panic.shlOverflow", @@ -502,6 +518,7 @@ pub const StdLangDecl = enum { @"panic.copyLenMismatch", @"panic.memcpyAlias", @"panic.noreturnReturned", + @"panic.loadUninstantiableType", VaList, @@ -577,6 +594,7 @@ pub const StdLangDecl = enum { .@"panic.castToNull", .@"panic.incorrectAlignment", .@"panic.invalidErrorCode", + .@"panic.unexpectedErrorCode", .@"panic.integerOutOfBounds", .@"panic.integerOverflow", .@"panic.shlOverflow", @@ -591,6 +609,7 @@ pub const StdLangDecl = enum { .@"panic.copyLenMismatch", .@"panic.memcpyAlias", .@"panic.noreturnReturned", + .@"panic.loadUninstantiableType", => .func, }; } @@ -633,7 +652,7 @@ pub const StdLangDecl = enum { return switch (decl) { inline else => |tag| { const name = @tagName(tag); - const split = (comptime std.mem.lastIndexOfScalar(u8, name, '.')) orelse return .{ .direct = name }; + const split = (comptime std.mem.findScalarLast(u8, name, '.')) orelse return .{ .direct = name }; const parent = @field(StdLangDecl, name[0..split]); comptime assert(@backingInt(parent) < @backingInt(tag)); // dependencies ordered correctly return .{ .nested = .{ parent, name[split + 1 ..] } }; @@ -664,6 +683,7 @@ pub const SimplePanicId = enum { copy_len_mismatch, memcpy_alias, noreturn_returned, + load_uninstantiable_type, pub fn toStdLangDecl(id: SimplePanicId) StdLangDecl { return switch (id) { @@ -687,6 +707,7 @@ pub const SimplePanicId = enum { .copy_len_mismatch => .@"panic.copyLenMismatch", .memcpy_alias => .@"panic.memcpyAlias", .noreturn_returned => .@"panic.noreturnReturned", + .load_uninstantiable_type => .@"panic.loadUninstantiableType", // zig fmt: on }; } @@ -2808,13 +2829,13 @@ pub const LazySrcLoc = struct { } }; -pub const SemaError = error{ OutOfMemory, Canceled, AnalysisFail }; +pub const SemaError = error{ OutOfMemory, Canceled, AlreadyReported }; pub const CompileError = error{ OutOfMemory, /// The compilation update is no longer desired. Canceled, /// When this is returned, the compile error for the failure has already been recorded. - AnalysisFail, + AlreadyReported, /// In a comptime scope, a return instruction was encountered. This error is only seen when /// doing a comptime function call. ComptimeReturn, @@ -2825,6 +2846,11 @@ pub const CompileError = error{ pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void { try zcu.intern_pool.init(gpa, io, thread_count); +} + +/// It is valid to not call this function before `deinit` in error paths. +/// Requires the fields on `zcu.comp` to already be initialized. +pub fn initAfterCompilation(zcu: *Zcu) void { zcu.initTracyPlots(); } @@ -4273,7 +4299,7 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana const fqn_slice = nav.fqn.toSlice(ip); if (comp.test_filters.len > 0) { for (comp.test_filters) |test_filter| { - if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break; + if (std.mem.find(u8, fqn_slice, test_filter) != null) break; } else break :a false; } break :a true; @@ -4597,6 +4623,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) .x86_64_regcall_v3_sysv, .x86_64_regcall_v4_win, .x86_64_interrupt, + .x86_64_preserve_none, .x86_fastcall, .x86_thiscall, .x86_vectorcall, @@ -4605,6 +4632,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) .x86_interrupt, .aarch64_vfabi, .aarch64_vfabi_sve, + .aarch64_preserve_none, .arm_aapcs, .csky_interrupt, .riscv64_lp64_v, @@ -4612,43 +4640,26 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) .m68k_rtd, .m68k_interrupt, .msp430_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .arm_aapcs_vfp, - => |opts| opts.incoming_stack_alignment == null, - .arc_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .arm_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .microblaze_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .mips_interrupt, .mips64_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .riscv32_interrupt, .riscv64_interrupt, - => |opts| opts.incoming_stack_alignment == null, - .sh_interrupt, - => |opts| opts.incoming_stack_alignment == null, + .avr_interrupt, + .avr_signal, + .ez80_tiflags, + .naked, + => true, // incoming stack alignment supported .x86_sysv, .x86_win, + .x86_mingw, .x86_stdcall, - => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0, - - .avr_interrupt, - .avr_signal, - => true, - - .ez80_tiflags => true, - - .naked => true, + => |opts| opts.register_params == 0, // incoming stack alignment supported else => false, }; @@ -4673,6 +4684,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) .stage2_x86 => switch (cc) { .x86_sysv, .x86_win, + .x86_mingw, => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0, .naked => true, else => false, diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index cabb5ea749fc8a939ac67f624e25cae8cee87546..64240f77c1c721bfcf90be0def4bb92aa7b07e99 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -320,7 +320,7 @@ pub fn update( // Zig compilation pipeline. It selects some `AnalUnit` which we know needs to be analyzed, // and analyzes it, which may in turn discover more `AnalUnit`s which we need to analyze. while (try zcu.findOutdatedToAnalyze()) |unit| { - const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) { + const maybe_err: UpdateUnitError!void = switch (unit.unwrap()) { .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu), .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav, null), .nav_val => |nav| pt.ensureNavValUpToDate(nav, null), @@ -332,7 +332,7 @@ pub fn update( error.Canceled, => |e| return e, - error.AnalysisFail => {}, // already reported + error.AnalysisFail => {}, }; break :res pt.ensureStructDefaultsUpToDate(.fromInterned(ty), null); }, @@ -344,7 +344,7 @@ pub fn update( error.Canceled, => |e| return e, - error.AnalysisFail => {}, // already reported + error.AnalysisFail => {}, }; } } @@ -455,7 +455,7 @@ fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zc /// Ensures that `file` has up-to-date ZIR. If not, loads the ZIR cache or runs /// AstGen as needed. Also updates `file.status`. Does not assume that `file.mod` -/// is populated. Does not return `error.AnalysisFail` on AstGen failures. +/// is populated. Returns success even if the file has AstGen errors. pub fn updateFile( pt: Zcu.PerThread, file_index: Zcu.File.Index, @@ -876,6 +876,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { const old_line = old_zir.getDeclaration(old_inst).src_line; const new_line = new_zir.getDeclaration(new_inst).src_line; if (old_line != new_line) { + comp.link_prog_node.increaseEstimatedTotalItems(1); try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .debug_update_line_number = tracked_inst_index }); } }, @@ -1035,6 +1036,11 @@ pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloc zcu.setFileRootType(file_index, wip.finish(ip, new_namespace_index)); } +const UpdateUnitError = Allocator.Error || Io.Cancelable || error{ + /// Semantic analysis of this `AnalUnit` failed. + AnalysisFail, +}; + /// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary. /// Returns `error.AnalysisFail` if an analysis error is encountered; the caller is free to ignore /// this, since the error is already registered, but it must not use the value of memoized fields. @@ -1043,7 +1049,7 @@ pub fn ensureMemoizedStateUpToDate( stage: InternPool.MemoizedStateStage, /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, -) Zcu.SemaError!void { +) UpdateUnitError!void { const zcu = pt.zcu; const gpa = zcu.gpa; @@ -1077,15 +1083,7 @@ pub fn ensureMemoizedStateUpToDate( const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage, reason)) |any_changed| .{ any_changed or prev_failed, false } else |err| switch (err) { - error.AnalysisFail => res: { - if (!zcu.failed_analysis.contains(unit)) { - // If this unit caused the error, it would have an entry in `failed_analysis`. - // Since it does not, this must be a transitive failure. - try zcu.transitive_failed_analysis.put(gpa, unit, {}); - log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(unit)}); - } - break :res .{ !prev_failed, true }; - }, + error.AlreadyReported => .{ !prev_failed, true }, error.OutOfMemory => { // TODO: same as for `ensureComptimeUnitUpToDate` etc return error.OutOfMemory; @@ -1153,7 +1151,7 @@ fn analyzeMemoizedState( /// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis /// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is /// free to ignore this, since the error is already registered. -pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.SemaError!void { +pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) UpdateUnitError!void { const zcu = pt.zcu; const gpa = zcu.gpa; @@ -1194,15 +1192,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU defer unit_tracking.end(zcu); return pt.analyzeComptimeUnit(cu_id) catch |err| switch (err) { - error.AnalysisFail => { - if (!zcu.failed_analysis.contains(anal_unit)) { - // If this unit caused the error, it would have an entry in `failed_analysis`. - // Since it does not, this must be a transitive failure. - try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); - } - return error.AnalysisFail; - }, + error.AlreadyReported => return error.AnalysisFail, error.OutOfMemory => { // TODO: it's unclear how to gracefully handle this. // To report the error cleanly, we need to add a message to `failed_analysis` and a @@ -1220,8 +1210,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU /// Re-analyzes a `ComptimeUnit`. The unit has already been determined to be out-of-date, and old /// side effects (exports/references/etc) have been dropped. If semantic analysis fails, this -/// function will return `error.AnalysisFail`, and it is the caller's reponsibility to add an entry -/// to `transitive_failed_analysis` if necessary. +/// function will return `error.AlreadyReported`. fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.CompileError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -1238,7 +1227,14 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu defer tracy_trace.end(); tracy_trace.addTextFmt("cu_id={d}", .{cu_id}); - const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail; + const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse { + try zcu.transitive_failed_analysis.putNoClobber( + gpa, + anal_unit, + if (build_options.enable_debug_extensions) .{ .lost_tracking = comptime_unit.zir_index }, + ); + return error.AlreadyReported; + }; const file = zcu.fileByIndex(inst_resolved.file); const zir = file.zir.?; @@ -1313,7 +1309,7 @@ pub fn ensureTypeLayoutUpToDate( ty: Type, /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, -) Zcu.SemaError!void { +) UpdateUnitError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const comp = zcu.comp; @@ -1398,15 +1394,7 @@ pub fn ensureTypeLayoutUpToDate( const new_failed: bool = if (result) failed: { break :failed false; } else |err| switch (err) { - error.AnalysisFail => failed: { - if (!zcu.failed_analysis.contains(anal_unit)) { - // If this unit caused the error, it would have an entry in `failed_analysis`. - // Since it does not, this must be a transitive failure. - try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); - } - break :failed true; - }, + error.AlreadyReported => true, error.OutOfMemory, error.Canceled, => |e| return e, @@ -1441,7 +1429,7 @@ pub fn ensureStructDefaultsUpToDate( ty: Type, /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, -) Zcu.SemaError!void { +) UpdateUnitError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const comp = zcu.comp; @@ -1512,15 +1500,7 @@ pub fn ensureStructDefaultsUpToDate( const new_failed: bool = if (Sema.type_resolution.resolveStructDefaults(&sema, ty)) failed: { break :failed false; } else |err| switch (err) { - error.AnalysisFail => failed: { - if (!zcu.failed_analysis.contains(anal_unit)) { - // If this unit caused the error, it would have an entry in `failed_analysis`. - // Since it does not, this must be a transitive failure. - try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); - } - break :failed true; - }, + error.AlreadyReported => true, error.OutOfMemory, error.Canceled, => |e| return e, @@ -1546,7 +1526,7 @@ pub fn ensureNavValUpToDate( nav_id: InternPool.Nav.Index, /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, -) Zcu.SemaError!void { +) UpdateUnitError!void { const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; @@ -1593,15 +1573,7 @@ pub fn ensureNavValUpToDate( false, }; } else |err| switch (err) { - error.AnalysisFail => res: { - if (!zcu.failed_analysis.contains(anal_unit)) { - // If this unit caused the error, it would have an entry in `failed_analysis`. - // Since it does not, this must be a transitive failure. - try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); - } - break :res .{ !prev_failed, true }; - }, + error.AlreadyReported => .{ !prev_failed, true }, error.OutOfMemory => { // TODO: it's unclear how to gracefully handle this. // To report the error cleanly, we need to add a message to `failed_analysis` and a @@ -1654,7 +1626,14 @@ fn analyzeNavVal( tracy_trace.addText(old_nav.fqn.toSlice(ip)); tracy_trace.addTextFmt("nav_id={d}", .{nav_id}); - const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail; + const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse { + try zcu.transitive_failed_analysis.putNoClobber( + gpa, + anal_unit, + if (build_options.enable_debug_extensions) .{ .lost_tracking = old_nav.analysis.?.zir_index }, + ); + return error.AlreadyReported; + }; const file = zcu.fileByIndex(inst_resolved.file); const zir = file.zir.?; const zir_decl = zir.getDeclaration(inst_resolved.inst); @@ -1915,7 +1894,7 @@ pub fn ensureNavTypeUpToDate( nav_id: InternPool.Nav.Index, /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, -) Zcu.SemaError!void { +) UpdateUnitError!void { const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; @@ -1962,15 +1941,7 @@ pub fn ensureNavTypeUpToDate( false, }; } else |err| switch (err) { - error.AnalysisFail => res: { - if (!zcu.failed_analysis.contains(anal_unit)) { - // If this unit caused the error, it would have an entry in `failed_analysis`. - // Since it does not, this must be a transitive failure. - try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); - } - break :res .{ !prev_failed, true }; - }, + error.AlreadyReported => .{ !prev_failed, true }, error.OutOfMemory => { // TODO: it's unclear how to gracefully handle this. // To report the error cleanly, we need to add a message to `failed_analysis` and a @@ -2023,7 +1994,14 @@ fn analyzeNavType( tracy_trace.addText(old_nav.fqn.toSlice(ip)); tracy_trace.addTextFmt("nav_id={d}", .{nav_id}); - const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail; + const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse { + try zcu.transitive_failed_analysis.putNoClobber( + gpa, + anal_unit, + if (build_options.enable_debug_extensions) .{ .lost_tracking = old_nav.analysis.?.zir_index }, + ); + return error.AlreadyReported; + }; const file = zcu.fileByIndex(inst_resolved.file); const zir = file.zir.?; @@ -2159,7 +2137,7 @@ pub fn ensureFuncBodyUpToDate( func_index: InternPool.Index, /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`. reason: ?*const Zcu.DependencyReason, -) Zcu.SemaError!void { +) UpdateUnitError!void { dev.check(.sema); const zcu = pt.zcu; @@ -2203,18 +2181,10 @@ pub fn ensureFuncBodyUpToDate( const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index, reason)) |result| .{ prev_failed or result.ies_outdated, false } else |err| switch (err) { - error.AnalysisFail => res: { - if (!zcu.failed_analysis.contains(anal_unit)) { - // If this function caused the error, it would have an entry in `failed_analysis`. - // Since it does not, this must be a transitive failure. - try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); - } - // We consider the IES to be outdated if the function previously succeeded analysis; in this case, - // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting - // a different error later (which may now be invalid). - break :res .{ !prev_failed, true }; - }, + // We consider the IES to be outdated if the function previously succeeded analysis; in this case, + // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting + // a different error later (which may now be invalid). + error.AlreadyReported => .{ !prev_failed, true }, error.OutOfMemory => { // TODO: it's unclear how to gracefully handle this. // To report the error cleanly, we need to add a message to `failed_analysis` and a @@ -3206,7 +3176,7 @@ const ScanDeclIter = struct { if (is_named and comp.test_filters.len > 0) { const fqn_slice = fqn.toSlice(ip); for (comp.test_filters) |test_filter| { - if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break; + if (std.mem.find(u8, fqn_slice, test_filter) != null) break; } else break :a false; } try zcu.test_functions.put(gpa, nav, {}); @@ -3292,9 +3262,7 @@ fn analyzeFuncBodyInner( defer sema.deinit(); // Every runtime function has a dependency on the source of the Decl it originates from. - // It also depends on the value of its owner Decl. try sema.declareDependency(.{ .src_hash = decl_analysis.zir_index }); - try sema.declareDependency(.{ .nav_val = func.owner_nav }); // Make sure that the declaration `Nav` still refers to this function (or its generic owner). // This will not be the case if the incremental update has changed a function type or turned a @@ -3305,15 +3273,23 @@ fn analyzeFuncBodyInner( // If we *are* still owned by the right NAV, this analysis updates `zir_body_inst` if necessary. if (func.generic_owner == .none) { - try pt.ensureNavValUpToDate(func.owner_nav, reason); + try sema.declareDependency(.{ .nav_val = func.owner_nav }); + pt.ensureNavValUpToDate(func.owner_nav, reason) catch |err| switch (err) { + error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .nav_val = func.owner_nav }) }), + else => |e| return e, + }; if (ip.getNav(func.owner_nav).resolved.?.value != func_index) { - return error.AnalysisFail; + return sema.failTransitive(.{ .func_nav_val_changed = func_index }); } } else { const go_nav = zcu.funcInfo(func.generic_owner).owner_nav; - try pt.ensureNavValUpToDate(go_nav, reason); + try sema.declareDependency(.{ .nav_val = go_nav }); + pt.ensureNavValUpToDate(go_nav, reason) catch |err| switch (err) { + error.AnalysisFail => return sema.failTransitive(.{ .failed_unit = .wrap(.{ .nav_val = go_nav }) }), + else => |e| return e, + }; if (ip.getNav(go_nav).resolved.?.value != func.generic_owner) { - return error.AnalysisFail; + return sema.failTransitive(.{ .func_nav_val_changed = func.generic_owner }); } } @@ -3343,7 +3319,9 @@ fn analyzeFuncBodyInner( }; defer inner_block.instructions.deinit(gpa); - const fn_info = sema.code.getFnInfo(func.zirBodyInstUnordered(ip).resolve(ip) orelse return error.AnalysisFail); + const fn_info = sema.code.getFnInfo(func.zirBodyInstUnordered(ip).resolve(ip) orelse { + return sema.failTransitive(.{ .lost_tracking = func.zirBodyInstUnordered(ip) }); + }); // Here we are performing "runtime semantic analysis" for a function body, which means // we must map the parameter ZIR instructions to `arg` AIR instructions. @@ -3520,6 +3498,25 @@ pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Err return pt.getErrorValue(try pt.zcu.intern_pool.getOrPutString(gpa, io, name)); } +/// Asserts that `slice.len` is *not* undef. +pub fn sliceToArrayPtr(pt: Zcu.PerThread, slice: InternPool.Key.Slice) Allocator.Error!Value { + const zcu = pt.zcu; + const slice_info = Type.fromInterned(slice.ty).ptrInfo(zcu); + const array_ty = try pt.arrayType(.{ + .len = Value.fromInterned(slice.len).toUnsignedInt(zcu), + .child = slice_info.child, + .sentinel = slice_info.sentinel, + }); + const ptr_ty = try pt.ptrType(ptr_info: { + var ptr_info = slice_info; + ptr_info.flags.size = .one; + ptr_info.child = array_ty.toIntern(); + ptr_info.sentinel = .none; + break :ptr_info ptr_info; + }); + return pt.getCoerced(.fromInterned(slice.ptr), ptr_ty); +} + /// Removes any entry from `Zcu.failed_files` associated with `file`. Acquires `Compilation.mutex` as needed. /// `file.zir` must be unchanged from the last update, as it is used to determine if there is such an entry. fn lockAndClearFileCompileError(pt: Zcu.PerThread, file_index: Zcu.File.Index, file: *Zcu.File) void { @@ -4377,12 +4374,18 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) (Io.Cancelable | return result.index; } +const UpdateNamespaceError = Allocator.Error || Io.Cancelable || error{ + /// This namespace refers to a ZIR container declaration which no longer exists, so any code + /// referencing it is guaranteed to be unreferenced on this update. + LostZirContainerDecl, +}; + /// Given a namespace, re-scan its declarations from the type definition if they have not /// yet been re-scanned on this update. -/// If the type declaration instruction has been lost, returns `error.AnalysisFail`. +/// If the type declaration instruction has been lost, returns `error.LostZirContainerDecl`. /// This will effectively short-circuit the caller, which will be semantic analysis of a /// guaranteed-unreferenced `AnalUnit`, to trigger a transitive analysis error. -pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) Zcu.SemaError!void { +pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) UpdateNamespaceError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const namespace = zcu.namespacePtr(namespace_index); @@ -4409,7 +4412,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace // Namespace outdated -- re-scan the type if necessary. - const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; + const inst_info = key.zir_index.resolveFull(ip) orelse return error.LostZirContainerDecl; const file = zcu.fileByIndex(inst_info.file); const zir = &file.zir.?; diff --git a/src/codegen.zig b/src/codegen.zig index a691b36a4811f7cf127de20aa50d33e2b6e8d700..326a9f1e2f52b90bb40bf4006000c3864a47fed5 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -767,11 +767,9 @@ fn lowerNavRef( offset: u64, ) (Error || std.Io.Writer.Error)!void { const zcu = pt.zcu; - const gpa = zcu.gpa; const ip = &zcu.intern_pool; const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8); - const is_obj = lf.comp.config.output_mode == .Obj; const nav_ty = Type.fromInterned(ip.getNav(nav_index).resolved.?.type); if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and ip.getNav(nav_index).getExtern(ip) == null) { @@ -786,34 +784,7 @@ fn lowerNavRef( dev.check(link.File.Tag.wasm.devFeature()); const wasm = lf.cast(.wasm).?; assert(reloc_parent == .none); - if (nav_ty.zigTypeTag(zcu) == .@"fn") { - const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index); - if (!gop.found_existing) gop.value_ptr.* = {}; - if (is_obj) { - @panic("TODO add out_reloc for this"); - } else { - try wasm.func_table_fixups.append(gpa, .{ - .table_index = @fromBackingInt(@intCast(gop.index)), - .offset = @intCast(w.end), - }); - } - } else { - if (is_obj) { - try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(w.end), - .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) }, - .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64, - .addend = @intCast(offset), - }); - } else { - try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1); - wasm.nav_fixups.appendAssumeCapacity(.{ - .navs_exe_index = try wasm.refNavExe(nav_index), - .offset = @intCast(w.end), - .addend = @intCast(offset), - }); - } - } + try wasm.addNavReloc(w.end, nav_index, nav_ty, @intCast(offset)); try w.splatByteAll(0, ptr_width_bytes); return; }, @@ -1124,6 +1095,201 @@ pub fn fieldOffset(ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32, zcu: }; } +pub const FlattenedItem = struct { offset: u64, type: ?Type }; +pub fn flattenType(items_buf: []FlattenedItem, ty: Type, zcu: *Zcu, opts: struct { + offset: u64 = 0, + allow_arrays: bool = true, + fn increaseOffset(opts: @This(), offset: u64) @This() { + return .{ + .offset = opts.offset + offset, + .allow_arrays = opts.allow_arrays, + }; + } +}) ?[]FlattenedItem { + const ip = &zcu.intern_pool; + switch (ip.indexToKey(ty.toIntern())) { + .int_type => |int_type| { + if (int_type.bits == 0) return items_buf[0..0]; + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .ptr_type => |ptr_type| switch (ptr_type.flags.size) { + .one, .many, .c => { + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .slice => { + if (items_buf.len < 2) return null; + const items = items_buf[0..2]; + const ptr_field_ty = ty.slicePtrFieldType(zcu); + items.* = .{ + .{ .offset = opts.offset, .type = ptr_field_ty }, + .{ .offset = opts.offset + ptr_field_ty.abiSize(zcu), .type = .usize }, + }; + return items; + }, + }, + .array_type => |array_type| { + const len = array_type.lenIncludingSentinel(); + if (len == 0) return items_buf[0..0]; + const elem_ty: Type = .fromInterned(array_type.child); + const elem_items = flattenType(items_buf, elem_ty, zcu, opts) orelse return null; + if (elem_items.len == 0) return items_buf[0..0]; + if (!opts.allow_arrays) return null; + const items_len, const items_overflow = @mulWithOverflow(elem_items.len, len); + if (items_overflow != 0 or items_buf.len < items_len) return null; + var items_index = elem_items.len; + const elem_size = elem_ty.abiSize(zcu); + var elem_offset: u64 = elem_size; + while (items_index != items_len) : ({ + items_index += elem_items.len; + elem_offset += elem_size; + }) for (items_buf[items_index..][0..elem_items.len], elem_items) |*item, elem_item| { + item.* = .{ .offset = elem_offset + elem_item.offset, .type = elem_item.type }; + }; + return items_buf[0..@intCast(items_len)]; + }, + .vector_type => |vector_type| { + if (vector_type.len == 0) return items_buf[0..0]; + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .opt_type, .error_union_type => return null, + .simple_type => |simple_type| switch (simple_type) { + .f16, + .f32, + .f64, + .f80, + .f128, + .usize, + .isize, + .c_char, + .c_short, + .c_ushort, + .c_int, + .c_uint, + .c_long, + .c_ulong, + .c_longlong, + .c_ulonglong, + .c_longdouble, + .bool, + .anyerror, + => { + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .anyopaque, .noreturn => return null, + .void, + .type, + .comptime_int, + .comptime_float, + .null, + .undefined, + .enum_literal, + => return items_buf[0..0], + .adhoc_inferred_error_set, .generic_poison => unreachable, + }, + .struct_type => { + const loaded_struct = ip.loadStructType(ty.toIntern()); + switch (loaded_struct.layout) { + .auto, .@"extern" => {}, + .@"packed" => return flattenType(items_buf, .fromInterned( + loaded_struct.packed_backing_int_type, + ), zcu, opts), + } + var items_len: usize = 0; + var offset: u64 = 0; + var field_it = loaded_struct.iterateRuntimeOrder(ip); + while (field_it.next()) |field_index| { + const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const field_offset = loaded_struct.field_offsets.get(ip)[field_index]; + if (field_offset - offset > 0 and + (items_len == 0 or items_buf[items_len - 1].type != null)) + { + if (items_len == items_buf.len) return null; + items_buf[items_len] = .{ .offset = offset, .type = null }; + items_len += 1; + } + items_len += (flattenType(items_buf[items_len..], field_ty, zcu, opts.increaseOffset( + field_offset, + )) orelse return null).len; + offset = field_offset + field_ty.abiSize(zcu); + } + if (ty.abiSize(zcu) - offset > 0 and + (items_len == 0 or items_buf[items_len - 1].type != null)) + { + if (items_len == items_buf.len) return null; + items_buf[items_len] = .{ .offset = offset, .type = null }; + items_len += 1; + } + return items_buf[0..items_len]; + }, + .tuple_type => |tuple_type| { + if (items_buf.len < tuple_type.types.len) return null; + var items_len: usize = 0; + var offset: u64 = 0; + for (tuple_type.types.get(ip)) |field_ty_ip| { + const field_ty: Type = .fromInterned(field_ty_ip); + offset = field_ty.abiAlignment(zcu).forward(offset); + items_len += (flattenType(items_buf[items_len..], field_ty, zcu, opts.increaseOffset( + offset, + )) orelse return null).len; + offset += field_ty.abiSize(zcu); + } + return items_buf[0..items_len]; + }, + .union_type => { + const loaded_union = ip.loadUnionType(ty.toIntern()); + return switch (loaded_union.layout) { + .auto, .@"extern" => return null, + .@"packed" => return flattenType(items_buf, .fromInterned( + loaded_union.packed_backing_int_type, + ), zcu, opts), + }; + }, + .opaque_type, .spirv_type, .func_type => return null, + .enum_type => return flattenType(items_buf, .fromInterned( + ip.loadEnumType(ty.toIntern()).int_tag_type, + ), zcu, opts), + .error_set_type, .inferred_error_set_type => { + if (items_buf.len < 1) return null; + const items = items_buf[0..1]; + items.* = .{.{ .offset = opts.offset, .type = ty }}; + return items; + }, + .anyframe_type, + // values, not types + .undef, + .simple_value, + .@"extern", + .func, + .int, + .err, + .error_union, + .enum_literal, + .enum_tag, + .float, + .ptr, + .slice, + .opt, + .aggregate, + .un, + .bitpack, + // memoization, not types + .memoized_call, + => unreachable, + } +} + test { _ = aarch64; } diff --git a/src/codegen/aarch64/Assemble.zig b/src/codegen/aarch64/Assemble.zig index 2875f6fc960e211f684d37815ba86de291fd8453..2d5cc913270f0259caa726e4073b34e1992fef8f 100644 --- a/src/codegen/aarch64/Assemble.zig +++ b/src/codegen/aarch64/Assemble.zig @@ -163,7 +163,7 @@ const matchers = matchers: { arg.* = zonCast(param_type.?, instruction.encode[encode_index], symbols); return @call(.auto, encode, args); } else if (pattern_token[0] == '<') { - const symbol_name = comptime pattern_token[1 .. std.mem.indexOfScalarPos(u8, pattern_token, 1, '|') orelse + const symbol_name = comptime pattern_token[1 .. std.mem.findScalarPos(u8, pattern_token, 1, '|') orelse pattern_token.len - 1]; const symbol = @field(Symbol, symbol_name); const symbol_ptr = &@field(symbols, symbol_name); diff --git a/src/codegen/aarch64/Mir.zig b/src/codegen/aarch64/Mir.zig index 7b976acde1c5401ef294ede213416828c55d26a9..ad40e86902d4273b2b558fa1b1b97add12b29345 100644 --- a/src/codegen/aarch64/Mir.zig +++ b/src/codegen/aarch64/Mir.zig @@ -70,8 +70,8 @@ pub fn emit( const func_align = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { - .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), - .ReleaseSmall => target_util.minFunctionAlignment(target), + .debug, .safe, .fast => target_util.defaultFunctionAlignment(target), + .small => target_util.minFunctionAlignment(target), }, else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), }; diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index 30387bfe8a37719577b57391f6f270e71e8238e2..1e5f1cbb6e7eee1fc176bff68fa0511dd8ec1b7a 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -2099,7 +2099,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "truncf", 64 => "trunc", 80 => "__truncx", - 128 => "truncq", + 128 => "truncf128", }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); @@ -2113,7 +2113,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "floorf", 64 => "floor", 80 => "__floorx", - 128 => "floorq", + 128 => "floorf128", }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); @@ -2431,7 +2431,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "fmodf", 64 => "fmod", 80 => "__fmodx", - 128 => "fmodq", + 128 => "fmodf128", }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); @@ -2599,7 +2599,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "fmaxf", 64 => "fmax", 80 => "__fmaxx", - 128 => "fmaxq", + 128 => "fmaxf128", }, .min => switch (bits) { else => unreachable, @@ -2607,7 +2607,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "fminf", 64 => "fmin", 80 => "__fminx", - 128 => "fminq", + 128 => "fminf128", }, }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, @@ -2856,7 +2856,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const remaining_source = std.mem.span(as.source); return isel.fail("unable to assemble: '{s}'", .{std.mem.trim( u8, - as.source[0 .. std.mem.indexOfScalar(u8, remaining_source, '\n') orelse remaining_source.len], + as.source[0 .. std.mem.findScalar(u8, remaining_source, '\n') orelse remaining_source.len], &std.ascii.whitespace, )}); }, @@ -4055,7 +4055,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "sqrtf", 64 => "sqrt", 80 => "__sqrtx", - 128 => "sqrtq", + 128 => "sqrtf128", }, .floor => switch (bits) { else => unreachable, @@ -4063,7 +4063,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "floorf", 64 => "floor", 80 => "__floorx", - 128 => "floorq", + 128 => "floorf128", }, .ceil => switch (bits) { else => unreachable, @@ -4071,7 +4071,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "ceilf", 64 => "ceil", 80 => "__ceilx", - 128 => "ceilq", + 128 => "ceilf128", }, .round => switch (bits) { else => unreachable, @@ -4079,7 +4079,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "roundf", 64 => "round", 80 => "__roundx", - 128 => "roundq", + 128 => "roundf128", }, .trunc_float => switch (bits) { else => unreachable, @@ -4087,7 +4087,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "truncf", 64 => "trunc", 80 => "__truncx", - 128 => "truncq", + 128 => "truncf128", }, }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, @@ -4147,7 +4147,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "sinf", 64 => "sin", 80 => "__sinx", - 128 => "sinq", + 128 => "sinf128", }, .cos => switch (bits) { else => unreachable, @@ -4155,7 +4155,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "cosf", 64 => "cos", 80 => "__cosx", - 128 => "cosq", + 128 => "cosf128", }, .tan => switch (bits) { else => unreachable, @@ -4163,7 +4163,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "tanf", 64 => "tan", 80 => "__tanx", - 128 => "tanq", + 128 => "tanf128", }, .exp => switch (bits) { else => unreachable, @@ -4171,7 +4171,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "expf", 64 => "exp", 80 => "__expx", - 128 => "expq", + 128 => "expf128", }, .exp2 => switch (bits) { else => unreachable, @@ -4179,7 +4179,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "exp2f", 64 => "exp2", 80 => "__exp2x", - 128 => "exp2q", + 128 => "exp2f128", }, .log => switch (bits) { else => unreachable, @@ -4187,7 +4187,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "logf", 64 => "log", 80 => "__logx", - 128 => "logq", + 128 => "logf128", }, .log2 => switch (bits) { else => unreachable, @@ -4195,7 +4195,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "log2f", 64 => "log2", 80 => "__log2x", - 128 => "log2q", + 128 => "log2f128", }, .log10 => switch (bits) { else => unreachable, @@ -4203,7 +4203,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "log10f", 64 => "log10", 80 => "__log10x", - 128 => "log10q", + 128 => "log10f128", }, }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, @@ -7118,7 +7118,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, 32 => "fmaf", 64 => "fma", 80 => "__fmax", - 128 => "fmaq", + 128 => "fmaf128", }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); @@ -12176,9 +12176,7 @@ pub const CallAbiIterator = struct { const loaded_struct = ip.loadStructType(ty.toIntern()); switch (loaded_struct.layout) { .auto, .@"extern" => {}, - .@"packed" => continue :type_key .{ - .int_type = ip.indexToKey(loaded_struct.packed_backing_int_type).int_type, - }, + .@"packed" => continue :type_key ip.indexToKey(loaded_struct.packed_backing_int_type), } const size = wip_vi.size(isel); if (size <= 16 * 4) homogeneous_aggregate: { @@ -12300,9 +12298,7 @@ pub const CallAbiIterator = struct { } }, .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque }, - .enum_type => continue :type_key .{ - .int_type = ip.indexToKey(ip.loadEnumType(ty.toIntern()).int_tag_type).int_type, - }, + .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).int_tag_type), .error_set_type, .inferred_error_set_type, => continue :type_key .{ .simple_type = .anyerror }, @@ -12388,7 +12384,7 @@ pub const CallAbiIterator = struct { .f32 => .single, .f64 => .double, .f128 => .quad, - .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble)) { + .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble).?) { else => unreachable, 64 => .double, 80 => null, diff --git a/src/codegen/aarch64/abi.zig b/src/codegen/aarch64/abi.zig index dcd192da8395fc6fca07c101aebff596bc4e99cc..863a45e2d4bded294e263edff46787942cbcb31b 100644 --- a/src/codegen/aarch64/abi.zig +++ b/src/codegen/aarch64/abi.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assert = std.debug.assert; const std = @import("std"); const InternPool = @import("../../InternPool.zig"); const Type = @import("../../Type.zig"); @@ -35,7 +35,12 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { if (bit_size > 64) return .double_integer; return .integer; }, - .int, .@"enum", .error_set, .float, .bool => return .byval, + .int, .@"enum", .error_set, .bool => return .byval, + .float => return switch (ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16, 32, 64, 128 => .byval, + 80 => .double_integer, + }, .vector => { const bit_size = ty.bitSize(zcu); // TODO is this controlled by a cpu feature? diff --git a/src/codegen/arm/abi.zig b/src/codegen/arm/abi.zig index 14acccbb7963991a3c9c201bcebaeb9218af7ff8..bd767560f1c0ac8fb3d5b8b6eed5956ea8e8253d 100644 --- a/src/codegen/arm/abi.zig +++ b/src/codegen/arm/abi.zig @@ -39,7 +39,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { const float_count = countFloats(ty, zcu, &maybe_float_bits); if (float_count <= byval_float_count) return .byval; - if (ty.abiAlignment(zcu).compare(.gt, .@"32")) { + if (ty.abiAlignment(zcu).compare(.gt, .@"4")) { return Class.arrSize(bit_size, 64); } @@ -62,7 +62,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { const float_count = countFloats(ty, zcu, &maybe_float_bits); if (float_count <= byval_float_count) return .byval; - if (union_obj.alignment.compareStrict(.gt, .@"32")) { + if (union_obj.alignment.compareStrict(.gt, .@"4")) { return Class.arrSize(bit_size, 64); } @@ -73,14 +73,16 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { } return Class.arrSize(bit_size, 32); }, - .bool, .float => return .byval, + .bool => return .byval, .int => { - // TODO this is incorrect for _BitInt(128) but implementing - // this correctly makes implementing compiler-rt impossible. - // const bit_size = ty.bitSize(zcu); - // if (bit_size > 64) return .memory; + if (ctx == .ret and ty.intInfo(zcu).bits > 64) return .memory; return .byval; }, + .float => return switch (ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16, 32, 64 => .byval, + 80, 128 => .{ .i64_array = 2 }, + }, .@"enum", .error_set => { const bit_size = ty.bitSize(zcu); if (bit_size > 64) return .memory; diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 0dc4ae6f3997ae55f4b068f725d5a02b3dea50a7..f2c8431dcab682067b18a9c785e1ac2edda4ade5 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -164,7 +164,8 @@ const BlockData = struct { const LocalType = struct { type: Type, - alignment: Alignment, + alignment: Alignment = .none, + array_len: u2 = 1, }; const LocalIndex = u16; @@ -184,13 +185,11 @@ const ValueRenderLocation = enum { } }; -const BuiltinInfo = enum { none, bits }; +const BuiltinInfo = enum { none, bits, bits_none, big_temp_bits }; const reserved_idents = std.StaticStringMap(void).initComptime(.{ // C language - .{ "alignas", { - @setEvalBranchQuota(4000); - } }, + .{ "alignas", {} }, .{ "alignof", {} }, .{ "asm", {} }, .{ "atomic_bool", {} }, @@ -302,7 +301,100 @@ const reserved_idents = std.StaticStringMap(void).initComptime(.{ // stddef.h .{ "offsetof", {} }, + // math.h (only symbols exported by compiler-rt) + .{ "ceil", {} }, + .{ "ceilf", {} }, + .{ "ceilf128", {} }, + .{ "ceill", {} }, + .{ "cos", {} }, + .{ "cosf", {} }, + .{ "cosf128", {} }, + .{ "cosl", {} }, + .{ "exp", {} }, + .{ "exp2", {} }, + .{ "exp2f", {} }, + .{ "exp2f128", {} }, + .{ "exp2l", {} }, + .{ "expf", {} }, + .{ "expf128", {} }, + .{ "expl", {} }, + .{ "fabs", {} }, + .{ "fabsf", {} }, + .{ "fabsf128", {} }, + .{ "fabsl", {} }, + .{ "floor", {} }, + .{ "floorf", {} }, + .{ "floorf128", {} }, + .{ "floorl", {} }, + .{ "fma", {} }, + .{ "fmaf", {} }, + .{ "fmaf128", {} }, + .{ "fmal", {} }, + .{ "fmax", {} }, + .{ "fmaxf", {} }, + .{ "fmaxf128", {} }, + .{ "fmaxl", {} }, + .{ "fmin", {} }, + .{ "fminf", {} }, + .{ "fminf128", {} }, + .{ "fminl", {} }, + .{ "fmod", {} }, + .{ "fmodf", {} }, + .{ "fmodf128", {} }, + .{ "fmodl", {} }, + .{ "log", {} }, + .{ "log10", {} }, + .{ "log10f", {} }, + .{ "log10f128", {} }, + .{ "log10l", {} }, + .{ "log2", {} }, + .{ "log2f", {} }, + .{ "log2f128", {} }, + .{ "log2l", {} }, + .{ "logf", {} }, + .{ "logf128", {} }, + .{ "logl", {} }, + .{ "round", {} }, + .{ "roundf", {} }, + .{ "roundf128", {} }, + .{ "roundl", {} }, + .{ "sin", {} }, + .{ "sincos", {} }, + .{ "sincosf", {} }, + .{ "sincosf128", {} }, + .{ "sincosl", {} }, + .{ "sinf", {} }, + .{ "sinf128", {} }, + .{ "sinl", {} }, + .{ "sqrt", {} }, + .{ "sqrtf", {} }, + .{ "sqrtf128", {} }, + .{ "sqrtl", {} }, + .{ "tan", {} }, + .{ "tanf", {} }, + .{ "tanf128", {} }, + .{ "tanl", {} }, + .{ "trunc", {} }, + .{ "truncf", {} }, + .{ "truncf128", {} }, + .{ "truncl", {} }, + // windows.h + .{"DUMMYSTRUCTNAME"}, + .{"DUMMYSTRUCTNAME2"}, + .{"DUMMYSTRUCTNAME3"}, + .{"DUMMYSTRUCTNAME4"}, + .{"DUMMYSTRUCTNAME5"}, + .{"DUMMYSTRUCTNAME6"}, + .{"DUMMYUNIONNAME"}, + .{"DUMMYUNIONNAME2"}, + .{"DUMMYUNIONNAME3"}, + .{"DUMMYUNIONNAME4"}, + .{"DUMMYUNIONNAME5"}, + .{"DUMMYUNIONNAME6"}, + .{"DUMMYUNIONNAME7"}, + .{"DUMMYUNIONNAME8"}, + .{"DUMMYUNIONNAME9"}, .{ "max", {} }, .{ "min", {} }, }); @@ -316,13 +408,6 @@ fn isReservedIdent(ident: []const u8) bool { } } - // windows.h - if (mem.startsWith(u8, ident, "DUMMYSTRUCTNAME") or - mem.startsWith(u8, ident, "DUMMYUNIONNAME")) - { - return true; - } - // CType if (mem.startsWith(u8, ident, "enum__") or mem.startsWith(u8, ident, "bitpack__") or @@ -453,8 +538,8 @@ pub const Function = struct { fn wantSafety(f: *Function) bool { return switch (f.dg.mod.optimize_mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, + .debug, .safe => true, + .fast, .small => false, }; } @@ -469,10 +554,7 @@ pub const Function = struct { } fn allocLocal(f: *Function, inst: ?Air.Inst.Index, ty: Type) !CValue { - return f.allocAlignedLocal(inst, .{ - .type = ty, - .alignment = .none, - }); + return f.allocAlignedLocal(inst, .{ .type = ty }); } /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should @@ -564,10 +646,6 @@ pub const Function = struct { return f.dg.renderType(w, ty); } - fn renderIntCast(f: *Function, w: *Writer, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void { - return f.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src, .v = v } }, src_ty, location); - } - fn fmtIntLiteralDec(f: *Function, val: Value) !std.fmt.Alt(FormatIntLiteralContext, formatIntLiteral) { return f.dg.fmtIntLiteralDec(val, .other); } @@ -672,7 +750,9 @@ pub const DeclGen = struct { // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. const ptr_ty: Type = .fromInterned(uav.orig_ty); if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { - return dg.renderUndefValue(w, ptr_ty, location); + try w.writeByte('('); + try dg.renderOpvPointer(w, ptr_ty, location); + return w.writeByte(')'); } switch (ip.indexToKey(uav.val)) { @@ -737,8 +817,10 @@ pub const DeclGen = struct { // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).resolved.?.type); const ptr_ty = try pt.navPtrType(owner_nav); - if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { - return dg.renderUndefValue(w, ptr_ty, location); + if (nav_ty.zigTypeTag(zcu) != .@"opaque" and !nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { + try w.writeByte('('); + try dg.renderOpvPointer(w, ptr_ty, location); + return w.writeByte(')'); } // We shouldn't cast C function pointers as this is UB (when you call @@ -758,6 +840,26 @@ pub const DeclGen = struct { if (need_cast) try w.writeByte(')'); } + fn renderOpvPointer( + dg: *DeclGen, + w: *Writer, + ptr_ty: Type, + location: ValueRenderLocation, + ) Error!void { + const zcu = dg.pt.zcu; + const target = zcu.getTarget(); + try w.writeByte('('); + try dg.renderType(w, ptr_ty); + return w.print("){f}", .{fmtUnsignedIntLiteralSmall( + target, + .uintptr_t, + ptr_ty.ptrAlignment(zcu).forward(undefPattern(u64) >> @intCast(64 - target.ptrBitWidth())), + location == .static_initializer, + 16, + .lower, + )}); + } + fn renderPointer( dg: *DeclGen, w: *Writer, @@ -959,9 +1061,6 @@ pub const DeclGen = struct { const bits = ty.floatBits(target); const f128_val = val.toFloat(f128, zcu); - // All unsigned ints matching float types are pre-allocated. - const repr_ty = pt.intType(.unsigned, bits) catch unreachable; - assert(bits <= 128); var repr_val_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; var repr_val_big = BigInt.Mutable{ @@ -971,29 +1070,27 @@ pub const DeclGen = struct { }; switch (bits) { + else => unreachable, 16 => repr_val_big.set(@as(u16, @bitCast(val.toFloat(f16, zcu)))), 32 => repr_val_big.set(@as(u32, @bitCast(val.toFloat(f32, zcu)))), 64 => repr_val_big.set(@as(u64, @bitCast(val.toFloat(f64, zcu)))), 80 => repr_val_big.set(@as(u80, @bitCast(val.toFloat(f80, zcu)))), 128 => repr_val_big.set(@as(u128, @bitCast(f128_val))), - else => unreachable, } - var empty = true; if (std.math.isFinite(f128_val)) { try w.writeAll("zig_make_"); try dg.renderTypeForBuiltinFnName(w, ty); try w.writeByte('('); switch (bits) { + else => unreachable, 16 => try w.print("{x}", .{val.toFloat(f16, zcu)}), 32 => try w.print("{x}", .{val.toFloat(f32, zcu)}), 64 => try w.print("{x}", .{val.toFloat(f64, zcu)}), 80 => try w.print("{x}", .{val.toFloat(f80, zcu)}), 128 => try w.print("{x}", .{f128_val}), - else => unreachable, } try w.writeAll(", "); - empty = false; } else { // isSignalNan is equivalent to isNan currently, and MSVC doesn't have nans, so prefer nan const operation = if (std.math.isNan(f128_val)) @@ -1028,6 +1125,7 @@ pub const DeclGen = struct { try w.writeAll(operation); try w.writeAll(", "); if (std.math.isNan(f128_val)) switch (bits) { + else => unreachable, // We only actually need to pass the significand, but it will get // properly masked anyway, so just pass the whole value. 16 => try w.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}), @@ -1035,16 +1133,23 @@ pub const DeclGen = struct { 64 => try w.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}), 80 => try w.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}), 128 => try w.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}), - else => unreachable, }; try w.writeAll(", "); - empty = false; } - try w.print("{f}", .{try dg.fmtIntLiteralHex( - try pt.intValue_big(repr_ty, repr_val_big.toConst()), - location, - )}); - if (!empty) try w.writeByte(')'); + switch (bits) { + else => unreachable, + 16, 32, 64 => { + // All unsigned ints matching float types are pre-allocated. + const repr_ty = pt.intType(.unsigned, bits) catch unreachable; + try w.print("{f}", .{try dg.fmtIntLiteralHex( + try pt.intValue_big(repr_ty, repr_val_big.toConst()), + location, + )}); + }, + 80 => try F80Repr.write(@bitCast(val.toFloat(f80, zcu)), w, target, location == .static_initializer), + 128 => try F128Repr.write(@bitCast(f128_val), w, target, location == .static_initializer), + } + try w.writeByte(')'); }, .slice => |slice| { if (!location.isInitializer()) { @@ -1306,8 +1411,8 @@ pub const DeclGen = struct { }; const safety_on = switch (dg.mod.optimize_mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, + .debug, .safe => true, + .fast, .small => false, }; switch (ty.toIntern()) { @@ -1319,22 +1424,29 @@ pub const DeclGen = struct { .f128_type, => { const bits = ty.floatBits(target); - // All unsigned ints matching float types are pre-allocated. - const repr_ty = dg.pt.intType(.unsigned, bits) catch unreachable; try w.writeAll("zig_make_"); try dg.renderTypeForBuiltinFnName(w, ty); try w.writeByte('('); switch (bits) { - 16 => try w.print("{x}", .{@as(f16, @bitCast(undefPattern(i16)))}), - 32 => try w.print("{x}", .{@as(f32, @bitCast(undefPattern(i32)))}), - 64 => try w.print("{x}", .{@as(f64, @bitCast(undefPattern(i64)))}), - 80 => try w.print("{x}", .{@as(f80, @bitCast(undefPattern(i80)))}), - 128 => try w.print("{x}", .{@as(f128, @bitCast(undefPattern(i128)))}), else => unreachable, + 16 => try w.print("{x}", .{undefPattern(f16)}), + 32 => try w.print("{x}", .{undefPattern(f32)}), + 64 => try w.print("{x}", .{undefPattern(f64)}), + 80 => try w.print("{x}", .{undefPattern(f80)}), + 128 => try w.print("{x}", .{undefPattern(f128)}), } try w.writeAll(", "); - try dg.renderUndefValue(w, repr_ty, .other); + switch (bits) { + else => unreachable, + 16, 32, 64 => { + // All unsigned ints matching float types are pre-allocated. + const repr_ty = dg.pt.intType(.unsigned, bits) catch unreachable; + try dg.renderUndefValue(w, repr_ty, .other); + }, + 80 => try undefPattern(F80Repr).write(w, target, location == .static_initializer), + 128 => try undefPattern(F128Repr).write(w, target, location == .static_initializer), + } return w.writeByte(')'); }, .bool_type => try w.writeAll(if (safety_on) "0xaa" else "false"), @@ -1638,8 +1750,6 @@ pub const DeclGen = struct { try w.writeAll("zig_no_builtin "); } - if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn "); - // While incomplete types are usually an acceptable substitute for "void", this is not true // in function return types, where "void" is the only incomplete type permitted. const actual_return_type: Type = .fromInterned(fn_info.return_type); @@ -1651,8 +1761,9 @@ pub const DeclGen = struct { const ret_cty: CType = try .lower(effective_return_type, &dg.ctype_deps, dg.arena, zcu); try w.print("{f}", .{ret_cty.fmtDeclaratorPrefix(zcu)}); - if (toCallingConvention(fn_info.cc, zcu)) |call_conv| { - try w.print("zig_callconv({s}) ", .{call_conv}); + switch (CType.CallingConvention.fromLang(fn_info.cc, zcu.getTarget())) { + .c => {}, + else => |cc| try w.print("zig_callconv({t}) ", .{cc}), } switch (name) { .nav => |nav| try renderNavName(w, nav, ip), @@ -1726,136 +1837,6 @@ pub const DeclGen = struct { try w.print("{f}", .{cty.fmtTypeName(zcu)}); } - const IntCastContext = union(enum) { - c_value: struct { - f: *Function, - value: CValue, - v: Vectorize, - }, - value: struct { - value: Value, - }, - - pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: *Writer, location: ValueRenderLocation) !void { - switch (self.*) { - .c_value => |v| { - try v.f.writeCValue(w, v.value, location); - try v.v.elem(v.f, w); - }, - .value => |v| try dg.renderValue(w, v.value, location), - } - } - }; - fn intCastIsNoop(dg: *DeclGen, dest_ty: Type, src_ty: Type) bool { - const pt = dg.pt; - const zcu = pt.zcu; - const dest_bits = dest_ty.bitSize(zcu); - const dest_int_info = dest_ty.intInfo(pt.zcu); - - const src_is_ptr = src_ty.isPtrAtRuntime(pt.zcu); - const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { - .unsigned => .usize, - .signed => .isize, - } else src_ty; - - const src_bits = src_eff_ty.bitSize(zcu); - const src_int_info = if (src_eff_ty.isAbiInt(pt.zcu)) src_eff_ty.intInfo(pt.zcu) else null; - if (dest_bits <= 64 and src_bits <= 64) { - const needs_cast = src_int_info == null or - (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or - dest_int_info.signedness != src_int_info.?.signedness); - return !needs_cast and !src_is_ptr; - } else return false; - } - /// Renders a cast to an int type, from either an int or a pointer. - /// - /// Some platforms don't have 128 bit integers, so we need to use - /// the zig_make_ and zig_lo_ macros in those cases. - /// - /// | Dest type bits | Src type | Result - /// |------------------|------------------|---------------------------| - /// | < 64 bit integer | pointer | (zig_)(zig_size)src - /// | < 64 bit integer | < 64 bit integer | (zig_)src - /// | < 64 bit integer | > 64 bit integer | zig_lo(src) - /// | > 64 bit integer | pointer | zig_make_(0, (zig_size)src) - /// | > 64 bit integer | < 64 bit integer | zig_make_(0, src) - /// | > 64 bit integer | > 64 bit integer | zig_make_(zig_hi_(src), zig_lo_(src)) - fn renderIntCast( - dg: *DeclGen, - w: *Writer, - dest_ty: Type, - context: IntCastContext, - src_ty: Type, - location: ValueRenderLocation, - ) !void { - const pt = dg.pt; - const zcu = pt.zcu; - const dest_bits = dest_ty.bitSize(zcu); - const dest_int_info = dest_ty.intInfo(zcu); - - const src_is_ptr = src_ty.isPtrAtRuntime(zcu); - const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { - .unsigned => .usize, - .signed => .isize, - } else src_ty; - - const src_bits = src_eff_ty.bitSize(zcu); - const src_int_info = if (src_eff_ty.isAbiInt(zcu)) src_eff_ty.intInfo(zcu) else null; - if (dest_bits <= 64 and src_bits <= 64) { - const needs_cast = src_int_info == null or - (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or - dest_int_info.signedness != src_int_info.?.signedness); - - if (needs_cast) { - try w.writeByte('('); - try dg.renderType(w, dest_ty); - try w.writeByte(')'); - } - if (src_is_ptr) { - try w.writeByte('('); - try dg.renderType(w, src_eff_ty); - try w.writeByte(')'); - } - try context.writeValue(dg, w, location); - } else if (dest_bits <= 64 and src_bits > 64) { - assert(!src_is_ptr); - if (dest_bits < 64) { - try w.writeByte('('); - try dg.renderType(w, dest_ty); - try w.writeByte(')'); - } - try w.writeAll("zig_lo_"); - try dg.renderTypeForBuiltinFnName(w, src_eff_ty); - try w.writeByte('('); - try context.writeValue(dg, w, .other); - try w.writeByte(')'); - } else if (dest_bits > 64 and src_bits <= 64) { - try w.writeAll("zig_make_"); - try dg.renderTypeForBuiltinFnName(w, dest_ty); - try w.writeAll("(0, "); - if (src_is_ptr) { - try w.writeByte('('); - try dg.renderType(w, src_eff_ty); - try w.writeByte(')'); - } - try context.writeValue(dg, w, .other); - try w.writeByte(')'); - } else { - assert(!src_is_ptr); - try w.writeAll("zig_make_"); - try dg.renderTypeForBuiltinFnName(w, dest_ty); - try w.writeAll("(zig_hi_"); - try dg.renderTypeForBuiltinFnName(w, src_eff_ty); - try w.writeByte('('); - try context.writeValue(dg, w, .other); - try w.writeAll("), zig_lo_"); - try dg.renderTypeForBuiltinFnName(w, src_eff_ty); - try w.writeByte('('); - try context.writeValue(dg, w, .other); - try w.writeAll("))"); - } - } - /// Renders to `w` a C declarator whose type is the C lowering of the given Zig type. fn renderTypeAndName( dg: *DeclGen, @@ -2000,6 +1981,7 @@ pub const DeclGen = struct { switch (info) { .none => if (!is_big) return, .bits => {}, + .bits_none, .big_temp_bits => unreachable, } const int_info: std.lang.Type.Int = if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else .{ @@ -2056,6 +2038,72 @@ const CQualifiers = packed struct { restrict: bool = false, }; +pub fn genHeader(zcu: *Zcu, w: *Writer) !void { + const gpa = zcu.comp.gpa; + + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var ctype_deps: CType.Dependencies = .empty; + defer ctype_deps.deinit(gpa); + + const target = zcu.getTarget(); + switch (target.abi) { + .msvc, .itanium => try w.writeAll("#define ZIG_TARGET_ABI_MSVC\n"), + else => {}, + } + for ([_]u16{ 16, 32, 64, 80, 128 }) |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => {}, + .soft => try w.print("#define ZIG_TARGET_SOFT_COMPILER_RT_F{d}_ABI\n", .{bits}), + }; + try w.print( + \\#define ZIG_TARGET_MAX_INT_ALIGNMENT {d} + \\#include "zig.h" + \\ + \\ + , + .{target.cMaxIntAlignment()}, + ); + + var basic_ty: Type = .fromInterned(.first_type); + while (true) : ({ + basic_ty = .fromInterned(@fromBackingInt(@intCast(@backingInt(basic_ty.toIntern()) + 1))); + if (basic_ty.toIntern() == InternPool.Index.last_type) break; + }) { + switch (basic_ty.toIntern()) { + else => {}, + .anyframe_type, + .adhoc_inferred_error_set_type, + .generic_poison_type, + => continue, // skip unsupported types + } + const basic_cty: CType = try .lower(basic_ty, &ctype_deps, arena.allocator(), zcu); + switch (basic_cty) { + .void => {}, // no layout to check + .bool, + .int, + .float, + => try CType.render_defs.writeStaticAssertTypeLayout(basic_ty, basic_cty, w, zcu), + .@"fn", + .@"enum", + .bitpack, + .@"struct", + .union_auto, + .union_extern, + .slice, + .opt, + .arr, + .vec, + .errunion, + .aligned, + .bigint, + .pointer, + .array, + .function, + => {}, + } + } +} + pub fn genGlobalAsm(zcu: *Zcu, w: *Writer) !void { for (zcu.global_assembly.values()) |asm_source| { try w.print("__asm({f});\n", .{fmtStringLiteral(asm_source, null)}); @@ -2070,16 +2118,16 @@ pub fn genErrDecls( const ip = &zcu.intern_pool; const names = ip.global_error_set.getNamesFromMainThread(); - // Don't generate an invalid empty enum if the global error set is empty! - if (names.len > 0) { - try w.writeAll("enum {\n"); - for (names, 1..) |name_nts, value| { - try w.writeByte(' '); - try renderErrorName(w, name_nts.toSlice(ip)); - try w.print(" = {d}u,\n", .{value}); - } - try w.writeAll("};\n"); + // Don't generate an invalid empty enum/array if the global error set is empty! + if (names.len == 0) return; + + try w.writeAll("enum {\n"); + for (names, 1..) |name_nts, value| { + try w.writeByte(' '); + try renderErrorName(w, name_nts.toSlice(ip)); + try w.print(" = {d}u,\n", .{value}); } + try w.writeAll("};\n"); for (names) |name_nts| { const name = name_nts.toSlice(ip); @@ -2093,7 +2141,7 @@ pub fn genErrDecls( "static {s} const zig_errorName[{d}] = {{", .{ slice_const_u8_sentinel_0_type_name, names.len }, ); - if (names.len > 0) try w.writeByte('\n'); + try w.writeByte('\n'); for (names) |name_nts| { const name = name_nts.toSlice(ip); try w.print( @@ -2114,10 +2162,18 @@ pub fn genTagNameFn( const ip = &zcu.intern_pool; const loaded_enum = ip.loadEnumType(enum_ty.toIntern()); assert(loaded_enum.field_names.len > 0); - if (Type.fromInterned(loaded_enum.int_tag_type).bitSize(zcu) > 64) { - @panic("TODO CBE: tagName for enum over 64 bits"); + switch (CType.classifyInt(enum_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => {}, + .zig_u128, .zig_i128 => @panic("TODO CBE: tagName for 128-bit enums"), + }, + .big => @panic("TODO CBE: tagName for bigint enums"), } + if (!zcu.comp.config.root_strip) try w.print("/* @tagName({f}) */\n", .{ + loaded_enum.name.fmt(ip), + }); try w.print("static {s} zig_tagName_{f}__{d}({s} tag) {{\n", .{ slice_const_u8_sentinel_0_type_name, fmtIdentUnsolo(loaded_enum.name.toSlice(ip)), @@ -2164,6 +2220,7 @@ pub fn genLazyCallModifierFn( const fn_val = zcu.navValue(fn_nav); + if (fn_val.typeOf(zcu).fnReturnType(zcu).isNoReturn(zcu)) try w.writeAll("zig_noreturn "); try w.print("static zig_{t} ", .{kind}); try dg.renderFunctionSignature(w, fn_val, .none, .definition, switch (kind) { .never_tail => .{ .nav_never_tail = fn_nav }, @@ -2269,8 +2326,10 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E const gpa = f.dg.gpa; const nav_index = f.dg.owner_nav.unwrap().?; const nav_val = zcu.navValue(nav_index); + const fn_info = zcu.typeToFunc(nav_val.typeOf(zcu)).?; const nav = ip.getNav(nav_index); + if (Type.fromInterned(fn_info.return_type).isNoReturn(zcu)) try fwd_decl_writer.writeAll("zig_noreturn "); try fwd_decl_writer.writeAll("static "); try f.dg.renderFunctionSignature( fwd_decl_writer, @@ -2291,11 +2350,41 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E .{ .nav = nav_index }, ); try header_writer.writeAll(" {\n "); + if (!f.dg.mod.strip) try header_writer.print("/* {f} */\n ", .{nav.fqn.fmt(ip)}); f.free_locals_map.clearRetainingCapacity(); const main_body = f.air.getMainBody(); f.indent(); + if (switch (fn_info.cc) { + inline else => |pl| switch (@TypeOf(pl)) { + void, + std.lang.CallingConvention.SpirvKernelOptions, + std.lang.CallingConvention.SpirvFragmentOptions, + std.lang.CallingConvention.SpirvMeshOptions, + => null, + std.lang.CallingConvention.ArcInterruptOptions, + std.lang.CallingConvention.ArmInterruptOptions, + std.lang.CallingConvention.RiscvInterruptOptions, + std.lang.CallingConvention.ShInterruptOptions, + std.lang.CallingConvention.MicroblazeInterruptOptions, + std.lang.CallingConvention.MipsInterruptOptions, + std.lang.CallingConvention.CommonOptions, + std.lang.CallingConvention.X86RegparmOptions, + => pl.incoming_stack_alignment, + else => @compileError(@tagName(pl)), + }, + }) |incoming_stack_alignment| realign_stack: { + const normal_stack_align = zcu.getTarget().stackAlignment(); + if (incoming_stack_alignment >= normal_stack_align) break :realign_stack; + try header_writer.print("char zig_align({d}) zig_realign_stack;\n ", .{ + normal_stack_align << 1, + }); + try f.code.writer.writeAll( + \\__asm volatile("" :: [zig_realign_stack] "m" (zig_realign_stack)); + ); + try f.newline(); + } try genBodyResolveState(f, undefined, &.{}, main_body, true); try f.outdent(); try f.code.writer.writeByte('}'); @@ -2346,6 +2435,7 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E for (list.keys()) |local_index| { const local = f.locals.items[local_index]; try f.dg.renderTypeAndName(header_writer, local.type, .{ .local = local_index }, .{}, local.alignment); + if (local.array_len != 1) try header_writer.print("[{d}]", .{local.array_len}); try header_writer.writeAll(";\n "); } } @@ -2397,10 +2487,12 @@ pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void { .@"extern" => |@"extern"| switch (nav_ty.zigTypeTag(zcu)) { .@"fn" => { + const fn_val: Value = .fromInterned(nav.resolved.?.value); + if (fn_val.typeOf(zcu).fnReturnType(zcu).isNoReturn(zcu)) try w.writeAll("zig_noreturn "); try w.writeAll("zig_extern "); try dg.renderFunctionSignature( w, - .fromInterned(nav.resolved.?.value), + fn_val, nav.resolved.?.@"align", .forward_decl, .{ .@"export" = .{ @@ -2461,7 +2553,12 @@ pub fn genDeclValue(dg: *DeclGen, w: *Writer, options: struct { try dg.renderTypeAndName(w, ty, options.name, .{ .@"const" = options.@"const" }, .none); try w.writeAll(" = "); try dg.renderValue(w, options.init_val, .static_initializer); - try w.writeAll(";\n"); + try w.writeByte(';'); + if (dg.owner_nav.unwrap()) |nav_index| { + const ip = &zcu.intern_pool; + if (!dg.mod.strip) try w.print(" /* {f} */", .{ip.getNav(nav_index).fqn.fmt(ip)}); + } + try w.writeByte('\n'); } pub fn genDeclValueFwd(dg: *DeclGen, w: *Writer, options: struct { name: CValue, @@ -2496,11 +2593,13 @@ pub fn genExports(dg: *DeclGen, w: *Writer, exported: Zcu.Exported, export_indic const exported_val = exported.getValue(zcu); if (ip.isFunctionType(exported_val.typeOf(zcu).toIntern())) return for (export_indices) |export_index| { const @"export" = export_index.ptr(zcu); + const fn_val = exported.getValue(zcu); + if (fn_val.typeOf(zcu).fnReturnType(zcu).isNoReturn(zcu)) try w.writeAll("zig_noreturn "); try w.writeAll("zig_extern "); if (@"export".opts.linkage == .weak) try w.writeAll("zig_weak_linkage_fn "); try dg.renderFunctionSignature( w, - exported.getValue(zcu), + fn_val, exported.getAlign(zcu), .forward_decl, .{ .@"export" = .{ @@ -2662,22 +2761,22 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .mul => try airBinOp(f, inst, "*", "mul", .none), .neg => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].un_op, "neg", .none), - .div_float => try airBinBuiltinCall(f, inst, "div", .none), + .div_float => try airBinBuiltinCall(f, inst, "div", .big_temp_bits), - .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .none), + .div_trunc, .div_exact => try airBinOp(f, inst, "/", "divTrunc", .big_temp_bits), .rem => blk: { const bin_op = air_datas[@intFromEnum(inst)].bin_op; const lhs_scalar_ty = f.typeOf(bin_op.lhs).scalarType(zcu); // For binary operations @TypeOf(lhs)==@TypeOf(rhs), // so we only check one. break :blk if (lhs_scalar_ty.isInt(zcu)) - try airBinOp(f, inst, "%", "rem", .none) + try airBinOp(f, inst, "%", "rem", .big_temp_bits) else try airBinBuiltinCall(f, inst, "fmod", .none); }, - .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none), - .div_ceil => try airBinBuiltinCall(f, inst, "div_ceil", .none), - .mod => try airBinBuiltinCall(f, inst, "mod", .none), + .div_floor => try airBinBuiltinCall(f, inst, "divFloor", .big_temp_bits), + .div_ceil => try airBinBuiltinCall(f, inst, "divCeil", .big_temp_bits), + .mod => try airBinBuiltinCall(f, inst, "mod", .big_temp_bits), .abs => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "abs", .none), .add_wrap => try airBinBuiltinCall(f, inst, "addw", .bits), @@ -2687,7 +2786,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .add_sat => try airBinBuiltinCall(f, inst, "adds", .bits), .sub_sat => try airBinBuiltinCall(f, inst, "subs", .bits), .mul_sat => try airBinBuiltinCall(f, inst, "muls", .bits), - .shl_sat => try airBinBuiltinCall(f, inst, "shls", .bits), + .shl_sat => try airBinBuiltinCall(f, inst, "shls", .bits_none), .sqrt => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].un_op, "sqrt", .none), .sin => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].un_op, "sin", .none), @@ -2764,8 +2863,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .int_from_error => try airNopCast(f, inst), .union_from_enum => try airUnionFromEnum(f, inst), .bit_cast => try airBitCast(f, inst), - .int_cast => try airIntCast(f, inst), - .trunc => try airTrunc(f, inst), + .int_cast => try airIntCast(f, inst, "intCast", .none), + .trunc => try airIntCast(f, inst, "truncate", .bits), .load => try airLoad(f, inst), .store => try airStore(f, inst, false), .store_safe => try airStore(f, inst, true), @@ -2783,9 +2882,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .get_union_tag => try airGetUnionTag(f, inst), .clz => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "clz", .bits), .ctz => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "ctz", .bits), - .popcount => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "popcount", .bits), - .byte_swap => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "byte_swap", .bits), - .bit_reverse => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "bit_reverse", .bits), + .popcount => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "popCount", .bits), + .byte_swap => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "byteSwap", .bits), + .bit_reverse => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "bitReverse", .bits), .tag_name => try airTagName(f, inst), .error_name => try airErrorName(f, inst), .splat => try airSplat(f, inst), @@ -3124,7 +3223,16 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { const zcu = pt.zcu; const inst_ty = f.typeOfIndex(inst); const elem_ty = inst_ty.childType(zcu); - if (!elem_ty.hasRuntimeBits(zcu)) return .{ .undef = inst_ty }; + if (!elem_ty.hasRuntimeBits(zcu)) { + const w = &f.code.writer; + const local = try f.allocLocal(inst, inst_ty); + try f.writeCValue(w, local, .other); + try w.writeAll(" = "); + try f.dg.renderOpvPointer(w, inst_ty, .other); + try w.writeByte(';'); + try f.newline(); + return local; + } const local = try f.allocLocalValue(.{ .type = elem_ty, @@ -3298,120 +3406,57 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void { } } -fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { +fn airIntCast(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue { const pt = f.dg.pt; const zcu = pt.zcu; const ty_op = f.air.instructions.items(.data)[@backingInt(inst)].ty_op; - const operand = try f.resolveInst(ty_op.operand); - try reap(f, inst, &.{ty_op.operand}); - - const inst_ty = f.typeOfIndex(inst); + const inst_ty = ty_op.ty.toType(); const inst_scalar_ty = inst_ty.scalarType(zcu); const operand_ty = f.typeOf(ty_op.operand); - const scalar_ty = operand_ty.scalarType(zcu); - - // `intCastIsNoop` doesn't apply to vectors because every vector lowers to a different C struct. - if (inst_ty.zigTypeTag(zcu) != .vector and f.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) { - return f.moveCValue(inst, inst_ty, operand); - } - - const w = &f.code.writer; - const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, w, operand_ty); - try f.writeCValue(w, local, .other); - try v.elem(f, w); - try w.writeAll(" = "); - try f.renderIntCast(w, inst_scalar_ty, operand, v, scalar_ty, .other); - try w.writeByte(';'); - try f.newline(); - try v.end(f, inst, w); - return local; -} - -fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { - const pt = f.dg.pt; - const zcu = pt.zcu; - const ty_op = f.air.instructions.items(.data)[@backingInt(inst)].ty_op; + const operand_scalar_ty = operand_ty.scalarType(zcu); + const is_big = lowersToBigInt(operand_ty, zcu); const operand = try f.resolveInst(ty_op.operand); - try reap(f, inst, &.{ty_op.operand}); - - const inst_ty = f.typeOfIndex(inst); - const inst_scalar_ty = inst_ty.scalarType(zcu); - const dest_int_info = inst_scalar_ty.intInfo(zcu); - const dest_bits = dest_int_info.bits; - const dest_c_bits = toCIntBits(dest_bits) orelse - return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - const operand_ty = f.typeOf(ty_op.operand); - const scalar_ty = operand_ty.scalarType(zcu); - const scalar_int_info = scalar_ty.intInfo(zcu); + if (!is_big) try reap(f, inst, &.{ty_op.operand}); - const need_cast = dest_c_bits < 64; - const need_lo = scalar_int_info.bits > 64 and dest_bits <= 64; - const need_mask = dest_bits < 8 or !std.math.isPowerOfTwo(dest_bits); - if (!need_cast and !need_lo and !need_mask) return f.moveCValue(inst, inst_ty, operand); + const ref_ret = lowersToBigInt(inst_scalar_ty, zcu); + const ref_arg = lowersToBigInt(operand_scalar_ty, zcu); const w = &f.code.writer; const local = try f.allocLocal(inst, inst_ty); + if (is_big) try reap(f, inst, &.{ty_op.operand}); const v = try Vectorize.start(f, inst, w, operand_ty); - try f.writeCValue(w, local, .other); - try v.elem(f, w); - try w.writeAll(" = "); - if (need_cast) { - try w.writeByte('('); - try f.renderType(w, inst_scalar_ty); - try w.writeByte(')'); - } - if (need_lo) { - try w.writeAll("zig_lo_"); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); - try w.writeByte('('); + if (!ref_ret) { + try f.writeCValue(w, local, .other); + try v.elem(f, w); + try w.writeAll(" = "); } - if (!need_mask) { - try f.writeCValue(w, operand, .other); + try w.writeAll("zig_"); + try f.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty); + try w.print("_{s}_", .{operation}); + try f.dg.renderTypeForBuiltinFnName(w, operand_scalar_ty); + try w.writeByte('('); + if (ref_ret) { + try w.writeByte('&'); + try f.writeCValue(w, local, .other); try v.elem(f, w); - } else switch (dest_int_info.signedness) { - .unsigned => { - try w.writeAll("zig_and_"); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); - try w.writeByte('('); - try f.writeCValue(w, operand, .other); - try v.elem(f, w); - try w.print(", {f})", .{ - try f.fmtIntLiteralHex(try inst_scalar_ty.maxIntScalar(pt, scalar_ty)), - }); - }, - .signed => { - const c_bits = toCIntBits(scalar_int_info.bits) orelse - return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - const shift_val = try pt.intValue(.u8, c_bits - dest_bits); - - try w.writeAll("zig_shr_"); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); - if (c_bits == 128) { - try w.print("(zig_bitCast_i{d}(", .{c_bits}); - } else { - try w.print("((int{d}_t)", .{c_bits}); - } - try w.print("zig_shl_u{d}(", .{c_bits}); - if (c_bits == 128) { - try w.print("zig_bitCast_u{d}(", .{c_bits}); - } else { - try w.print("(uint{d}_t)", .{c_bits}); - } - try f.writeCValue(w, operand, .other); - try v.elem(f, w); - if (c_bits == 128) try w.writeByte(')'); - try w.print(", {f})", .{try f.fmtIntLiteralDec(shift_val)}); - if (c_bits == 128) try w.writeByte(')'); - try w.print(", {f})", .{try f.fmtIntLiteralDec(shift_val)}); - }, + try w.writeAll(", "); } - if (need_lo) try w.writeByte(')'); - try w.writeByte(';'); + if (ref_arg) { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + } else try f.writeCValue(w, operand, .other); + try v.elem(f, w); + try f.dg.renderBuiltinInfo(w, inst_scalar_ty, info); + try f.dg.renderBuiltinInfo(w, operand_scalar_ty, .none); + try w.writeAll(");"); try f.newline(); try v.end(f, inst, w); + return local; } @@ -3525,39 +3570,46 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: const ty_pl = f.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; + const lhs_ty = f.typeOf(bin_op.lhs); + const rhs_ty = f.typeOf(bin_op.rhs); + const is_big = lowersToBigInt(lhs_ty, zcu); + const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); - try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); + if (!is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const inst_ty = f.typeOfIndex(inst); - const operand_ty = f.typeOf(bin_op.lhs); - const scalar_ty = operand_ty.scalarType(zcu); + const lhs_scalar_ty = lhs_ty.scalarType(zcu); + const rhs_scalar_ty = rhs_ty.scalarType(zcu); - const ref_arg = lowersToBigInt(scalar_ty, zcu); + const ref_lhs = lowersToBigInt(lhs_scalar_ty, zcu); + const ref_rhs = lowersToBigInt(rhs_scalar_ty, zcu); const w = &f.code.writer; - const local = try f.allocLocal(inst, inst_ty); - const v = try Vectorize.start(f, inst, w, operand_ty); + const local = try f.allocLocal(inst, f.typeOfIndex(inst)); + if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); + const v = try Vectorize.start(f, inst, w, lhs_ty); try f.writeCValueMember(w, local, .{ .field = 1 }); try v.elem(f, w); - try w.writeAll(" = zig_"); + try w.writeAll(" = "); + try w.writeAll("zig_"); try w.writeAll(operation); try w.writeAll("o_"); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try f.dg.renderTypeForBuiltinFnName(w, lhs_scalar_ty); try w.writeByte('('); // '&dest', possibly preceded by a cast - switch (zcu.intern_pool.indexToKey(scalar_ty.toIntern())) { + switch (zcu.intern_pool.indexToKey(lhs_scalar_ty.toIntern())) { .int_type => {}, // we already have a '[u]intX_t *' .simple_type => { // '&dest' will be something like a 'uintptr_t *', which might be a different C type to // the equivalent sized integer (e.g. 'uint64_t *'), so we need a cast. We don't need a // cast on the *operands* because they are passed by value (except for big integers, // where this issue doesn't exist because no "simple" int type needs bigint repr). - try w.print("({s}int{d}_t *)", .{ - if (scalar_ty.isUnsignedInt(zcu)) "u" else "", - scalar_ty.abiSize(zcu) * 8, - }); + const inst_int_info = lhs_scalar_ty.intInfo(zcu); + try w.print("({s}int{d}_t *)", .{ switch (inst_int_info.signedness) { + .signed => "", + .unsigned => "u", + }, inst_int_info.bits }); }, else => unreachable, } @@ -3566,14 +3618,24 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: try v.elem(f, w); try w.writeAll(", "); - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, lhs, .other); + if (ref_lhs) { + try w.writeByte('&'); + switch (lhs) { + .constant => |lhs_val| try f.dg.renderValueAsLvalue(w, lhs_val), + else => try f.writeCValue(w, lhs, .other), + } + } else try f.writeCValue(w, lhs, .other); try v.elem(f, w); try w.writeAll(", "); - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, rhs, .other); - if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w); - try f.dg.renderBuiltinInfo(w, scalar_ty, info); + if (ref_rhs) { + try w.writeByte('&'); + switch (rhs) { + .constant => |rhs_val| try f.dg.renderValueAsLvalue(w, rhs_val), + else => try f.writeCValue(w, rhs, .other), + } + } else try f.writeCValue(w, rhs, .other); + try v.elem(f, w); + try f.dg.renderBuiltinInfo(w, lhs_scalar_ty, info); try w.writeAll(");"); try f.newline(); try v.end(f, inst, w); @@ -3622,8 +3684,18 @@ fn airBinOp( const bin_op = f.air.instructions.items(.data)[@backingInt(inst)].bin_op; const operand_ty = f.typeOf(bin_op.lhs); const scalar_ty = operand_ty.scalarType(zcu); - if ((scalar_ty.isInt(zcu) and scalar_ty.bitSize(zcu) > 64) or scalar_ty.isRuntimeFloat()) - return try airBinBuiltinCall(f, inst, operation, info); + + builtin: { + if (scalar_ty.isInt(zcu)) switch (CType.classifyInt(scalar_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => break :builtin, + .zig_u128, .zig_i128 => {}, + }, + .big => {}, + } else if (!scalar_ty.isRuntimeFloat()) break :builtin; + return airBinBuiltinCall(f, inst, operation, info); + } const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); @@ -3662,19 +3734,21 @@ fn airCmpOp( const lhs_ty = f.typeOf(data.lhs); const scalar_ty = lhs_ty.scalarType(zcu); - if (scalar_ty.isInt(zcu)) { - const scalar_bits = scalar_ty.bitSize(zcu); - if (scalar_bits > 64) return airCmpBuiltinCall( - f, - inst, - data, - operator, - .cmp, - if (scalar_bits > 128) .bits else .none, - ); + builtin: { + if (scalar_ty.isInt(zcu)) { + switch (CType.classifyInt(scalar_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => break :builtin, + .zig_u128, .zig_i128 => {}, + }, + .big => {}, + } + return airCmpBuiltinCall(f, inst, data, operator, .cmp, .none); + } + if (scalar_ty.isRuntimeFloat()) + return airCmpBuiltinCall(f, inst, data, operator, .operator, .none); } - if (scalar_ty.isRuntimeFloat()) - return airCmpBuiltinCall(f, inst, data, operator, .operator, .none); const inst_ty = f.typeOfIndex(inst); const lhs = try f.resolveInst(data.lhs); @@ -3716,21 +3790,23 @@ fn airEquality( const pt = f.dg.pt; const zcu = pt.zcu; const bin_op = f.air.instructions.items(.data)[@backingInt(inst)].bin_op; - const operand_ty = f.typeOf(bin_op.lhs); - if (operand_ty.isAbiInt(zcu)) { - const operand_bits = operand_ty.bitSize(zcu); - if (operand_bits > 64) return airCmpBuiltinCall( - f, - inst, - bin_op, - operator, - .cmp, - if (operand_bits > 128) .bits else .none, - ); + + builtin: { + if (operand_ty.isAbiInt(zcu)) { + switch (CType.classifyInt(operand_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => break :builtin, + .zig_u128, .zig_i128 => {}, + }, + .big => {}, + } + return airCmpBuiltinCall(f, inst, bin_op, operator, .cmp, .none); + } + if (operand_ty.isRuntimeFloat()) + return airCmpBuiltinCall(f, inst, bin_op, operator, .operator, .none); } - if (operand_ty.isRuntimeFloat()) - return airCmpBuiltinCall(f, inst, bin_op, operator, .operator, .none); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); @@ -3809,7 +3885,7 @@ fn airCmpLteErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { try f.writeCValue(w, local, .other); try w.writeAll(" = "); try f.writeCValue(w, operand, .other); - try w.writeAll(" < sizeof(zig_errorName) / sizeof(*zig_errorName);"); + try w.writeAll(" <= sizeof(zig_errorName) / sizeof(*zig_errorName);"); try f.newline(); return local; } @@ -3862,8 +3938,17 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons const inst_ty = f.typeOfIndex(inst); const inst_scalar_ty = inst_ty.scalarType(zcu); - if ((inst_scalar_ty.isInt(zcu) and inst_scalar_ty.bitSize(zcu) > 64) or inst_scalar_ty.isRuntimeFloat()) - return try airBinBuiltinCall(f, inst, operation, .none); + builtin: { + if (inst_scalar_ty.isInt(zcu)) switch (CType.classifyInt(inst_scalar_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => break :builtin, + .zig_u128, .zig_i128 => {}, + }, + .big => {}, + } else if (!inst_scalar_ty.isRuntimeFloat()) break :builtin; + return airBinBuiltinCall(f, inst, operation, .none); + } const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); @@ -3979,10 +4064,7 @@ fn airCall( try w.writeAll("(void)"); break :result .none; } else { - const local = try f.allocAlignedLocal(inst, .{ - .type = ret_ty, - .alignment = .none, - }); + const local = try f.allocAlignedLocal(inst, .{ .type = ret_ty }); try f.writeCValue(w, local, .other); try w.writeAll(" = "); break :result local; @@ -4058,16 +4140,7 @@ fn airCall( fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { const dbg_stmt = f.air.instructions.items(.data)[@backingInt(inst)].dbg_stmt; const w = &f.code.writer; - // TODO re-evaluate whether to emit these or not. If we naively emit - // these directives, the output file will report bogus line numbers because - // every newline after the #line directive adds one to the line. - // We also don't print the filename yet, so the output is strictly unhelpful. - // If we wanted to go this route, we would need to go all the way and not output - // newlines until the next dbg_stmt occurs. - // Perhaps an additional compilation option is in order? - //try w.print("#line {d}", .{dbg_stmt.line + 1}); - //try f.newline(); - try w.print("/* file:{d}:{d} */", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); + try w.print("/* {d}:{d} */", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); try f.newline(); return .none; } @@ -4433,12 +4506,12 @@ fn airBitCast(f: *Function, inst: Air.Inst.Index) Error!CValue { const operand_scalar_ty = operand_ty.scalarType(zcu); const dest_scalar_ty = dest_ty.scalarType(zcu); - // Some cases are handled with a simple cast: - // * float -> float - // * bool -> int if ((operand_scalar_ty.isRuntimeFloat() and dest_scalar_ty.isRuntimeFloat()) or (operand_scalar_ty.toIntern() == .bool_type and dest_scalar_ty.isAbiInt(zcu))) { + // Some cases are handled with a simple cast: + // * float -> float + // * bool -> int try f.writeCValue(w, dest_local, .other); try v.elem(f, w); try w.writeAll(" = ("); @@ -4458,85 +4531,44 @@ fn airBitCast(f: *Function, inst: Air.Inst.Index) Error!CValue { try v.elem(f, w); try w.writeAll(" != 0;"); try f.newline(); - } else if (dest_scalar_ty.isRuntimeFloat()) { - // For int->float, just do a memcpy. - assert(operand_scalar_ty.isAbiInt(zcu)); - try w.writeAll("memcpy(&"); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.writeAll(", &"); - switch (operand) { - .constant => |val| try f.dg.renderValueAsLvalue(w, val), - else => try f.writeCValue(w, operand, .other), - } - try v.elem(f, w); - try w.print(", {d});", .{@min(operand_scalar_ty.abiSize(zcu), dest_scalar_ty.abiSize(zcu))}); - try f.newline(); } else { - // The only remaining possibility is that the result is an integer. We will need to use - // `zig_wrap_*` to correct the "padding" bits after we populate the value bits. - assert(dest_scalar_ty.isAbiInt(zcu)); assert(operand_scalar_ty.isRuntimeFloat() or operand_scalar_ty.isAbiInt(zcu)); + assert(dest_scalar_ty.isRuntimeFloat() or dest_scalar_ty.isAbiInt(zcu)); - // memcpy the value... - try w.writeAll("memcpy(&"); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.writeAll(", &"); - switch (operand) { - .constant => |val| try f.dg.renderValueAsLvalue(w, val), - else => try f.writeCValue(w, operand, .other), + const ref_ret = lowersToBigInt(dest_scalar_ty, zcu); + const ref_arg = lowersToBigInt(operand_scalar_ty, zcu); + + if (!ref_ret) { + try f.writeCValue(w, dest_local, .other); + try v.elem(f, w); + try w.writeAll(" = "); + } + try w.writeAll("zig_"); + try f.dg.renderTypeForBuiltinFnName(w, dest_scalar_ty); + try w.writeAll("_bitCast_"); + try f.dg.renderTypeForBuiltinFnName(w, operand_scalar_ty); + try w.writeByte('('); + if (ref_ret) { + try w.writeByte('&'); + try f.writeCValue(w, dest_local, .other); + try v.elem(f, w); + try w.writeAll(", "); } + if (ref_arg) { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + } else try f.writeCValue(w, operand, .other); try v.elem(f, w); - try w.print(", {d});", .{@min(operand_scalar_ty.abiSize(zcu), dest_scalar_ty.abiSize(zcu))}); + try f.dg.renderBuiltinInfo( + w, + dest_scalar_ty, + if (operand_scalar_ty.isRuntimeFloat() or dest_scalar_ty.isRuntimeFloat()) .none else .bits, + ); + try w.writeAll(");"); try f.newline(); - - // ...and ensure padding bits have the correct value. - switch (CType.classifyInt(dest_scalar_ty, zcu)) { - .void => unreachable, // opv - .small => { - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.writeAll(" = zig_wrap_"); - try f.dg.renderTypeForBuiltinFnName(w, dest_scalar_ty); - try w.writeByte('('); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try f.dg.renderBuiltinInfo(w, dest_scalar_ty, .bits); - try w.writeAll(");"); - try f.newline(); - }, - .big => |big| { - const dest_info = dest_scalar_ty.intInfo(zcu); - const padding_index: u16 = switch (f.dg.mod.resolved_target.result.cpu.arch.endian()) { - .little => big.limbs_len - 1, - .big => 0, - }; - const wrap_bits = ((dest_info.bits - 1) % big.limb_size.bits()) + 1; - if (big.limb_size != .@"128" or dest_info.signedness == .unsigned) { - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.print(".limbs[{d}] = zig_wrap_{c}{d}(", .{ - padding_index, - signAbbrev(dest_info.signedness), - big.limb_size.bits(), - }); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.print(".limbs[{d}], {d});", .{ padding_index, wrap_bits }); - } else { - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.print(".limbs[{d}] = zig_bitCast_u128(zig_wrap_i128(zig_bitCast_i128(", .{ - padding_index, - }); - try f.writeCValue(w, dest_local, .other); - try v.elem(f, w); - try w.print(".limbs[{d}]), {d}));", .{ padding_index, wrap_bits }); - try f.newline(); - } - }, - } } try v.end(f, inst, w); @@ -4906,11 +4938,9 @@ fn lowerSwitchCmp( fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool { const dg = f.dg; - const target = &dg.mod.resolved_target.result; return switch (constraint[0]) { '{' => true, - 'i', 'r' => false, - 'I' => !target.cpu.arch.isArm(), + 'r', 'i', 'n', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P' => false, else => switch (value) { .constant => |val| switch (dg.pt.zcu.intern_pool.indexToKey(val.toIntern())) { .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) { @@ -4937,10 +4967,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { const w = &f.code.writer; const inst_ty = f.typeOfIndex(inst); const inst_local = if (inst_ty.hasRuntimeBits(zcu)) local: { - const inst_local = try f.allocLocalValue(.{ - .type = inst_ty, - .alignment = .none, - }); + const inst_local = try f.allocLocalValue(.{ .type = inst_ty }); if (f.wantSafety()) { try f.writeCValue(w, inst_local, .other); try w.writeAll(" = "); @@ -4967,10 +4994,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { if (is_reg) { const output_ty = if (output.operand == .none) inst_ty else f.typeOf(output.operand).childType(zcu); try w.writeAll("register "); - const output_local = try f.allocLocalValue(.{ - .type = output_ty, - .alignment = .none, - }); + const output_local = try f.allocLocalValue(.{ .type = output_ty }); try f.allocs.put(gpa, output_local.new_local, false); try f.dg.renderTypeAndName(w, output_ty, output_local, .{}, .none); try w.writeAll(" __asm(\""); @@ -4989,7 +5013,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { while (it.next()) |input| { const constraint = input.constraint; - if (constraint.len < 1 or mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or + if (constraint.len < 1 or mem.findScalar(u8, "=+&%", constraint[0]) != null or (constraint[0] == '{' and constraint[constraint.len - 1] != '}')) { return f.fail("CBE: constraint not supported: '{s}'", .{constraint}); @@ -5000,10 +5024,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { if (asmInputNeedsLocal(f, constraint, input_val)) { const input_ty = f.typeOf(input.operand); if (is_reg) try w.writeAll("register "); - const input_local = try f.allocLocalValue(.{ - .type = input_ty, - .alignment = .none, - }); + const input_local = try f.allocLocalValue(.{ .type = input_ty }); try f.allocs.put(gpa, input_local.new_local, false); // Do not render the declaration as `const` qualified if we're generating an // explicit `register` local, as GCC will ignore the constraint completely. @@ -5056,7 +5077,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { } const desc = mem.sliceTo(asm_source[src_i..], ']'); - if (mem.indexOfScalar(u8, desc, ':')) |colon| { + if (mem.findScalar(u8, desc, ':')) |colon| { const name = desc[0..colon]; const modifier = desc[colon + 1 ..]; @@ -5853,28 +5874,124 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { else unreachable; + const ref_ret = lowersToBigInt(inst_scalar_ty, zcu); + const ref_operand = lowersToBigInt(scalar_ty, zcu); + const w = &f.code.writer; const local = try f.allocLocal(inst, inst_ty); const v = try Vectorize.start(f, inst, w, operand_ty); - try f.writeCValue(w, local, .other); - try v.elem(f, w); - try w.writeAll(" = "); + if (ref_ret) { + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits <= 128) { + try w.writeAll("zig_"); + try f.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty); + try w.print("_intCast_{c}{d}", .{ + @as(u8, switch (inst_int_info.signedness) { + .signed => 'i', + .unsigned => 'u', + }), + std.math.ceilPowerOfTwoAssert(u16, @max(inst_int_info.bits, 32)), + }); + try w.writeAll("(&"); + try f.writeCValue(w, local, .other); + try v.elem(f, w); + try w.writeAll(", "); + } + } else { + try f.writeCValue(w, local, .other); + try v.elem(f, w); + try w.writeAll(" = "); + } if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) { - try w.writeAll("zig_wrap_"); - try f.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty); - try w.writeByte('('); + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits <= 128) try w.print("zig_{c}{d}_truncate_{[0]c}{[1]d}(", .{ + @as(u8, switch (inst_int_info.signedness) { + .signed => 'i', + .unsigned => 'u', + }), + std.math.ceilPowerOfTwoAssert(u16, @max(inst_int_info.bits, 32)), + }); } try w.writeAll("zig_"); try w.writeAll(operation); try w.writeAll(compilerRtAbbrev(scalar_ty, zcu, target)); try w.writeAll(compilerRtAbbrev(inst_scalar_ty, zcu, target)); try w.writeByte('('); - try f.writeCValue(w, operand, .other); - try v.elem(f, w); + if (ref_ret) { + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits > 128) { + try w.writeByte('&'); + try f.writeCValue(w, local, .other); + try v.elem(f, w); + try w.writeAll(", "); + } + } + if (ref_operand) { + const operand_int_info = scalar_ty.intInfo(zcu); + if (operand_int_info.bits <= 128) { + try w.print("zig_{c}{d}_intCast_", .{ + @as(u8, switch (operand_int_info.signedness) { + .signed => 'i', + .unsigned => 'u', + }), + std.math.ceilPowerOfTwoAssert(u16, @max(operand_int_info.bits, 32)), + }); + try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try w.writeAll("(&"); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + try v.elem(f, w); + try f.dg.renderBuiltinInfo(w, scalar_ty, .none); + try w.writeByte(')'); + } else { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + try v.elem(f, w); + try w.print(", {f}", .{fmtUnsignedIntLiteralSmall( + target, + .uint16_t, + operand_int_info.bits, + false, + 10, + .lower, + )}); + } + } else { + try f.writeCValue(w, operand, .other); + try v.elem(f, w); + } + if (ref_ret) { + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits > 128) try w.print(", {f}", .{fmtUnsignedIntLiteralSmall( + target, + .uint16_t, + inst_int_info.bits, + false, + 10, + .lower, + )}); + } try w.writeByte(')'); if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) { - try f.dg.renderBuiltinInfo(w, inst_scalar_ty, .bits); - try w.writeByte(')'); + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits <= 128) { + try w.print(", {f}", .{ + try f.dg.fmtIntLiteralDec(try pt.intValue(.u8, inst_int_info.bits), .other), + }); + try w.writeByte(')'); + } + } + if (ref_ret) { + const inst_int_info = inst_scalar_ty.intInfo(zcu); + if (inst_int_info.bits <= 128) { + try f.dg.renderBuiltinInfo(w, inst_scalar_ty, .none); + try w.writeByte(')'); + } } try w.writeByte(';'); try f.newline(); @@ -5893,18 +6010,21 @@ fn airUnBuiltinCall( const pt = f.dg.pt; const zcu = pt.zcu; - const operand = try f.resolveInst(operand_ref); - try reap(f, inst, &.{operand_ref}); const inst_ty = f.typeOfIndex(inst); const inst_scalar_ty = inst_ty.scalarType(zcu); const operand_ty = f.typeOf(operand_ref); const scalar_ty = operand_ty.scalarType(zcu); + const is_big = lowersToBigInt(operand_ty, zcu); + + const operand = try f.resolveInst(operand_ref); + if (!is_big) try reap(f, inst, &.{operand_ref}); const ref_ret = lowersToBigInt(inst_scalar_ty, zcu); const ref_arg = lowersToBigInt(scalar_ty, zcu); const w = &f.code.writer; const local = try f.allocLocal(inst, inst_ty); + if (is_big) try reap(f, inst, &.{operand_ref}); const v = try Vectorize.start(f, inst, w, operand_ty); if (!ref_ret) { try f.writeCValue(w, local, .other); @@ -5920,8 +6040,13 @@ fn airUnBuiltinCall( try v.elem(f, w); try w.writeAll(", "); } - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, operand, .other); + if (ref_arg) { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + } else try f.writeCValue(w, operand, .other); try v.elem(f, w); try f.dg.renderBuiltinInfo(w, scalar_ty, info); try w.writeAll(");"); @@ -5941,8 +6066,9 @@ fn airBinBuiltinCall( const zcu = pt.zcu; const bin_op = f.air.instructions.items(.data)[@backingInt(inst)].bin_op; - const operand_ty = f.typeOf(bin_op.lhs); - const is_big = lowersToBigInt(operand_ty, zcu); + const lhs_ty = f.typeOf(bin_op.lhs); + const rhs_ty = f.typeOf(bin_op.rhs); + const is_big = lowersToBigInt(lhs_ty, zcu); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); @@ -5950,22 +6076,31 @@ fn airBinBuiltinCall( const inst_ty = f.typeOfIndex(inst); const inst_scalar_ty = inst_ty.scalarType(zcu); - const scalar_ty = operand_ty.scalarType(zcu); + const lhs_scalar_ty = lhs_ty.scalarType(zcu); + const rhs_scalar_ty = rhs_ty.scalarType(zcu); const ref_ret = lowersToBigInt(inst_scalar_ty, zcu); - const ref_arg = lowersToBigInt(scalar_ty, zcu); + const ref_lhs = lowersToBigInt(lhs_scalar_ty, zcu); + const ref_rhs = lowersToBigInt(rhs_scalar_ty, zcu); const w = &f.code.writer; const local = try f.allocLocal(inst, inst_ty); if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); - const v = try Vectorize.start(f, inst, w, operand_ty); + const v = try Vectorize.start(f, inst, w, lhs_ty); if (!ref_ret) { try f.writeCValue(w, local, .other); try v.elem(f, w); try w.writeAll(" = "); } try w.print("zig_{s}_", .{operation}); - try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try f.dg.renderTypeForBuiltinFnName(w, lhs_scalar_ty); + switch (info) { + .bits, .none, .big_temp_bits => {}, + .bits_none => { + try w.writeByte('_'); + try f.dg.renderTypeForBuiltinFnName(w, rhs_scalar_ty); + }, + } try w.writeByte('('); if (ref_ret) { try w.writeByte('&'); @@ -5973,15 +6108,45 @@ fn airBinBuiltinCall( try v.elem(f, w); try w.writeAll(", "); } - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, lhs, .other); + if (ref_lhs) { + try w.writeByte('&'); + switch (lhs) { + .constant => |lhs_val| try f.dg.renderValueAsLvalue(w, lhs_val), + else => try f.writeCValue(w, lhs, .other), + } + } else try f.writeCValue(w, lhs, .other); try v.elem(f, w); try w.writeAll(", "); - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, rhs, .other); - if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w); - try f.dg.renderBuiltinInfo(w, scalar_ty, info); - try w.writeAll(");\n"); + if (ref_rhs) { + try w.writeByte('&'); + switch (rhs) { + .constant => |rhs_val| try f.dg.renderValueAsLvalue(w, rhs_val), + else => try f.writeCValue(w, rhs, .other), + } + } else try f.writeCValue(w, rhs, .other); + try v.elem(f, w); + try f.dg.renderBuiltinInfo(w, lhs_scalar_ty, info: switch (info) { + .none => .none, + .bits, .bits_none => .bits, + .big_temp_bits => { + if (lowersToBigInt(lhs_scalar_ty, zcu)) { + const temp_local = try f.allocAlignedLocal(inst, .{ + .type = lhs_scalar_ty, + .array_len = 2, + }); + try w.writeAll(", &"); + try f.writeCValue(w, temp_local, .other); + try freeLocal(f, inst, temp_local.new_local, null); + } + break :info .none; + }, + }); + switch (info) { + .none, .bits, .big_temp_bits => {}, + .bits_none => try f.dg.renderBuiltinInfo(w, rhs_scalar_ty, .none), + } + try w.writeAll(");"); + try f.newline(); try v.end(f, inst, w); return local; @@ -6029,12 +6194,22 @@ fn airCmpBuiltinCall( try v.elem(f, w); try w.writeAll(", "); } - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, lhs, .other); + if (ref_arg) { + try w.writeByte('&'); + switch (lhs) { + .constant => |lhs_val| try f.dg.renderValueAsLvalue(w, lhs_val), + else => try f.writeCValue(w, lhs, .other), + } + } else try f.writeCValue(w, lhs, .other); try v.elem(f, w); try w.writeAll(", "); - if (ref_arg) try w.writeByte('&'); - try f.writeCValue(w, rhs, .other); + if (ref_arg) { + try w.writeByte('&'); + switch (rhs) { + .constant => |rhs_val| try f.dg.renderValueAsLvalue(w, rhs_val), + else => try f.writeCValue(w, rhs, .other), + } + } else try f.writeCValue(w, rhs, .other); try v.elem(f, w); try f.dg.renderBuiltinInfo(w, scalar_ty, info); try w.writeByte(')'); @@ -6595,7 +6770,8 @@ fn airShuffleOne(f: *Function, inst: Air.Inst.Index) !CValue { }, .value => |val| try f.dg.renderValue(w, .fromInterned(val), .other), } - try w.writeAll(";\n"); + try w.writeByte(';'); + try f.newline(); } return local; @@ -6653,7 +6829,14 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { const operand_ty = f.typeOf(reduce.operand); const w = &f.code.writer; - const use_operator = scalar_ty.bitSize(zcu) <= 64; + const use_operator, const is_big = if (scalar_ty.isInt(zcu)) switch (CType.classifyInt(scalar_ty, zcu)) { + .void => unreachable, + .small => |int| switch (int) { + else => .{ true, false }, + .zig_u128, .zig_i128 => .{ false, false }, + }, + .big => .{ false, true }, + } else .{ false, false }; const op: union(enum) { const Func = struct { operation: []const u8, info: BuiltinInfo = .none }; builtin: Func, @@ -6742,25 +6925,57 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { try f.newline(); const v = try Vectorize.start(f, inst, w, operand_ty); - try f.writeCValue(w, accum, .other); switch (op) { .builtin => |func| { - try w.print(" = zig_{s}_", .{func.operation}); + const prev_accum = if (is_big) prev_accum: { + const prev_accum = try f.allocLocal(inst, scalar_ty); + try f.writeCValue(w, prev_accum, .other); + try w.writeAll(" = "); + try f.writeCValue(w, accum, .other); + try w.writeByte(';'); + try f.newline(); + break :prev_accum prev_accum; + } else prev_accum: { + try f.writeCValue(w, accum, .other); + try w.writeAll(" = "); + break :prev_accum accum; + }; + try w.print("zig_{s}_", .{func.operation}); try f.dg.renderTypeForBuiltinFnName(w, scalar_ty); try w.writeByte('('); - try f.writeCValue(w, accum, .other); + if (is_big) { + try w.writeByte('&'); + switch (accum) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, accum, .other), + } + try w.writeAll(", &"); + switch (prev_accum) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, prev_accum, .other), + } + } else try f.writeCValue(w, prev_accum, .other); try w.writeAll(", "); - try f.writeCValue(w, operand, .other); + if (is_big) { + try w.writeByte('&'); + switch (operand) { + .constant => |val| try f.dg.renderValueAsLvalue(w, val), + else => try f.writeCValue(w, operand, .other), + } + } else try f.writeCValue(w, operand, .other); try v.elem(f, w); try f.dg.renderBuiltinInfo(w, scalar_ty, func.info); try w.writeByte(')'); + if (is_big) try freeLocal(f, inst, prev_accum.new_local, null); }, .infix => |ass| { + try f.writeCValue(w, accum, .other); try w.writeAll(ass); try f.writeCValue(w, operand, .other); try v.elem(f, w); }, .ternary => |cmp| { + try f.writeCValue(w, accum, .other); try w.writeAll(" = "); try f.writeCValue(w, accum, .other); try w.writeAll(cmp); @@ -7097,101 +7312,6 @@ fn writeMemoryOrder(w: *Writer, order: std.lang.AtomicOrder) !void { return w.writeAll(toMemoryOrder(order)); } -fn toCallingConvention(cc: std.lang.CallingConvention, zcu: *Zcu) ?[]const u8 { - if (zcu.getTarget().cCallingConvention()) |ccc| { - if (cc.eql(ccc)) { - return null; - } - } - return switch (cc) { - .auto, .naked => null, - - .x86_16_cdecl => "cdecl", - .x86_16_regparmcall => "regparmcall", - .x86_64_sysv, .x86_sysv => "sysv_abi", - .x86_64_win, .x86_win => "ms_abi", - .x86_16_stdcall, .x86_stdcall => "stdcall", - .x86_fastcall => "fastcall", - .x86_thiscall => "thiscall", - - .x86_vectorcall, - .x86_64_vectorcall, - => "vectorcall", - - .x86_64_regcall_v3_sysv, - .x86_64_regcall_v4_win, - .x86_regcall_v3, - .x86_regcall_v4_win, - => "regcall", - - .aarch64_vfabi => "aarch64_vector_pcs", - .aarch64_vfabi_sve => "aarch64_sve_pcs", - - .arm_aapcs => "pcs(\"aapcs\")", - .arm_aapcs_vfp => "pcs(\"aapcs-vfp\")", - - .arc_interrupt => |opts| switch (opts.type) { - inline else => |t| "interrupt(\"" ++ @tagName(t) ++ "\")", - }, - - .arm_interrupt => |opts| switch (opts.type) { - .generic => "interrupt", - .irq => "interrupt(\"IRQ\")", - .fiq => "interrupt(\"FIQ\")", - .swi => "interrupt(\"SWI\")", - .abort => "interrupt(\"ABORT\")", - .undef => "interrupt(\"UNDEF\")", - }, - - .avr_signal => "signal", - - .microblaze_interrupt => |opts| switch (opts.type) { - .user => "save_volatiles", - .regular => "interrupt_handler", - .fast => "fast_interrupt", - .breakpoint => "break_handler", - }, - - .mips_interrupt, - .mips64_interrupt, - => |opts| switch (opts.mode) { - inline else => |m| "interrupt(\"" ++ @tagName(m) ++ "\")", - }, - - .riscv64_lp64_v, .riscv32_ilp32_v => "riscv_vector_cc", - - .riscv32_interrupt, - .riscv64_interrupt, - => |opts| switch (opts.mode) { - inline else => |m| "interrupt(\"" ++ @tagName(m) ++ "\")", - }, - - .sh_renesas => "renesas", - .sh_interrupt => |opts| switch (opts.save) { - .fpscr => "trapa_handler", // Implies `interrupt_handler`. - .high => "interrupt_handler, nosave_low_regs", - .full => "interrupt_handler", - .bank => "interrupt_handler, resbank", - }, - - .m68k_rtd => "m68k_rtd", - - .avr_interrupt, - .csky_interrupt, - .m68k_interrupt, - .msp430_interrupt, - .x86_16_interrupt, - .x86_interrupt, - .x86_64_interrupt, - => "interrupt", - - .ez80_tiflags, - => "__tiflags__", - - else => unreachable, // `Zcu.callconvSupported` - }; -} - fn toAtomicRmwSuffix(order: std.lang.AtomicRmwOp) []const u8 { return switch (order) { .Xchg => "xchg", @@ -7224,17 +7344,18 @@ fn signAbbrev(signedness: std.lang.Signedness) u8 { fn compilerRtAbbrev(ty: Type, zcu: *Zcu, target: *const std.Target) []const u8 { return if (ty.isInt(zcu)) switch (ty.intInfo(zcu).bits) { + 0 => unreachable, 1...32 => "si", 33...64 => "di", 65...128 => "ti", - else => unreachable, + else => "ei", } else if (ty.isRuntimeFloat()) switch (ty.floatBits(target)) { + else => unreachable, 16 => "hf", 32 => "sf", 64 => "df", 80 => "xf", - 128 => "tf", - else => unreachable, + 128 => if (target.cpu.arch.isPowerPC()) "kf" else "tf", } else unreachable; } @@ -7390,10 +7511,8 @@ fn fmtStringLiteral(str: []const u8, sentinel: ?u8) std.fmt.Alt(FormatStringCont return .{ .data = .{ .str = str, .sentinel = sentinel } }; } -fn undefPattern(comptime IntType: type) IntType { - const int_info = @typeInfo(IntType).int; - const UnsignedType = @Int(.unsigned, int_info.bits); - return @bitCast(@as(UnsignedType, (1 << (int_info.bits | 1)) / 3)); +fn undefPattern(comptime Result: type) Result { + return @bitCast(@as(@Int(.unsigned, @bitSizeOf(Result)), (1 << (@bitSizeOf(Result) | 1)) / 3)); } const FormatIntLiteralContext = struct { @@ -7580,11 +7699,9 @@ const FormatSignedIntLiteralSmall = struct { case: std.fmt.Case, pub fn format(data: FormatSignedIntLiteralSmall, w: *Writer) Writer.Error!void { const bits = data.int_cty.bits(data.target); - const max_int: i64 = @bitCast((@as(u64, 1) << @intCast(bits - 1)) - 1); - const min_int: i64 = @bitCast(@as(u64, 1) << @intCast(bits - 1)); - if (data.val == max_int) { + if (data.val == @as(i64, std.math.maxInt(i64)) >> @intCast(64 - bits)) { return w.print("{s}_MAX", .{minMaxMacroPrefix(data.int_cty)}); - } else if (data.val == min_int) { + } else if (data.val == @as(i64, std.math.minInt(i64)) >> @intCast(64 - bits)) { return w.print("{s}_MIN", .{minMaxMacroPrefix(data.int_cty)}); } if (data.val < 0) try w.writeByte('-'); @@ -7596,7 +7713,7 @@ const FormatSignedIntLiteralSmall = struct { 16 => try w.writeAll("0x"), else => unreachable, } - // This `@abs` is safe thanks to the `min_int` case above. + // This `@abs` is safe thanks to the min int check above. try w.printInt(@abs(data.val), data.base, data.case, .{}); try w.writeAll(intLiteralSuffix(data.int_cty)); } @@ -7610,8 +7727,7 @@ const FormatUnsignedIntLiteralSmall = struct { case: std.fmt.Case, pub fn format(data: FormatUnsignedIntLiteralSmall, w: *Writer) Writer.Error!void { const bits = data.int_cty.bits(data.target); - const max_int: u64 = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - bits); - if (data.val == max_int) { + if (data.val == @as(u64, std.math.maxInt(u64)) >> @intCast(64 - bits)) { return w.print("{s}_MAX", .{minMaxMacroPrefix(data.int_cty)}); } try w.writeAll(intLiteralPrefix(data.int_cty, data.is_global)); @@ -7735,6 +7851,31 @@ fn intLiteralSuffix(cty: CType.Int) []const u8 { }; } +const F80Repr = packed struct { + mantissa: u64, + exponent: u16, + + fn write(repr: F80Repr, w: *Writer, target: *const std.Target, is_global: bool) Writer.Error!void { + try w.print("zig_{s}_repr_f80({f}, {f})", .{ + if (is_global) "init" else "make", + fmtUnsignedIntLiteralSmall(target, .uint64_t, repr.mantissa, is_global, 16, .lower), + fmtUnsignedIntLiteralSmall(target, .uint16_t, repr.exponent, is_global, 16, .lower), + }); + } +}; +const F128Repr = packed struct { + lo: u64, + hi: u64, + + fn write(repr: F128Repr, w: *Writer, target: *const std.Target, is_global: bool) Writer.Error!void { + try w.print("zig_{s}_repr_f128({f}, {f})", .{ + if (is_global) "init" else "make", + fmtUnsignedIntLiteralSmall(target, .uint64_t, repr.hi, is_global, 16, .lower), + fmtUnsignedIntLiteralSmall(target, .uint64_t, repr.lo, is_global, 16, .lower), + }); + } +}; + const Materialize = struct { local: CValue, diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig index 8e86c0da93dabcda0bdfec08c406bbe0dab4f04d..01b474dc9c7cfa2c995cae0f3e75b238b8447619 100644 --- a/src/codegen/c/type.zig +++ b/src/codegen/c/type.zig @@ -44,8 +44,181 @@ pub const CType = union(enum) { param_tys: []const CType, ret_ty: *const CType, varargs: bool, + cc: CallingConvention, }, + pub const CallingConvention = enum { + c, + + cdecl, + regparmcall, + sysv_abi, + ms_abi, + stdcall, + fastcall, + thiscall, + + vectorcall, + + regcall, + + preserve_none, + + aarch64_vector_pcs, + aarch64_sve_pcs, + + @"pcs(\"aapcs\")", + @"pcs(\"aapcs-vfp\")", + + @"interrupt(\"ilink1\")", + @"interrupt(\"ilink2\")", + @"interrupt(\"ilink\")", + @"interrupt(\"firq\")", + + interrupt, + @"interrupt(\"IRQ\")", + @"interrupt(\"FIQ\")", + @"interrupt(\"SWI\")", + @"interrupt(\"ABORT\")", + @"interrupt(\"UNDEF\")", + + signal, + + save_volatiles, + interrupt_handler, + fast_interrupt, + break_handler, + + @"interrupt(\"eic\")", + @"interrupt(\"sw0\")", + @"interrupt(\"sw1\")", + @"interrupt(\"hw0\")", + @"interrupt(\"hw1\")", + @"interrupt(\"hw2\")", + @"interrupt(\"hw3\")", + @"interrupt(\"hw4\")", + @"interrupt(\"hw5\")", + + riscv_vector_cc, + @"interrupt(\"supervisor\")", + @"interrupt(\"machine\")", + + renesas, + /// Implies `interrupt_handler`. + trapa_handler, + @"interrupt_handler, nosave_low_regs", + @"interrupt_handler, resbank", + + m68k_rtd, + + tiflags, + + pub fn fromLang(cc: std.lang.CallingConvention, target: *const std.Target) CallingConvention { + if (target.cCallingConvention()) |ccc| { + if (cc.eql(ccc)) { + return .c; + } + } + return switch (cc) { + .auto, .naked => .c, + + .x86_16_cdecl => .cdecl, + .x86_16_regparmcall => .regparmcall, + .x86_64_sysv, .x86_sysv => .sysv_abi, + .x86_64_win, .x86_win, .x86_mingw => .ms_abi, + .x86_16_stdcall, .x86_stdcall => .stdcall, + .x86_fastcall => .fastcall, + .x86_thiscall => .thiscall, + + .x86_vectorcall, + .x86_64_vectorcall, + => .vectorcall, + + .x86_64_regcall_v3_sysv, + .x86_64_regcall_v4_win, + .x86_regcall_v3, + .x86_regcall_v4_win, + => .regcall, + + .x86_64_preserve_none, + .aarch64_preserve_none, + => .preserve_none, + + .aarch64_vfabi => .aarch64_vector_pcs, + .aarch64_vfabi_sve => .aarch64_sve_pcs, + + .arm_aapcs => .@"pcs(\"aapcs\")", + .arm_aapcs_vfp => .@"pcs(\"aapcs-vfp\")", + + .arc_interrupt => |opts| switch (opts.type) { + .ilink1 => .@"interrupt(\"ilink1\")", + .ilink2 => .@"interrupt(\"ilink2\")", + .ilink => .@"interrupt(\"ilink\")", + .firq => .@"interrupt(\"firq\")", + }, + + .arm_interrupt => |opts| switch (opts.type) { + .generic => .interrupt, + .irq => .@"interrupt(\"IRQ\")", + .fiq => .@"interrupt(\"FIQ\")", + .swi => .@"interrupt(\"SWI\")", + .abort => .@"interrupt(\"ABORT\")", + .undef => .@"interrupt(\"UNDEF\")", + }, + + .avr_signal => .signal, + + .microblaze_interrupt => |opts| switch (opts.type) { + .user => .save_volatiles, + .regular => .interrupt_handler, + .fast => .fast_interrupt, + .breakpoint => .break_handler, + }, + + .mips_interrupt, .mips64_interrupt => |opts| switch (opts.mode) { + .eic => .@"interrupt(\"eic\")", + .sw0 => .@"interrupt(\"sw0\")", + .sw1 => .@"interrupt(\"sw1\")", + .hw0 => .@"interrupt(\"hw0\")", + .hw1 => .@"interrupt(\"hw1\")", + .hw2 => .@"interrupt(\"hw2\")", + .hw3 => .@"interrupt(\"hw3\")", + .hw4 => .@"interrupt(\"hw4\")", + .hw5 => .@"interrupt(\"hw5\")", + }, + + .riscv64_lp64_v, .riscv32_ilp32_v => .riscv_vector_cc, + .riscv32_interrupt, .riscv64_interrupt => |opts| switch (opts.mode) { + .supervisor => .@"interrupt(\"supervisor\")", + .machine => .@"interrupt(\"machine\")", + }, + + .sh_renesas => .renesas, + .sh_interrupt => |opts| switch (opts.save) { + .fpscr => .trapa_handler, + .high => .@"interrupt_handler, nosave_low_regs", + .full => .interrupt_handler, + .bank => .@"interrupt_handler, resbank", + }, + + .m68k_rtd => .m68k_rtd, + + .avr_interrupt, + .csky_interrupt, + .m68k_interrupt, + .msp430_interrupt, + .x86_16_interrupt, + .x86_interrupt, + .x86_64_interrupt, + => .interrupt, + + .ez80_tiflags => .tiflags, + + else => unreachable, // `Zcu.callconvSupported` + }; + } + }; + /// Returns `true` if this node has a postfix operator, meaning an `[...]` or `(...)` appears /// after the identifier in a declarator with this type. In this case, if this node is wrapped /// in a pointer type, we will need to add parentheses due to operator precedence. @@ -130,28 +303,28 @@ pub const CType = union(enum) { pub fn bits(int: Int, target: *const std.Target) u16 { return switch (int) { // zig fmt: off - .char => target.cTypeBitSize(.char), + .char => target.cTypeBitSize(.char).?, - .@"unsigned short" => target.cTypeBitSize(.ushort), - .@"unsigned int" => target.cTypeBitSize(.uint), - .@"unsigned long" => target.cTypeBitSize(.ulong), - .@"unsigned long long" => target.cTypeBitSize(.ulonglong), + .@"unsigned short" => target.cTypeBitSize(.ushort).?, + .@"unsigned int" => target.cTypeBitSize(.uint).?, + .@"unsigned long" => target.cTypeBitSize(.ulong).?, + .@"unsigned long long" => target.cTypeBitSize(.ulonglong).?, - .@"signed short" => target.cTypeBitSize(.short), - .@"signed int" => target.cTypeBitSize(.int), - .@"signed long" => target.cTypeBitSize(.long), - .@"signed long long" => target.cTypeBitSize(.longlong), + .@"signed short" => target.cTypeBitSize(.short).?, + .@"signed int" => target.cTypeBitSize(.int).?, + .@"signed long" => target.cTypeBitSize(.long).?, + .@"signed long long" => target.cTypeBitSize(.longlong).?, - .uintptr_t, .intptr_t => target.ptrBitWidth(), + .uintptr_t, .intptr_t => target.ptrBitWidth(), - .uint8_t, .int8_t => 8, - .uint16_t, .int16_t => 16, - .uint24_t, .int24_t => 24, - .uint32_t, .int32_t => 32, - .uint48_t, .int48_t => 48, - .uint64_t, .int64_t => 64, - .zig_u128, .zig_i128 => 128, - // zig fmt: on + .uint8_t, .int8_t => 8, + .uint16_t, .int16_t => 16, + .uint24_t, .int24_t => 24, + .uint32_t, .int32_t => 32, + .uint48_t, .int48_t => 48, + .uint64_t, .int64_t => 64, + .zig_u128, .zig_i128 => 128, + // zig fmt: on }; } }; @@ -376,6 +549,7 @@ pub const CType = union(enum) { .ret_ty = ret_cty_buf, .param_tys = param_cty_buf, .varargs = func_type.is_var_args, + .cc = .fromLang(func_type.cc, zcu.getTarget()), } }; } try deps.addType(gpa, cur_ty, allow_incomplete); @@ -763,6 +937,13 @@ pub const CType = union(enum) { try w.writeByte('('); }, } + switch (ptr.elem_ty.*) { + else => {}, + .function => |function| switch (function.cc) { + .c => {}, + else => |cc| try w.print("zig_callconv({t}) ", .{cc}), + }, + } try w.writeByte('*'); }, @@ -812,7 +993,7 @@ pub const CType = union(enum) { => {}, .pointer => |ptr| { - // Match opening paren "(" write `writeTypePrefix`. + // Match opening paren "(" in `writeTypePrefix`. switch (ptr.elem_ty.kind()) { .specifier, .pointer => {}, .postfix_op => try w.writeByte(')'), diff --git a/src/codegen/c/type/render_defs.zig b/src/codegen/c/type/render_defs.zig index 03aae41ee0ec47cca9b560bd358263a5b0cb2352..2ba76d64eda0073dc0cdb032d117fedf16fba0ae 100644 --- a/src/codegen/c/type/render_defs.zig +++ b/src/codegen/c/type/render_defs.zig @@ -21,16 +21,21 @@ pub fn defineAligned( if (complete and alignment.compareStrict(.lt, ty.abiAlignment(zcu))) { try w.print("zig_under_align({d}) ", .{alignment.toByteUnits().?}); } - try w.print("{f}{f}{f}; /* align({d}) {f} */\n", .{ + try w.print("{f}{f}{f};", .{ cty.fmtDeclaratorPrefix(zcu), name_cty.fmtTypeName(zcu), cty.fmtDeclaratorSuffix(zcu), + }); + if (!zcu.comp.config.root_strip) try w.print(" /* align({d}) {f} */", .{ alignment.toByteUnits().?, ty.fmt(pt), }); + try w.writeByte('\n'); } /// Renders the definition of a big-int `struct`. pub fn defineBigInt(big: CType.BigInt, w: *Writer, zcu: *const Zcu) Writer.Error!void { + const target = zcu.getTarget(); + const bits = big.limb_size.bits() *| big.limbs_len; const name_cty: CType = .{ .bigint = .{ .limb_size = big.limb_size, .limbs_len = big.limbs_len, @@ -41,12 +46,20 @@ pub fn defineBigInt(big: CType.BigInt, w: *Writer, zcu: *const Zcu) Writer.Error .elem_ty = &limb_cty, .nonstring = limb_cty.isStringElem(), } }; - try w.print("{f} {{ {f}limbs{f}; }}; /* {d} bits */\n", .{ + try w.print("{f} {{ {f}limbs{f}; }};", .{ name_cty.fmtTypeName(zcu), array_cty.fmtDeclaratorPrefix(zcu), array_cty.fmtDeclaratorSuffix(zcu), - big.limb_size.bits() * @as(u17, big.limbs_len), }); + if (!zcu.comp.config.root_strip) try w.print(" /* u{d}, i{d} */", .{ bits, bits }); + try w.writeByte('\n'); + try writeStaticAssertCTypeLayout( + name_cty, + std.zig.target.intByteSize(target, bits), + .fromByteUnits(std.zig.target.intAlignment(target, bits)), + w, + zcu, + ); } /// Renders a forward declaration of the `struct` which represents an error union whose payload type @@ -81,27 +94,28 @@ pub fn errunionDefineComplete( if (payload_ty.hasRuntimeBits(zcu)) { const payload_cty: CType = try .lower(payload_ty, deps, arena, zcu); try w.print( - \\{f} {{ /* anyerror!{f} */ + \\{f} {{ \\ {f}payload{f}; \\ {f}error{f}; \\}}; - \\ , .{ name_cty.fmtTypeName(zcu), - payload_ty.fmt(pt), payload_cty.fmtDeclaratorPrefix(zcu), payload_cty.fmtDeclaratorSuffix(zcu), error_cty.fmtDeclaratorPrefix(zcu), error_cty.fmtDeclaratorSuffix(zcu), }); } else { - try w.print("{f} {{ {f}error{f}; }}; /* anyerror!{f} */\n", .{ + try w.print("{f} {{ {f}error{f}; }};", .{ name_cty.fmtTypeName(zcu), error_cty.fmtDeclaratorPrefix(zcu), error_cty.fmtDeclaratorSuffix(zcu), - payload_ty.fmt(pt), }); } + if (!zcu.comp.config.root_strip) try w.print(" /* anyerror!{f} */", .{ + payload_ty.fmt(pt), + }); + try w.writeByte('\n'); } /// If the Zig type `ty` lowers to a `struct` or `union` type, renders a forward declaration of that @@ -141,10 +155,13 @@ pub fn defineIncomplete(ty: Type, w: *Writer, pt: Zcu.PerThread) Writer.Error!vo }, else => return, }; - try w.print("typedef void {f}; /* {f} */\n", .{ + try w.print("typedef void {f};", .{ name_cty.fmtTypeName(zcu), + }); + if (!zcu.comp.config.root_strip) try w.print(" /* {f} */", .{ ty.fmt(pt), }); + try w.writeByte('\n'); } /// If the Zig type `ty` lowers to a `struct` or `union` type, or to a `typedef`, renders the @@ -163,13 +180,13 @@ pub fn defineComplete( ty.assertHasLayout(zcu); - switch (ty.zigTypeTag(zcu)) { + const check_cty = check_cty: switch (ty.zigTypeTag(zcu)) { .@"fn" => if (!ty.fnHasRuntimeBits(zcu)) { const name_cty: CType = .{ .@"fn" = ty }; - try w.print("typedef void {f}; /* {f} */\n", .{ + try w.print("typedef void {f};", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); + break :check_cty null; } else { const ip = &zcu.intern_pool; const func_type = ip.indexToKey(ty.toIntern()).func_type; @@ -186,10 +203,12 @@ pub fn defineComplete( const name_cty: CType = .{ .@"fn" = ty }; const ret_cty: CType = try .lower(effective_ret_ty, deps, arena, zcu); - try w.print("typedef {f}{f}(", .{ - ret_cty.fmtDeclaratorPrefix(zcu), - name_cty.fmtTypeName(zcu), - }); + try w.print("typedef {f}", .{ret_cty.fmtDeclaratorPrefix(zcu)}); + switch (CType.CallingConvention.fromLang(func_type.cc, zcu.getTarget())) { + .c => {}, + else => |cc| try w.print("zig_callconv({t}) ", .{cc}), + } + try w.print("{f}(", .{name_cty.fmtTypeName(zcu)}); var any_params = false; for (func_type.param_types.get(ip)) |param_ty_ip| { const param_ty: Type = .fromInterned(param_ty_ip); @@ -205,88 +224,85 @@ pub fn defineComplete( } else if (!any_params) { try w.writeAll("void"); } - try w.print("){f}; /* {f} */\n", .{ - ret_cty.fmtDeclaratorSuffixIgnoreNonstring(zcu), - ty.fmt(pt), - }); + try w.print("){f};", .{ret_cty.fmtDeclaratorSuffixIgnoreNonstring(zcu)}); + break :check_cty null; }, .@"enum" => { const name_cty: CType = .{ .@"enum" = ty }; const cty: CType = try .lower(ty.backingIntType(zcu), deps, arena, zcu); - try w.print("typedef {f}{f}{f}; /* {f} */\n", .{ + try w.print("typedef {f}{f}{f};", .{ cty.fmtDeclaratorPrefix(zcu), name_cty.fmtTypeName(zcu), cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), }); + break :check_cty null; }, - .@"struct" => if (ty.isTuple(zcu)) { - try defineTuple(ty, deps, arena, w, pt); - } else switch (ty.containerLayout(zcu)) { - .auto, .@"extern" => try defineStruct(ty, deps, arena, w, pt), + .@"struct" => if (ty.isTuple(zcu)) + if (ty.hasRuntimeBits(zcu)) try defineTuple(ty, deps, arena, w, pt) else return + else switch (ty.containerLayout(zcu)) { + .auto, .@"extern" => if (ty.hasRuntimeBits(zcu)) try defineStruct(ty, deps, arena, w, pt) else return, .@"packed" => try defineBitpack(ty, deps, arena, w, pt), }, .@"union" => switch (ty.containerLayout(zcu)) { - .auto => try defineUnionAuto(ty, deps, arena, w, pt), - .@"extern" => try defineUnionExtern(ty, deps, arena, w, pt), + .auto => if (ty.hasRuntimeBits(zcu)) try defineUnionAuto(ty, deps, arena, w, pt) else return, + .@"extern" => if (ty.hasRuntimeBits(zcu)) try defineUnionExtern(ty, deps, arena, w, pt) else return, .@"packed" => try defineBitpack(ty, deps, arena, w, pt), }, .pointer => if (ty.isSlice(zcu)) { const name_cty: CType = .{ .slice = ty }; const ptr_cty: CType = try .lower(ty.slicePtrFieldType(zcu), deps, arena, zcu); try w.print( - \\{f} {{ /* {f} */ + \\{f} {{ \\ {f}ptr{f}; - \\ size_t len; + \\ uintptr_t len; \\}}; - \\ , .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), ptr_cty.fmtDeclaratorPrefix(zcu), ptr_cty.fmtDeclaratorSuffix(zcu), }); - // Don't bother with `writeStaticAssertLayout`---there's not really any way we could mess - // slices up, and they're all obviously the same layout. - }, + break :check_cty switch (ty.toIntern()) { + .slice_const_u8_sentinel_0_type => name_cty, + else => null, + }; + } else return, .optional => switch (CType.classifyOptional(ty, zcu)) { .error_set, .ptr_like, .slice_like, .npv_payload, - => {}, + => return, .opv_payload => { const name_cty: CType = .{ .opt = ty }; - try w.print("{f} {{ bool is_null; }}; /* {f} */\n", .{ + try w.print("{f} {{ bool is_null; }};", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); - try writeStaticAssertLayout(ty, name_cty, w, zcu); + break :check_cty switch (ty.toIntern()) { + .optional_noreturn_type => name_cty, + else => null, + }; }, .@"struct" => { const name_cty: CType = .{ .opt = ty }; const payload_cty: CType = try .lower(ty.optionalChild(zcu), deps, arena, zcu); try w.print( - \\{f} {{ /* {f} */ + \\{f} {{ \\ {f}payload{f}; \\ bool is_null; \\}}; - \\ , .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), payload_cty.fmtDeclaratorPrefix(zcu), payload_cty.fmtDeclaratorSuffix(zcu), }); - try writeStaticAssertLayout(ty, name_cty, w, zcu); + break :check_cty name_cty; }, }, .array => if (ty.hasRuntimeBits(zcu)) { - const elem_ty = ty.childType(zcu); const name_cty: CType = .{ .arr = ty }; - const elem_cty: CType = try .lower(elem_ty, deps, arena, zcu); + const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu); const array_cty: CType = .{ .array = .{ .len = ty.arrayLenIncludingSentinel(zcu), .elem_ty = &elem_cty, @@ -296,43 +312,35 @@ pub fn defineComplete( break :nonstring Value.compareHetero(s, .neq, .zero_comptime_int, zcu); }, } }; - if (elem_ty.defaultStructFieldAlignment(.auto, zcu) == elem_ty.abiAlignment(zcu)) { - try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{ - name_cty.fmtTypeName(zcu), - array_cty.fmtDeclaratorPrefix(zcu), - array_cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), - }); - } else { - try w.print("zig_packed({f} {{ zig_under_align({d}) {f}array{f}; }}); /* {f} */\n", .{ - name_cty.fmtTypeName(zcu), - elem_ty.abiAlignment(zcu).toByteUnits().?, - array_cty.fmtDeclaratorPrefix(zcu), - array_cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), - }); - } - try writeStaticAssertLayout(ty, name_cty, w, zcu); - }, + try w.print("{f} {{ {f}array{f}; }};", .{ + name_cty.fmtTypeName(zcu), + array_cty.fmtDeclaratorPrefix(zcu), + array_cty.fmtDeclaratorSuffix(zcu), + }); + break :check_cty name_cty; + } else return, .vector => if (ty.hasRuntimeBits(zcu)) { - const elem_ty = ty.childType(zcu); const name_cty: CType = .{ .vec = ty }; - const elem_cty: CType = try .lower(elem_ty, deps, arena, zcu); + const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu); const array_cty: CType = .{ .array = .{ .len = ty.arrayLenIncludingSentinel(zcu), .elem_ty = &elem_cty, .nonstring = elem_cty.isStringElem(), } }; - try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{ + try w.print("{f} {{ {f}array{f}; }};", .{ name_cty.fmtTypeName(zcu), array_cty.fmtDeclaratorPrefix(zcu), array_cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), }); - try writeStaticAssertLayout(ty, name_cty, w, zcu); - }, - else => {}, - } + break :check_cty name_cty; + } else return, + else => return, + }; + if (!zcu.comp.config.root_strip) try w.print(" /* {f} */", .{ + ty.fmt(pt), + }); + try w.writeByte('\n'); + if (check_cty) |cty| try writeStaticAssertTypeLayout(ty, cty, w, zcu); } fn defineBitpack( ty: Type, @@ -340,16 +348,16 @@ fn defineBitpack( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!?CType { const zcu = pt.zcu; const name_cty: CType = .{ .bitpack = ty }; const cty: CType = try .lower(ty.backingIntType(zcu), deps, arena, zcu); - try w.print("typedef {f}{f}{f}; /* {f} */\n", .{ + try w.print("typedef {f}{f}{f};", .{ cty.fmtDeclaratorPrefix(zcu), name_cty.fmtTypeName(zcu), cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), }); + return null; } fn defineTuple( ty: Type, @@ -357,72 +365,54 @@ fn defineTuple( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!CType { const zcu = pt.zcu; - if (!ty.hasRuntimeBits(zcu)) return; const ip = &zcu.intern_pool; const tuple = ip.indexToKey(ty.toIntern()).tuple_type; + // Fields cannot be underaligned, because tuple fields cannot have specified alignments. + // However, overaligned fields are possible thanks to intermediate zero-bit fields. + const tuple_align = ty.abiAlignment(zcu); - // If there are any underaligned fields, we need to byte-pack the tuple. - const pack: bool = pack: { - var offset: u64 = 0; - for (tuple.types.get(ip)) |field_ty_ip| { - const field_ty: Type = .fromInterned(field_ty_ip); - if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); - const natural_offset = natural_align.forward(offset); - offset = field_ty.abiAlignment(zcu).forward(offset); - if (offset < natural_offset) break :pack true; - // Also pack if any field is more aligned than the tuple should be. - if (natural_align.compareStrict(.gt, tuple_align)) break :pack true; - offset += field_ty.abiSize(zcu); - } - break :pack false; - }; - // If the alignment of other fields would not give the tuple sufficient alignment, we // need to align the first field (which does not affect its offset, because 0 is always // well-aligned) to indirectly specify the tuple alignment. - const overalign: bool = switch (pack) { - true => tuple_align.compareStrict(.gt, .@"1"), - false => for (tuple.types.get(ip)) |field_ty_ip| { - const field_ty: Type = .fromInterned(field_ty_ip); - if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); - if (natural_align.compareStrict(.gte, tuple_align)) break false; - } else true, - }; + const overalign: bool = for (tuple.types.get(ip)) |field_ty_ip| { + const field_ty: Type = .fromInterned(field_ty_ip); + if (!field_ty.hasRuntimeBits(zcu)) continue; + const natural_align = field_ty.abiAlignment(zcu); + if (natural_align.compareStrict(.gte, tuple_align)) break false; + } else true; - if (pack) try w.writeAll("zig_packed("); const name_cty: CType = .{ .@"struct" = ty }; - try w.print("{f} {{ /* {f} */\n", .{ + try w.print("{f} {{\n", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); var zig_offset: u64 = 0; var c_offset: u64 = 0; for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty_ip, field_val_ip, field_index| { if (field_val_ip != .none) continue; // `comptime` field const field_ty: Type = .fromInterned(field_ty_ip); - zig_offset = field_ty.abiAlignment(zcu).forward(zig_offset); + const field_align = field_ty.abiAlignment(zcu); + zig_offset = field_align.forward(zig_offset); if (!field_ty.hasRuntimeBits(zcu)) continue; - if (!pack) c_offset = field_ty.defaultStructFieldAlignment(.auto, zcu).forward(c_offset); + c_offset = field_align.forward(c_offset); try w.writeByte(' '); if (zig_offset == 0 and overalign) { // This is the first field; specify its alignment to align the tuple. try writeFieldAlign(field_ty, tuple_align, w, zcu); - } else if (zig_offset > c_offset) { - // This field needs to be underaligned or overaligned compared to what its - // offset would otherwise be. - const need_align: Alignment = .minStrict( - tuple_align, // don't make the tuple more aligned than it should be - .fromLog2Units(@ctz(zig_offset)), - ); - try writeFieldAlign(field_ty, need_align, w, zcu); - c_offset = need_align.forward(c_offset); + } else switch (zig_offset - c_offset) { + 0 => {}, + else => |need_bytes| { + // This field needs to be overaligned compared to what its offset would otherwise be. + const need_align: Alignment = .fromLog2Units(std.math.log2_int(u64, need_bytes) + 1); + assert(need_align.compareStrict(.lte, tuple_align)); + try writeFieldAlign(field_ty, need_align, w, zcu); + c_offset = need_align.forward(c_offset); + }, } + assert(c_offset == zig_offset); const field_cty: CType = try .lower(field_ty, deps, arena, zcu); try w.print("{f}f{d}{f};\n", .{ field_cty.fmtDeclaratorPrefix(zcu), @@ -433,11 +423,8 @@ fn defineTuple( zig_offset += field_size; c_offset += field_size; } - try w.writeByte('}'); - if (pack) try w.writeByte(')'); - try w.writeAll(";\n"); - - try writeStaticAssertLayout(ty, name_cty, w, zcu); + try w.writeAll("};"); + return name_cty; } fn defineStruct( ty: Type, @@ -445,9 +432,8 @@ fn defineStruct( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!CType { const zcu = pt.zcu; - if (!ty.hasRuntimeBits(zcu)) return; const ip = &zcu.intern_pool; const struct_type = ip.loadStructType(ty.toIntern()); @@ -459,7 +445,7 @@ fn defineStruct( while (it.next()) |field_index| { const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu); + const natural_align = field_ty.abiAlignment(zcu); const natural_offset = natural_align.forward(offset); const actual_offset = struct_type.field_offsets.get(ip)[field_index]; if (actual_offset < natural_offset) break :pack true; @@ -480,7 +466,7 @@ fn defineStruct( while (it.next()) |field_index| { const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gte, struct_type.alignment)) break :overalign false; } break :overalign true; @@ -489,16 +475,15 @@ fn defineStruct( if (pack) try w.writeAll("zig_packed("); const name_cty: CType = .{ .@"struct" = ty }; - try w.print("{f} {{ /* {f} */\n", .{ + try w.print("{f} {{\n", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); var it = struct_type.iterateRuntimeOrder(ip); var offset: u64 = 0; while (it.next()) |field_index| { const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu); + const natural_align = field_ty.abiAlignment(zcu); const natural_offset = switch (pack) { true => offset, false => natural_align.forward(offset), @@ -529,9 +514,8 @@ fn defineStruct( assert(struct_type.alignment.forward(offset) == struct_type.size); try w.writeByte('}'); if (pack) try w.writeByte(')'); - try w.writeAll(";\n"); - - try writeStaticAssertLayout(ty, name_cty, w, zcu); + try w.writeByte(';'); + return name_cty; } fn defineUnionAuto( ty: Type, @@ -539,9 +523,8 @@ fn defineUnionAuto( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!CType { const zcu = pt.zcu; - if (!ty.hasRuntimeBits(zcu)) return; const ip = &zcu.intern_pool; const union_type = ip.loadUnionType(ty.toIntern()); @@ -553,7 +536,7 @@ fn defineUnionAuto( const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gt, union_type.alignment)) break true; // The tag will immediately follow the payload. This layout may put the tag in what would // otherwise be padding on the payload union, because if the most-aligned union field is not @@ -571,7 +554,7 @@ fn defineUnionAuto( false => for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gte, union_type.alignment)) break false; } else overalign: { if (union_type.has_runtime_tag) { @@ -585,9 +568,8 @@ fn defineUnionAuto( const payload_has_bits = !union_type.has_runtime_tag or union_type.size > enum_tag_ty.abiSize(zcu); const name_cty: CType = .{ .union_auto = ty }; - try w.print("{f} {{ /* {f} */\n", .{ + try w.print("{f} {{\n", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); if (payload_has_bits) { try w.writeByte(' '); @@ -619,9 +601,8 @@ fn defineUnionAuto( tag_cty.fmtDeclaratorSuffix(zcu), }); } - try w.writeAll("};\n"); - - try writeStaticAssertLayout(ty, name_cty, w, zcu); + try w.writeAll("};"); + return name_cty; } fn defineUnionExtern( ty: Type, @@ -629,9 +610,8 @@ fn defineUnionExtern( arena: Allocator, w: *Writer, pt: Zcu.PerThread, -) (Allocator.Error || Writer.Error)!void { +) (Allocator.Error || Writer.Error)!CType { const zcu = pt.zcu; - if (!ty.hasRuntimeBits(zcu)) return; const ip = &zcu.intern_pool; const union_type = ip.loadUnionType(ty.toIntern()); @@ -642,7 +622,7 @@ fn defineUnionExtern( const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.@"extern", zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gt, union_type.alignment)) break true; } else false; @@ -654,7 +634,7 @@ fn defineUnionExtern( false => for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.@"extern", zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gte, union_type.alignment)) break false; } else overalign: { if (union_type.has_runtime_tag) { @@ -668,9 +648,8 @@ fn defineUnionExtern( if (pack) try w.writeAll("zig_packed("); const name_cty: CType = .{ .union_extern = ty }; - try w.print("{f} {{ /* {f} */\n", .{ + try w.print("{f} {{\n", .{ name_cty.fmtTypeName(zcu), - ty.fmt(pt), }); for (0..enum_tag_ty.enumFieldCount(zcu)) |field_index| { @@ -691,9 +670,8 @@ fn defineUnionExtern( } try w.writeByte('}'); if (pack) try w.writeByte(')'); - try w.writeAll(";\n"); - - try writeStaticAssertLayout(ty, name_cty, w, zcu); + try w.writeByte(';'); + return name_cty; } /// Writes an annotation which, placed before a struct/union field declaration with field type `ty`, @@ -704,7 +682,7 @@ fn writeFieldAlign( w: *Writer, zcu: *const Zcu, ) Writer.Error!void { - if (alignment.compareStrict(.lt, ty.defaultStructFieldAlignment(.auto, zcu))) { + if (alignment.compareStrict(.lt, ty.abiAlignment(zcu))) { try w.print("zig_under_align({d}) ", .{alignment.toByteUnits().?}); } else { try w.print("zig_align({d}) ", .{alignment.toByteUnits().?}); @@ -712,19 +690,29 @@ fn writeFieldAlign( } /// Emits static assertions that the size and alignment of `cty` match those of the Zig type `ty`. -fn writeStaticAssertLayout( +pub fn writeStaticAssertTypeLayout( ty: Type, cty: CType, w: *Writer, zcu: *const Zcu, +) Writer.Error!void { + try writeStaticAssertCTypeLayout(cty, ty.abiSize(zcu), ty.abiAlignment(zcu), w, zcu); +} + +/// Emits static assertions that the size and alignment of `cty` match the provided values. +pub fn writeStaticAssertCTypeLayout( + cty: CType, + expected_size: u64, + expected_alignment: Alignment, + w: *Writer, + zcu: *const Zcu, ) Writer.Error!void { try w.print( - \\zig_static_assert(sizeof ({f}) == {d}, "incorrect size"); - \\zig_static_assert(_Alignof ({f}) == {d}, "incorrect alignment"); + \\zig_static_assert(sizeof({f}) == {d} && zig_alignOf({f}) == {d}, "abi mismatch"); \\ , .{ - cty.fmtTypeName(zcu), ty.abiSize(zcu), - cty.fmtTypeName(zcu), ty.abiAlignment(zcu).toByteUnits().?, + cty.fmtTypeName(zcu), expected_size, + cty.fmtTypeName(zcu), expected_alignment.toByteUnits().?, }); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index fc1c494828fc8d8f141be115c54231bcbe38814c..8f3e3917fc0bf0a15dbaa5261dd9dcac9fd4f972 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -263,7 +263,7 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8 => {}, .semver => |ver| if (target.os.tag == .wasi and ver.min.major == 0) { try llvm_triple.print("p{d}", .{ver.min.minor}); - } else { + } else if (target.os.tag != .amdhsa) { try llvm_triple.print("{d}.{d}.{d}", .{ ver.min.major, ver.min.minor, @@ -345,160 +345,6 @@ pub fn supportsTailCall(target: *const std.Target) bool { }; } -pub fn dataLayout(target: *const std.Target) []const u8 { - // These data layouts should match Clang. - return switch (target.cpu.arch) { - .arc => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32", - .xcore => "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32-f64:32-a:0:32-n32", - .hexagon => "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048", - .lanai => "E-m:e-p:32:32-i64:64-a:0:32-n32-S64", - .aarch64 => if (target.ofmt == .macho) - if (target.os.tag == .windows or target.os.tag == .uefi) - "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" - else if (target.abi == .ilp32) - "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" - else - "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" - else if (target.os.tag == .windows or target.os.tag == .uefi) - "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32" - else - "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", - .aarch64_be => "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32", - .arm => if (target.ofmt == .macho) - "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" - else - "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", - .armeb, .thumbeb => if (target.ofmt == .macho) - "E-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" - else - "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", - .thumb => if (target.ofmt == .macho) - "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" - else if (target.os.tag == .windows or target.os.tag == .uefi) - "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" - else - "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", - .avr => "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8", - .bpfeb => "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .bpfel => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .msp430 => "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16", - .mips => "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", - .mipsel => "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", - .mips64 => switch (target.abi) { - .gnuabin32, .muslabin32, .abin32 => "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", - else => "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", - }, - .mips64el => switch (target.abi) { - .gnuabin32, .muslabin32, .abin32 => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", - else => "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", - }, - .m68k => "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16", - .powerpc => "E-m:e-p:32:32-Fn32-i64:64-n32", - .powerpcle => "e-m:e-p:32:32-Fn32-i64:64-n32", - .powerpc64 => switch (target.os.tag) { - .linux => "E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512", - .ps3 => "E-m:e-p:32:32-Fi64-i64:64-i128:128-n32:64", - else => "E-m:e-Fn32-i64:64-i128:128-n32:64", - }, - .powerpc64le => if (target.os.tag == .linux) - "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" - else - "e-m:e-Fn32-i64:64-i128:128-n32:64", - .nvptx => "e-p:32:32-p6:32:32-p7:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64", - .nvptx64 => "e-p6:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64", - .amdgcn => "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9", - .riscv32 => if (target.cpu.has(.riscv, .e)) - "e-m:e-p:32:32-i64:64-n32-S32" - else - "e-m:e-p:32:32-i64:64-n32-S128", - .riscv32be => if (target.cpu.has(.riscv, .e)) - "E-m:e-p:32:32-i64:64-n32-S32" - else - "E-m:e-p:32:32-i64:64-n32-S128", - .riscv64 => if (target.cpu.has(.riscv, .e)) - "e-m:e-p:64:64-i64:64-i128:128-n32:64-S64" - else - "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .riscv64be => if (target.cpu.has(.riscv, .e)) - "E-m:e-p:64:64-i64:64-i128:128-n32:64-S64" - else - "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .sparc => "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64", - .sparc64 => "E-m:e-i64:64-i128:128-n32:64-S128", - .s390x => "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64", - .x86 => if (target.os.tag == .windows or target.os.tag == .uefi) switch (target.abi) { - .gnu => if (target.ofmt == .coff) - "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" - else - "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32", - else => blk: { - const msvc = switch (target.abi) { - .none, .msvc => true, - else => false, - }; - - break :blk if (target.ofmt == .coff) - if (msvc) - "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" - else - "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" - else if (msvc) - "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32" - else - "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32"; - }, - } else if (target.ofmt == .macho) - "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128" - else - "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", - .x86_64 => if (target.os.tag.isDarwin() or target.ofmt == .macho) - "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" - else switch (target.abi) { - .gnux32, .muslx32, .x32 => "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", - else => if ((target.os.tag == .windows or target.os.tag == .uefi) and target.ofmt == .coff) - "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" - else - "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", - }, - .spirv32 => switch (target.os.tag) { - .vulkan, .opengl => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", - else => "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", - }, - .spirv64 => "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1", - .wasm32 => if (target.os.tag == .emscripten) - "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20" - else - "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20", - .wasm64 => if (target.os.tag == .emscripten) - "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20" - else - "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20", - .ve => "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64", - .csky => "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32", - .loongarch32 => "e-m:e-p:32:32-i64:64-n32-S128", - .loongarch64 => "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", - .xtensa => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32", - - .alpha, - .arceb, - .ez80, - .hppa, - .hppa64, - .kalimba, - .kvx, - .m88k, - .microblaze, - .microblazeel, - .or1k, - .propeller, - .sh, - .sheb, - .x86_16, - .xtensaeb, - => unreachable, // Gated by hasLlvmSupport(). - }; -} - // Avoid depending on `bindings.CodeModel` in the bitcode-only case. const CodeModel = enum { default, @@ -573,6 +419,8 @@ pub const Object = struct { val: InternPool.Index, @"addrspace": std.lang.AddressSpace, }, Builder.Variable.Index), + /// Same as `uav_map` but for llvm values not originating from the frontend. + const_map: std.AutoHashMapUnmanaged(Builder.Constant, Builder.Variable.Index), /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction. enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index), /// Serves the same purpose as `enum_tag_name_map` but for the `is_named_enum_value` instruction. @@ -616,8 +464,6 @@ pub const Object = struct { }); errdefer builder.deinit(); - builder.data_layout = try builder.string(dataLayout(target)); - const debug_compile_unit, const debug_enums_fwd_ref, const debug_globals_fwd_ref = if (!builder.strip) debug_info: { // We fully resolve all paths at this point to avoid lack of @@ -653,7 +499,7 @@ pub const Object = struct { }), debug_enums_fwd_ref, debug_globals_fwd_ref, - .{ .optimized = comp.root_mod.optimize_mode != .Debug }, + .{ .optimized = comp.root_mod.optimize_mode != .debug }, ); try builder.addNamedMetadata(try builder.string("llvm.dbg.cu"), &.{debug_compile_unit}); @@ -693,6 +539,7 @@ pub const Object = struct { .zcu = zcu, .nav_map = .empty, .uav_map = .empty, + .const_map = .empty, .enum_tag_name_map = .empty, .named_enum_map = .empty, .type_map = .empty, @@ -703,21 +550,22 @@ pub const Object = struct { return obj; } - pub fn deinit(self: *Object) void { - const gpa = self.gpa; - self.type_pool.deinit(gpa); - self.lazy_abi_aligns.deinit(gpa); - self.debug_enums.deinit(gpa); - self.debug_globals.deinit(gpa); - self.debug_file_map.deinit(gpa); - self.debug_types.deinit(gpa); - self.nav_map.deinit(gpa); - self.uav_map.deinit(gpa); - self.enum_tag_name_map.deinit(gpa); - self.named_enum_map.deinit(gpa); - self.type_map.deinit(gpa); - self.builder.deinit(); - self.* = undefined; + pub fn deinit(o: *Object) void { + const gpa = o.gpa; + o.type_pool.deinit(gpa); + o.lazy_abi_aligns.deinit(gpa); + o.debug_enums.deinit(gpa); + o.debug_globals.deinit(gpa); + o.debug_file_map.deinit(gpa); + o.debug_types.deinit(gpa); + o.nav_map.deinit(gpa); + o.uav_map.deinit(gpa); + o.const_map.deinit(gpa); + o.enum_tag_name_map.deinit(gpa); + o.named_enum_map.deinit(gpa); + o.type_map.deinit(gpa); + o.builder.deinit(); + o.* = undefined; } fn genErrorNameTable(o: *Object) Allocator.Error!void { @@ -741,16 +589,16 @@ pub const Object = struct { for (llvm_errors[1..], error_name_list) |*llvm_error, name| { const name_string = try o.builder.stringNull(name.toSlice(ip)); const name_init = try o.builder.stringConst(name_string); - const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); - try name_variable_index.setInitializer(name_init, &o.builder); - name_variable_index.setMutability(.constant, &o.builder); - name_variable_index.setAlignment(comptime .fromByteUnits(1), &o.builder); - const global_index = name_variable_index.ptrConst(&o.builder).global; - global_index.setLinkage(.private, &o.builder); - global_index.setUnnamedAddr(.unnamed_addr, &o.builder); + const name_llvm_variable = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); + try name_llvm_variable.setInitializer(name_init, &o.builder); + name_llvm_variable.setMutability(.constant, &o.builder); + name_llvm_variable.setAlignment(comptime .fromByteUnits(1), &o.builder); + const llvm_global = name_llvm_variable.ptrConst(&o.builder).global; + llvm_global.setLinkage(.private, &o.builder); + llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{ - name_variable_index.toConst(&o.builder), + name_llvm_variable.toConst(&o.builder), try o.builder.intConst(llvm_usize_ty, name_string.slice(&o.builder).?.len - 1), }); } @@ -770,7 +618,7 @@ pub const Object = struct { b.module_asm.appendSliceAssumeCapacity(assembly); b.module_asm.appendAssumeCapacity('\n'); } - if (b.module_asm.getLast()) |last| { + if (b.module_asm.last()) |last| { if (last != '\n') try b.module_asm.append(gpa, '\n'); } } @@ -1028,7 +876,7 @@ pub const Object = struct { const optimize_mode = comp.root_mod.optimize_mode; - const opt_level: bindings.CodeGenOptLevel = if (optimize_mode == .Debug) + const opt_level: bindings.CodeGenOptLevel = if (optimize_mode == .debug) .None else .Aggressive; @@ -1199,19 +1047,33 @@ pub const Object = struct { global.dll_storage_class = .default; global.unnamed_addr = .unnamed_addr; } - llvm_function.setAlignment(switch (nav.resolved.?.@"align") { - .none => fn_ty.abiAlignment(zcu).toLlvm(), - else => |a| a.toLlvm(), - }, &o.builder); + llvm_function.setAlignment(nav.resolved.?.@"align".toLlvm(), &o.builder); llvm_function.setSection(s: { const section = nav.resolved.?.@"linksection".toSlice(ip) orelse break :s .none; break :s try o.builder.string(section); }, &o.builder); - try o.addLlvmFunctionAttributes(pt, func.owner_nav, llvm_function); - var attributes = try llvm_function.ptrConst(&o.builder).attributes.toWip(&o.builder); + var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); + // Function attributes that are independent of analysis results of the function body. + try o.addCommonFnAttributes( + &attributes, + owner_mod, + // Some backends don't respect the `naked` attribute in `TargetFrameLowering::hasFP()`, + // so for these backends, LLVM will happily emit code that accesses the stack through + // the frame pointer. This is nonsensical since what the `naked` attribute does is + // suppress generation of the prologue and epilogue, and the prologue is where the + // frame pointer normally gets set up. At time of writing, this is the case for at + // least x86 and RISC-V. + owner_mod.omit_frame_pointer or fn_info.cc == .naked, + ); + + try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, if (nav.getExtern(ip)) |@"extern"| .{ + .name = nav.name.toSlice(ip), + .lib_name = @"extern".lib_name.toSlice(ip), + } else null, .fromIntern(fn_info, ip)); + const func_analysis = func.analysisUnordered(ip); if (func_analysis.is_noinline) { try attributes.addFnAttr(.@"noinline", &o.builder); @@ -1299,7 +1161,7 @@ pub const Object = struct { .NoReturn = fn_info.return_type == .noreturn_type, }, .sp_flags = .{ - .Optimized = owner_mod.optimize_mode != .Debug, + .Optimized = owner_mod.optimize_mode != .debug, .Definition = true, .LocalToUnit = is_internal_linkage, }, @@ -1324,7 +1186,7 @@ pub const Object = struct { const counters_variable = try o.builder.addVariable(anon_name, .void, .default); try o.used.append(gpa, counters_variable.toConst(&o.builder)); counters_variable.ptrConst(&o.builder).global.setLinkage(.private, &o.builder); - counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); + counters_variable.setAlignment(comptime .fromByteUnits(1), &o.builder); if (target.ofmt == .macho) { counters_variable.setSection(try o.builder.string("__DATA,__sancov_cntrs"), &o.builder); @@ -1507,10 +1369,6 @@ pub const Object = struct { llvm_global.ptr(&o.builder).unnamed_addr = .unnamed_addr; } - const llvm_align = switch (resolved.@"align") { - .none => nav_ty.abiAlignment(zcu).toLlvm(), - else => |a| a.toLlvm(), - }; const llvm_section: Builder.String = if (resolved.@"linksection".toSlice(ip)) |section| s: { break :s try o.builder.string(section); } else .none; @@ -1519,13 +1377,20 @@ pub const Object = struct { // can see are extern functions or other comptime function body values (e.g. undefined). Of // these, only extern functions need to be lowered to LLVM functions. if (opt_extern != null and nav_ty.zigTypeTag(zcu) == .@"fn" and nav_ty.fnHasRuntimeBits(zcu)) { + const fn_info = zcu.typeToFunc(nav_ty).?; const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) { .function => |function| function, // re-use existing `Builder.Function` .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder), }; - llvm_function.setAlignment(llvm_align, &o.builder); + llvm_function.setAlignment(resolved.@"align".toLlvm(), &o.builder); llvm_function.setSection(llvm_section, &o.builder); - try o.addLlvmFunctionAttributes(pt, nav_id, llvm_function); + var attributes: Builder.FunctionAttributes.Wip = .{}; + defer attributes.deinit(&o.builder); + try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, .{ + .name = nav.name.toSlice(ip), + .lib_name = opt_extern.?.lib_name.toSlice(ip), + }, .fromIntern(fn_info, ip)); + llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder); } else { const file_scope = nav.srcInst(ip).resolveFile(ip); const mod = zcu.fileByIndex(file_scope).mod.?; @@ -1534,7 +1399,10 @@ pub const Object = struct { .variable => |variable| variable, // re-use existing `Builder.Variable` .replaced, .alias, .function => try llvm_global.toNewVariable(&o.builder), }; - llvm_variable.setAlignment(llvm_align, &o.builder); + llvm_variable.setAlignment(switch (resolved.@"align") { + .none => nav_ty.abiAlignment(zcu).toLlvm(), + else => |a| a.toLlvm(), + }, &o.builder); llvm_variable.setSection(llvm_section, &o.builder); llvm_variable.setMutability(if (resolved.@"const") .constant else .global, &o.builder); try llvm_variable.setInitializer(if (opt_extern != null) .no_init else try o.lowerValue(resolved.value, .in_memory), &o.builder); @@ -1585,7 +1453,7 @@ pub const Object = struct { const uav_ty = Value.fromInterned(uav).typeOf(zcu); const uav_ref = try o.lowerUavRef( uav, - uav_ty.abiAlignment(zcu), + uav_ty.abiAlignment(zcu).toLlvm(), target_util.defaultAddressSpace(zcu.getTarget(), .global_constant), ); break :exp .{ uav_ty, uav_ref }; @@ -1599,7 +1467,7 @@ pub const Object = struct { fn updateExportedGlobal( o: *Object, - global_index: Builder.Global.Index, + llvm_global: Builder.Global.Index, ty: Type, export_indices: []const Zcu.Export.Index, ) link.Error!void { @@ -1634,18 +1502,21 @@ pub const Object = struct { // make much sense: the linksection should be associated with the declaration itself rather // than some particular symbol it is exported as! if (export_indices[0].ptr(zcu).opts.section.toSlice(ip)) |section_slice| { - const variable = &global_index.ptrConst(&o.builder).kind.variable; + const variable = &llvm_global.ptrConst(&o.builder).kind.variable; variable.setSection(try o.builder.string(section_slice), &o.builder); } - const llvm_global_ty = global_index.typeOf(&o.builder); + const arch = comp.root_mod.resolved_target.result.cpu.arch; + const workaround_alias_bugs = arch == .amdgcn or arch == .nvptx or arch == .nvptx64; + + const llvm_global_ty = llvm_global.typeOf(&o.builder); // All exports are represented as aliases to the original global. // TODO: we currently do not delete old exports. To do that we'll need to track which // globals actually *are* exports. - for (export_indices) |export_idx| { + for (export_indices, 0..) |export_idx, export_i| { const exp = export_idx.ptr(zcu); const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip)); @@ -1656,13 +1527,23 @@ pub const Object = struct { // The name, aliasee, and type will be set within this block. Other properties of the // alias will be set below. const alias_global: Builder.Global.Index = global: { + + // WORKAROUND (see https://github.com/llvm/llvm-project/issues/213504, https://github.com/llvm/llvm-project/issues/214835) + // For NVPTX, LLVM throws "NVPTX aliasee must be a non-kernel function definition" if we try to alias a kernel + // On AMDGCN, LLVM does not generate an alias for the kernel descriptor symbol on associated functions + // To solve these, we rename the global + if (workaround_alias_bugs and export_i == 0) { + try llvm_global.rename(exp_name, &o.builder); + break :global llvm_global; + } + const existing_global = o.builder.getGlobal(exp_name) orelse { // There is no existing global with this name, so make a new alias. const alias = try o.builder.addAlias( exp_name, llvm_global_ty, - .default, - global_index.toConst(), + llvm_global.ptrConst(&o.builder).addr_space, + llvm_global.toConst(), ); break :global alias.ptrConst(&o.builder).global; }; @@ -1671,8 +1552,9 @@ pub const Object = struct { switch (existing_global.ptrConst(&o.builder).kind) { .alias => |alias| { // We can just repurpose the existing alias. - alias.setAliasee(global_index.toConst(), &o.builder); - alias.ptrConst(&o.builder).global.ptr(&o.builder).type = global_index.typeOf(&o.builder); + alias.setAliasee(llvm_global.toConst(), &o.builder); + alias.ptrConst(&o.builder).global.ptr(&o.builder).type = llvm_global.typeOf(&o.builder); + alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = llvm_global.ptrConst(&o.builder).addr_space; break :global existing_global; }, .variable, .function => { @@ -1682,13 +1564,13 @@ pub const Object = struct { // We need to make a new global which is an alias. Replace this existing one // with the target global, making the name available and fixing references // to this global to point to the target. - try existing_global.replace(global_index, &o.builder); + try existing_global.replace(llvm_global, &o.builder); // The name is now free, so create an alias. const alias = try o.builder.addAlias( exp_name, llvm_global_ty, - .default, - global_index.toConst(), + llvm_global.ptrConst(&o.builder).addr_space, + llvm_global.toConst(), ); break :global alias.ptrConst(&o.builder).global; }, @@ -1721,11 +1603,11 @@ pub const Object = struct { pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void { _ = o.type_map.remove(ty); try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success); - if (o.named_enum_map.get(ty)) |function_index| { - try o.updateIsNamedEnumValueFunction(.fromInterned(ty), function_index); + if (o.named_enum_map.get(ty)) |llvm_function| { + try o.updateIsNamedEnumValueFunction(.fromInterned(ty), llvm_function); } - if (o.enum_tag_name_map.get(ty)) |function_index| { - try o.updateEnumTagNameFunction(.fromInterned(ty), function_index); + if (o.enum_tag_name_map.get(ty)) |llvm_function| { + try o.updateEnumTagNameFunction(.fromInterned(ty), llvm_function); } } @@ -2098,7 +1980,7 @@ pub const Object = struct { payload_offset * 8, ); - return try o.builder.debugStructType( + return o.builder.debugStructType( name, null, // File o.debug_compile_unit.unwrap().?, // Scope @@ -2136,7 +2018,7 @@ pub const Object = struct { defer debug_param_types.deinit(gpa); // Return type goes first. - if (try fnReturnStrat(o, fn_info) == .sret) { + if (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)) == .sret) { // Actual return type is void, then first arg is the sret pointer. const ptr_ty = try pt.singleMutPtrType(.fromInterned(fn_info.return_type)); debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, .void)); @@ -2571,53 +2453,117 @@ pub const Object = struct { fn namespaceToDebugScope(o: *Object, pt: Zcu.PerThread, namespace_index: InternPool.NamespaceIndex) !Builder.Metadata { const zcu = o.zcu; const namespace = zcu.namespacePtr(namespace_index); - if (namespace.parent == .none) return try o.getDebugFile(namespace.file_scope); + if (namespace.parent == .none) return o.getDebugFile(namespace.file_scope); return o.getDebugType(pt, .fromInterned(namespace.owner_type)); } - /// Sets the attributes and callconv of the given `Builder.Function`, which corresponds to the - /// given `Nav` (which is a function). - fn addLlvmFunctionAttributes( + fn addCommonFnAttributes( + o: *Object, + attributes: *Builder.FunctionAttributes.Wip, + owner_mod: *Module, + omit_frame_pointer: bool, + ) Allocator.Error!void { + if (!owner_mod.red_zone) { + try attributes.addFnAttr(.noredzone, &o.builder); + } + if (omit_frame_pointer) { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("frame-pointer"), + .value = try o.builder.string("none"), + } }, &o.builder); + } else { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("frame-pointer"), + .value = try o.builder.string("all"), + } }, &o.builder); + } + try attributes.addFnAttr(.nounwind, &o.builder); + if (owner_mod.unwind_tables != .none) { + try attributes.addFnAttr( + .{ .uwtable = if (owner_mod.unwind_tables == .async) .async else .sync }, + &o.builder, + ); + } + if (owner_mod.optimize_mode == .small) { + try attributes.addFnAttr(.minsize, &o.builder); + try attributes.addFnAttr(.optsize, &o.builder); + } + const target = &owner_mod.resolved_target.result; + if (target.cpu.model.llvm_name) |s| { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("target-cpu"), + .value = try o.builder.string(s), + } }, &o.builder); + } + if (owner_mod.resolved_target.llvm_cpu_features) |s| { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("target-features"), + .value = try o.builder.string(std.mem.span(s)), + } }, &o.builder); + } + if (target.abi.float() == .soft) { + // `use-soft-float` means "use software routines for floating point computations". In + // other words, it configures how LLVM lowers basic float instructions like `fcmp`, + // `fadd`, etc. The float calling convention is configured on `TargetMachine` and is + // mostly an orthogonal concept, although obviously we do need hardware float operations + // to actually be able to pass float values in float registers. + // + // Ideally, we would support something akin to the `-mfloat-abi=softfp` option that GCC + // and Clang support for Arm32 and CSKY. We don't currently expose such an option in + // Zig, and using CPU features as the source of truth for this makes for a miserable + // user experience since people expect e.g. `arm-linux-gnueabi` to mean full soft float + // unless the compiler has explicitly been told otherwise. (And note that our baseline + // CPU models almost all include FPU features!) + // + // Revisit this at some point. + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("use-soft-float"), + .value = try o.builder.string("true"), + } }, &o.builder); + + // This prevents LLVM from using FPU/SIMD code for things like `memcpy`. As for the + // above, this should be revisited if `softfp` support is added. + try attributes.addFnAttr(.noimplicitfloat, &o.builder); + } + } + + pub fn addCallingConventionFnAttributes( o: *Object, pt: Zcu.PerThread, - nav_id: InternPool.Nav.Index, - function_index: Builder.Function.Index, + llvm_function: Builder.Function.Index, + attributes: *Builder.FunctionAttributes.Wip, + opt_extern: ?struct { + name: []const u8, + lib_name: ?[]const u8 = null, + }, + fn_info: FuncInfo, ) Allocator.Error!void { const zcu = o.zcu; - const ip = &zcu.intern_pool; - const nav = ip.getNav(nav_id); - const owner_mod = zcu.navFileScope(nav_id).mod.?; - const ty: Type = .fromInterned(nav.resolved.?.type); - - const fn_info = zcu.typeToFunc(ty).?; - const target = &owner_mod.resolved_target.result; - - var attributes: Builder.FunctionAttributes.Wip = .{}; - defer attributes.deinit(&o.builder); - - if (target.cpu.arch.isWasm()) if (nav.getExtern(ip)) |@"extern"| { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("wasm-import-name"), - .value = try o.builder.string(nav.name.toSlice(ip)), - } }, &o.builder); - if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| { - if (!std.mem.eql(u8, lib_name_slice, "c")) try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("wasm-import-module"), - .value = try o.builder.string(lib_name_slice), - } }, &o.builder); - } - }; + const target = zcu.getTarget(); if (fn_info.cc == .async) { @panic("TODO: LLVM backend lower async function"); } + if (target.cpu.arch.isWasm()) if (opt_extern) |@"extern"| { + try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("wasm-import-name"), + .value = try o.builder.string(@"extern".name), + } }, &o.builder); + if (@"extern".lib_name) |lib_name| { + if (!std.mem.eql(u8, lib_name, "c")) try attributes.addFnAttr(.{ .string = .{ + .kind = try o.builder.string("wasm-import-module"), + .value = try o.builder.string(lib_name), + } }, &o.builder); + } + }; + const cc_info = toLlvmCallConv(fn_info.cc, target).?; - function_index.setCallConv(cc_info.llvm_cc, &o.builder); + llvm_function.setCallConv(cc_info.llvm_cc, &o.builder); if (cc_info.align_stack) { - try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder); + try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("stackrealign"), .value = .empty } }, &o.builder); } if (cc_info.naked) { @@ -2668,29 +2614,16 @@ pub const Object = struct { else => {}, } - // Function attributes that are independent of analysis results of the function body. - try o.addCommonFnAttributes( - &attributes, - owner_mod, - // Some backends don't respect the `naked` attribute in `TargetFrameLowering::hasFP()`, - // so for these backends, LLVM will happily emit code that accesses the stack through - // the frame pointer. This is nonsensical since what the `naked` attribute does is - // suppress generation of the prologue and epilogue, and the prologue is where the - // frame pointer normally gets set up. At time of writing, this is the case for at - // least x86 and RISC-V. - owner_mod.omit_frame_pointer or fn_info.cc == .naked, - ); - if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder); - var it = iterateParamTypes(o, fn_info); - if (try fnReturnStrat(o, fn_info) == .sret) { - // Sret pointers must not be address 0 - try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder); - try attributes.addParamAttr(it.llvm_index, .@"noalias", &o.builder); - - const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type), .in_memory); - try attributes.addParamAttr(it.llvm_index, .{ .sret = raw_llvm_ret_ty }, &o.builder); + var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types); + if (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)) == .sret) { + try o.addSRetFnAttributes( + attributes, + try o.lowerType(.fromInterned(fn_info.return_type), .in_memory), + Type.fromInterned(fn_info.return_type).abiAlignment(zcu).toLlvm(), + .declaration, + ); it.llvm_index += 1; } else if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { .signed => try attributes.addRetAttr(.signext, &o.builder), @@ -2709,9 +2642,9 @@ pub const Object = struct { while (try it.next()) |lowering| switch (lowering) { .byval => { const param_index = it.zig_index - 1; - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[param_index]); + const param_ty: Type = .fromInterned(fn_info.param_types[param_index]); if (!isByRef(param_ty, zcu)) { - try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1); + try o.addByValParamAttrs(pt, attributes, param_ty, param_index, fn_info, it.llvm_index - 1); } if (remaining_inreg_int > 0 and @@ -2730,12 +2663,12 @@ pub const Object = struct { } }, .byref => { - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, it.byval_attr, param_ty); + const param_ty: Type = .fromInterned(fn_info.param_types[it.zig_index - 1]); + try o.addByRefParamAttrs(attributes, it.llvm_index - 1, it.byval_attr, param_ty); }, .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), .slice => { - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); + const param_ty: Type = .fromInterned(fn_info.param_types[it.zig_index - 1]); const ptr_info = param_ty.ptrInfo(zcu); const llvm_ptr_index = it.llvm_index - 2; if (std.math.cast(u5, it.zig_index - 1)) |i| { @@ -2767,94 +2700,205 @@ pub const Object = struct { .i64_array, => continue, }; - - function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); } - fn addCommonFnAttributes( + pub fn addSRetFnAttributes( o: *Object, attributes: *Builder.FunctionAttributes.Wip, - owner_mod: *Module, - omit_frame_pointer: bool, + ret_ty: Builder.Type, + ret_align: Builder.Alignment, + location: enum { declaration, callsite }, ) Allocator.Error!void { - if (!owner_mod.red_zone) { - try attributes.addFnAttr(.noredzone, &o.builder); - } - if (omit_frame_pointer) { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("frame-pointer"), - .value = try o.builder.string("none"), - } }, &o.builder); - } else { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("frame-pointer"), - .value = try o.builder.string("all"), - } }, &o.builder); - } - try attributes.addFnAttr(.nounwind, &o.builder); - if (owner_mod.unwind_tables != .none) { - try attributes.addFnAttr( - .{ .uwtable = if (owner_mod.unwind_tables == .async) .async else .sync }, - &o.builder, - ); - } - if (owner_mod.optimize_mode == .ReleaseSmall) { - try attributes.addFnAttr(.minsize, &o.builder); - try attributes.addFnAttr(.optsize, &o.builder); - } - const target = &owner_mod.resolved_target.result; - if (target.cpu.model.llvm_name) |s| { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("target-cpu"), - .value = try o.builder.string(s), - } }, &o.builder); - } - if (owner_mod.resolved_target.llvm_cpu_features) |s| { - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("target-features"), - .value = try o.builder.string(std.mem.span(s)), - } }, &o.builder); - } - if (target.abi.float() == .soft) { - // `use-soft-float` means "use software routines for floating point computations". In - // other words, it configures how LLVM lowers basic float instructions like `fcmp`, - // `fadd`, etc. The float calling convention is configured on `TargetMachine` and is - // mostly an orthogonal concept, although obviously we do need hardware float operations - // to actually be able to pass float values in float registers. - // - // Ideally, we would support something akin to the `-mfloat-abi=softfp` option that GCC - // and Clang support for Arm32 and CSKY. We don't currently expose such an option in - // Zig, and using CPU features as the source of truth for this makes for a miserable - // user experience since people expect e.g. `arm-linux-gnueabi` to mean full soft float - // unless the compiler has explicitly been told otherwise. (And note that our baseline - // CPU models almost all include FPU features!) - // - // Revisit this at some point. - try attributes.addFnAttr(.{ .string = .{ - .kind = try o.builder.string("use-soft-float"), - .value = try o.builder.string("true"), - } }, &o.builder); - - // This prevents LLVM from using FPU/SIMD code for things like `memcpy`. As for the - // above, this should be revisited if `softfp` support is added. - try attributes.addFnAttr(.noimplicitfloat, &o.builder); - } + try attributes.addParamAttr(0, .dead_on_unwind, &o.builder); + switch (location) { + .declaration => try attributes.addParamAttr(0, .@"noalias", &o.builder), + .callsite => {}, + } + try attributes.addParamAttr(0, .writeonly, &o.builder); + try attributes.addParamAttr(0, .{ .captures = .none }, &o.builder); + try attributes.addParamAttr(0, .{ .sret = ret_ty }, &o.builder); + try attributes.addParamAttr(0, .{ .@"align" = .wrap(ret_align) }, &o.builder); } pub const TypeRepr = enum { /// The representation of the type when it is being manipulated as a value in a function. - /// e.g. Zig `u5` -> LLVM `i5` - by_value, - /// The representation of the type when it is stored in memory. - /// e.g. Zig `u5` -> LLVM `i8` + /// e.g. Zig `u90` -> LLVM `i90` + as_value, + /// The representation of the type when it is loaded from or stored to memory. + /// e.g. Zig `u90` -> LLVM `i96` + memory_access, + /// The representation of the type when it is in memory. + /// e.g. Zig `u90` -> LLVM `[12 x i8]` in_memory, }; + pub fn intType(o: *Object, bits: u16, repr: TypeRepr) Allocator.Error!Builder.Type { + switch (repr) { + .as_value => return o.builder.intType(bits), + .memory_access, .in_memory => {}, + } + const target = o.zcu.getTarget(); + const abi_size = std.zig.target.intByteSize(target, bits); + const llvm_bit_width = @as(u20, 8) * abi_size; + switch (repr) { + .as_value => unreachable, + .memory_access => {}, + .in_memory => { + const zig_align = std.zig.target.intAlignment(target, bits); + const llvm_align = o.builder.data_layout.getIntegerSpec(llvm_bit_width).abi_align; + if (zig_align < llvm_align.toByteUnits().?) return o.builder.arrayType(abi_size, .i8); + }, + } + return o.builder.intType(llvm_bit_width); + } + pub fn errorIntType(o: *Object, repr: TypeRepr) Allocator.Error!Builder.Type { - return o.builder.intType(switch (repr) { - .by_value => o.zcu.errorSetBits(), - .in_memory => @intCast(Type.anyerror.abiSize(o.zcu) * 8), - }); + return o.intType(o.zcu.errorSetBits(), repr); + } + + pub const SoftF80Layout = struct { + alignment: InternPool.Alignment, + /// byte offset of u64 field + mantissa_offset: u64, + /// byte offset of u16 field + exponent_offset: u64, + llvm_fields_len: u32, + + pub const LlvmFieldTag = enum { mantissa, exponent, padding }; + }; + pub fn softF80Layout(o: *Object, opts: struct { + llvm_field_tags_buf: []SoftF80Layout.LlvmFieldTag = &.{}, + llvm_field_types_buf: []Builder.Type = &.{}, + }) Allocator.Error!SoftF80Layout { + const zcu = o.zcu; + const target = zcu.getTarget(); + assert(std.zig.target.compilerRtFloatAbi(target, 80) == .soft); + // Current compiler rt soft abi, which is not yet affected by endianness for simplicity: + // + // typedef struct { uint64_t mantissa; uint16_t exponent; } f80; + // + var layout: SoftF80Layout = .{ + .alignment = Type.f80.abiAlignment(zcu), + .mantissa_offset = undefined, + .exponent_offset = undefined, + .llvm_fields_len = 0, + }; + var offset: u64 = 0; + for ([2]SoftF80Layout.LlvmFieldTag{ .mantissa, .exponent }, [2]Type{ .u64, .u16 }) |field_tag, field_type| { + const field_align = field_type.abiAlignment(zcu); + assert(field_align.compareStrict(.lte, layout.alignment)); + const field_offset = field_align.forward(offset); + switch (field_offset - offset) { + 0 => {}, + else => |padding| { + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8); + layout.llvm_fields_len += 1; + }, + } + switch (field_tag) { + .mantissa => layout.mantissa_offset = field_offset, + .exponent => layout.exponent_offset = field_offset, + .padding => unreachable, + } + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = field_tag; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.lowerType(field_type, .in_memory); + layout.llvm_fields_len += 1; + offset = field_offset + field_type.abiSize(zcu); + } + const end = layout.alignment.forward(offset); + assert(end == Type.f80.abiSize(zcu)); + switch (end - offset) { + 0 => {}, + else => |padding| { + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8); + layout.llvm_fields_len += 1; + }, + } + return layout; + } + + pub const SoftF128Layout = struct { + alignment: InternPool.Alignment, + /// byte offset of u64 field + lo_offset: u64, + /// byte offset of u64 field + hi_offset: u64, + llvm_fields_len: u32, + + pub const LlvmFieldTag = enum { lo, hi, padding }; + }; + pub fn softF128Layout(o: *Object, opts: struct { + llvm_field_tags_buf: []SoftF128Layout.LlvmFieldTag = &.{}, + llvm_field_types_buf: []Builder.Type = &.{}, + }) Allocator.Error!SoftF128Layout { + const zcu = o.zcu; + const target = zcu.getTarget(); + assert(std.zig.target.compilerRtFloatAbi(target, 128) == .soft); + // Current compiler rt soft abi: + // + // #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + // typedef struct { uint64_t hi, lo; } f128; + // #else + // typedef struct { uint64_t lo, hi; } f128; + // #endif + // + var layout: SoftF128Layout = .{ + .alignment = Type.f128.abiAlignment(zcu), + .lo_offset = undefined, + .hi_offset = undefined, + .llvm_fields_len = 0, + }; + var offset: u64 = 0; + for (@as([2]SoftF128Layout.LlvmFieldTag, switch (target.cpu.arch.endian()) { + .big => .{ .hi, .lo }, + .little => .{ .lo, .hi }, + }), [2]Type{ .u64, .u64 }) |field_tag, field_type| { + const field_align = field_type.abiAlignment(zcu); + assert(field_align.compareStrict(.lte, layout.alignment)); + const field_offset = field_align.forward(offset); + switch (field_offset - offset) { + 0 => {}, + else => |padding| { + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8); + layout.llvm_fields_len += 1; + }, + } + switch (field_tag) { + .lo => layout.lo_offset = field_offset, + .hi => layout.hi_offset = field_offset, + .padding => unreachable, + } + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = field_tag; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.lowerType(field_type, .in_memory); + layout.llvm_fields_len += 1; + offset = field_offset + field_type.abiSize(zcu); + } + const end = layout.alignment.forward(offset); + assert(end == Type.f128.abiSize(zcu)); + switch (end - offset) { + 0 => {}, + else => |padding| { + if (layout.llvm_fields_len < opts.llvm_field_tags_buf.len) + opts.llvm_field_tags_buf[layout.llvm_fields_len] = .padding; + if (layout.llvm_fields_len < opts.llvm_field_types_buf.len) + opts.llvm_field_types_buf[layout.llvm_fields_len] = try o.builder.arrayType(padding, .i8); + layout.llvm_fields_len += 1; + }, + } + return layout; } pub fn lowerType(o: *Object, t: Type, repr: TypeRepr) Allocator.Error!Builder.Type { @@ -2862,42 +2906,31 @@ pub const Object = struct { const target = zcu.getTarget(); const ip = &zcu.intern_pool; - if (repr == .by_value) { - assert(!isByRef(t, zcu)); // by-ref types must only be manipulated in memory + switch (repr) { + .as_value => assert(!isByRef(t, zcu)), // by-ref types must only be manipulated in memory + .memory_access, .in_memory => {}, } return switch (t.toIntern()) { .u0_type => unreachable, // no runtime bits - inline .u1_type, - .u8_type, - .i8_type, - .u16_type, - .i16_type, - .u29_type, - .u32_type, - .i32_type, - .u64_type, - .i64_type, - .u80_type, - .u128_type, - .i128_type, - => |tag| switch (repr) { - .by_value => @field(Builder.Type, "i" ++ @tagName(tag)[1 .. @tagName(tag).len - "_type".len]), - .in_memory => try o.builder.intType(@intCast(t.abiSize(zcu) * 8)), - }, - .usize_type, .isize_type => try o.builder.intType(target.ptrBitWidth()), - inline .c_char_type, - .c_short_type, - .c_ushort_type, - .c_int_type, - .c_uint_type, - .c_long_type, - .c_ulong_type, - .c_longlong_type, - .c_ulonglong_type, - => |tag| try o.builder.intType(target.cTypeBitSize( - @field(std.Target.CType, @tagName(tag)["c_".len .. @tagName(tag).len - "_type".len]), - )), + .u1_type, .bool_type => try o.intType(1, repr), + .u8_type, .i8_type => try o.intType(8, repr), + .u16_type, .i16_type => try o.intType(16, repr), + .u29_type => try o.intType(29, repr), + .u32_type, .i32_type => try o.intType(32, repr), + .u64_type, .i64_type => try o.intType(64, repr), + .u80_type => try o.intType(80, repr), + .u128_type, .i128_type => try o.intType(128, repr), + .usize_type, .isize_type => try o.intType(target.ptrBitWidth(), repr), + .c_char_type => try o.intType(target.cTypeBitSize(.char).?, repr), + .c_short_type => try o.intType(target.cTypeBitSize(.short).?, repr), + .c_ushort_type => try o.intType(target.cTypeBitSize(.ushort).?, repr), + .c_int_type => try o.intType(target.cTypeBitSize(.int).?, repr), + .c_uint_type => try o.intType(target.cTypeBitSize(.uint).?, repr), + .c_long_type => try o.intType(target.cTypeBitSize(.long).?, repr), + .c_ulong_type => try o.intType(target.cTypeBitSize(.ulong).?, repr), + .c_longlong_type => try o.intType(target.cTypeBitSize(.longlong).?, repr), + .c_ulonglong_type => try o.intType(target.cTypeBitSize(.ulonglong).?, repr), .c_longdouble_type, .f16_type, .f32_type, @@ -2905,11 +2938,44 @@ pub const Object = struct { .f80_type, .f128_type, => switch (t.floatBits(target)) { - 16 => if (backendSupportsF16(target)) .half else .i16, - 32 => .float, - 64 => .double, - 80 => if (backendSupportsF80(target)) .x86_fp80 else .i80, - 128 => .fp128, + 16 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .half, + .soft => .i16, + }, + 32 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .float, + .soft => .i32, + }, + 64 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .double, + .soft => .i64, + }, + 80 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .x86_fp80, + .soft => { + var llvm_field_types_buf: [5]Builder.Type = undefined; + const f80_layout = try o.softF80Layout(.{ + .llvm_field_types_buf = &llvm_field_types_buf, + }); + return o.builder.structType( + .normal, + llvm_field_types_buf[0..f80_layout.llvm_fields_len], + ); + }, + }, + 128 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => .fp128, + .soft => { + var llvm_field_types_buf: [5]Builder.Type = undefined; + const f128_layout = try o.softF128Layout(.{ + .llvm_field_types_buf = &llvm_field_types_buf, + }); + return o.builder.structType( + .normal, + llvm_field_types_buf[0..f128_layout.llvm_fields_len], + ); + }, + }, else => unreachable, }, .anyopaque_type => { @@ -2918,7 +2984,6 @@ pub const Object = struct { // @foo = external global i8 return .i8; }, - .bool_type => .i1, .anyerror_type => try o.errorIntType(repr), .void_type => unreachable, // no runtime bits .type_type => unreachable, // no runtime bits @@ -2968,10 +3033,7 @@ pub const Object = struct { .none, => unreachable, else => switch (ip.indexToKey(t.toIntern())) { - .int_type => |int_type| switch (repr) { - .by_value => try o.builder.intType(int_type.bits), - .in_memory => try o.builder.intType(@intCast(t.abiSize(zcu) * 8)), - }, + .int_type => |int_type| o.intType(int_type.bits, repr), .ptr_type => |ptr_type| type: { const ptr_ty = try o.builder.ptrType( toLlvmAddressSpace(ptr_type.flags.address_space, target), @@ -2988,11 +3050,13 @@ pub const Object = struct { array_type.lenIncludingSentinel(), try o.lowerType(.fromInterned(array_type.child), repr), ), - .vector_type => |vector_type| o.builder.vectorType( - .normal, - vector_type.len, - try o.lowerType(.fromInterned(vector_type.child), .by_value), - ), + .vector_type => |vector_type| if (isByRef(t, zcu)) { + const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), repr); + return o.builder.arrayType(vector_type.len, child_llvm_ty); + } else { + const child_llvm_ty = try o.lowerType(.fromInterned(vector_type.child), .as_value); + return o.builder.vectorType(.normal, vector_type.len, child_llvm_ty); + }, .opt_type => |child_ty| { // Must stay in sync with `opt_payload` logic in `lowerPtr`. switch (Type.fromInterned(child_ty).classify(zcu)) { @@ -3252,8 +3316,11 @@ pub const Object = struct { return ty; }, .opaque_type, .spirv_type => unreachable, // no runtime bits - .enum_type => try o.lowerType(t.backingIntType(zcu), repr), - .func_type => |func_type| try o.lowerFnType(t, func_type), + .enum_type => try o.intType(t.backingIntType(zcu).intInfo(zcu).bits, repr), + .func_type => |func_type| { + assert(t.fnHasRuntimeBits(zcu)); + return o.lowerFnType(.fromIntern(func_type, ip)); + }, .error_set_type, .inferred_error_set_type => try o.errorIntType(repr), // values, not types .undef, @@ -3279,14 +3346,28 @@ pub const Object = struct { }; } - fn lowerFnType(o: *Object, fn_ty: Type, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { + pub const FuncInfo = struct { + cc: std.lang.CallingConvention, + noalias_bits: u32 = 0, + param_types: []const InternPool.Index, + return_type: InternPool.Index = .void_type, + is_var_args: bool = false, + + pub fn fromIntern(fn_info: InternPool.Key.FuncType, ip: *InternPool) FuncInfo { + return .{ + .cc = fn_info.cc, + .noalias_bits = fn_info.noalias_bits, + .param_types = fn_info.param_types.get(ip), + .return_type = fn_info.return_type, + .is_var_args = fn_info.is_var_args, + }; + } + }; + pub fn lowerFnType(o: *Object, fn_info: FuncInfo) Allocator.Error!Builder.Type { const zcu = o.zcu; - const ip = &zcu.intern_pool; const target = zcu.getTarget(); - assert(fn_ty.fnHasRuntimeBits(zcu)); - - const ret_strat = try fnReturnStrat(o, fn_info); + const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)); var llvm_params: std.ArrayList(Builder.Type) = .empty; defer llvm_params.deinit(o.gpa); @@ -3301,35 +3382,35 @@ pub const Object = struct { try llvm_params.append(o.gpa, llvm_ptr_ty); } - var it = iterateParamTypes(o, fn_info); + var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types); while (try it.next()) |lowering| switch (lowering) { .no_bits => continue, .byval => { - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .in_memory else .by_value)); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); + try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .memory_access else .as_value)); }, .byref, .byref_mut => { try llvm_params.append(o.gpa, .ptr); }, .abi_sized_int => { - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); try llvm_params.append(o.gpa, try o.builder.intType( @intCast(param_ty.abiSize(zcu) * 8), )); }, .slice => { - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); try llvm_params.appendSlice(o.gpa, &.{ try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(zcu), target)), - try o.lowerType(.usize, .by_value), + try o.lowerType(.usize, .as_value), }); }, .multiple_llvm_types => { try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]); }, .float_array => |count| { - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .in_memory); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); + const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .memory_access); try llvm_params.append(o.gpa, try o.builder.arrayType(count, float_ty)); }, .i32_array, .i64_array => |arr_len| { @@ -3343,7 +3424,7 @@ pub const Object = struct { const llvm_ret_ty: Builder.Type = switch (ret_strat) { .void, .sret => .void, - .by_val => try o.lowerType(.fromInterned(fn_info.return_type), .by_value), + .by_val => try o.lowerType(.fromInterned(fn_info.return_type), .as_value), .mem_cast => |llvm_ret_ty| llvm_ret_ty, }; const llvm_fn_kind: Builder.Type.Function.Kind = switch (fn_info.is_var_args) { @@ -3391,8 +3472,14 @@ pub const Object = struct { .null => unreachable, // non-runtime value .@"unreachable" => unreachable, // non-runtime value - .false => .false, - .true => .true, + .false => switch (repr) { + .as_value => .false, + .in_memory, .memory_access => try o.builder.intConst(.i8, 0), + }, + .true => switch (repr) { + .as_value => .true, + .in_memory, .memory_access => try o.builder.intConst(.i8, 1), + }, }, .enum_literal => unreachable, // non-runtime value .@"extern" => unreachable, // non-runtime value @@ -3401,7 +3488,12 @@ pub const Object = struct { var bigint_space: Value.BigIntSpace = undefined; const bigint = val.toBigInt(&bigint_space, zcu); const llvm_int_ty = try o.lowerType(ty, repr); - return o.builder.bigIntConst(llvm_int_ty, bigint); + if (llvm_int_ty.isInteger(&o.builder)) + return o.builder.bigIntConst(llvm_int_ty, bigint); + const buffer = try o.gpa.alloc(u8, llvm_int_ty.aggregateLen(&o.builder)); + defer o.gpa.free(buffer); + bigint.writeTwosComplement(buffer, target.cpu.arch.endian()); + return o.builder.stringConst(try o.builder.string(buffer)); }, .err => |err| { const int = zcu.intern_pool.getErrorValueIfExists(err.name).?; @@ -3456,18 +3548,12 @@ pub const Object = struct { }, .enum_tag => |enum_tag| o.lowerValue(enum_tag.int, repr), .float => switch (ty.floatBits(target)) { - 16 => if (backendSupportsF16(target)) - try o.builder.halfConst(val.toFloat(f16, zcu)) - else - try o.builder.intConst(.i16, @as(i16, @bitCast(val.toFloat(f16, zcu)))), - 32 => try o.builder.floatConst(val.toFloat(f32, zcu)), - 64 => try o.builder.doubleConst(val.toFloat(f64, zcu)), - 80 => if (backendSupportsF80(target)) - try o.builder.x86_fp80Const(val.toFloat(f80, zcu)) - else - try o.builder.intConst(.i80, @as(i80, @bitCast(val.toFloat(f80, zcu)))), - 128 => try o.builder.fp128Const(val.toFloat(f128, zcu)), else => unreachable, + 16 => try o.f16Const(val.toFloat(f16, zcu)), + 32 => try o.f32Const(val.toFloat(f32, zcu)), + 64 => try o.f64Const(val.toFloat(f64, zcu)), + 80 => try o.f80Const(val.toFloat(f80, zcu)), + 128 => try o.f128Const(val.toFloat(f128, zcu)), }, .ptr => try o.lowerPtr(arg_val, 0), .slice => |slice| return o.builder.structConst(try o.lowerType(ty, repr), &.{ @@ -3586,12 +3672,13 @@ pub const Object = struct { }, .vector_type => |vector_type| { const vector_ty = try o.lowerType(ty, repr); + const ExpectedContents = [Builder.expected_fields_len]Builder.Constant; + var bfa_buf: ExpectedContents = undefined; + var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa); + const allocator = bfa.allocator(); + const is_by_ref = isByRef(ty, zcu); switch (aggregate.storage) { .bytes, .elems => { - const ExpectedContents = [Builder.expected_fields_len]Builder.Constant; - var bfa_buf: ExpectedContents = undefined; - var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), o.gpa); - const allocator = bfa.allocator(); const vals = try allocator.alloc(Builder.Constant, vector_type.len); defer allocator.free(vals); @@ -3600,16 +3687,21 @@ pub const Object = struct { result_val.* = try o.builder.intConst(.i8, byte); }, .elems => |elems| for (vals, elems) |*result_val, elem| { - result_val.* = try o.lowerValue(elem, .by_value); + result_val.* = try o.lowerValue(elem, if (is_by_ref) repr else .as_value); }, .repeated_elem => unreachable, } - return o.builder.vectorConst(vector_ty, vals); + return if (is_by_ref) + o.builder.arrayConst(vector_ty, vals) + else + o.builder.vectorConst(vector_ty, vals); }, - .repeated_elem => |elem| return o.builder.splatConst( - vector_ty, - try o.lowerValue(elem, .by_value), - ), + .repeated_elem => |elem| if (is_by_ref) { + const vals = try allocator.alloc(Builder.Constant, vector_type.len); + defer allocator.free(vals); + @memset(vals, try o.lowerValue(elem, repr)); + return o.builder.arrayConst(vector_ty, vals); + } else return o.builder.splatConst(vector_ty, try o.lowerValue(elem, .as_value)), } }, .tuple_type => |tuple| { @@ -3837,6 +3929,117 @@ pub const Object = struct { }; } + pub fn f16Const(o: *Object, val: f16) Allocator.Error!Builder.Constant { + return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 16)) { + .hard => o.builder.halfConst(val), + .soft => o.builder.intConst(.i16, @as(u16, @bitCast(val))), + }; + } + + pub fn f32Const(o: *Object, val: f32) Allocator.Error!Builder.Constant { + return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 32)) { + .hard => o.builder.floatConst(val), + .soft => o.builder.intConst(.i32, @as(u32, @bitCast(val))), + }; + } + + pub fn f64Const(o: *Object, val: f64) Allocator.Error!Builder.Constant { + return switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 64)) { + .hard => o.builder.doubleConst(val), + .soft => o.builder.intConst(.i64, @as(u64, @bitCast(val))), + }; + } + + pub fn f80Const(o: *Object, val: f80) Allocator.Error!Builder.Constant { + switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 80)) { + .hard => return o.builder.x86_fp80Const(val), + .soft => {}, + } + var llvm_field_tags_buf: [5]SoftF80Layout.LlvmFieldTag = undefined; + var llvm_field_types_buf: [5]Builder.Type = undefined; + const f80_layout = try o.softF80Layout(.{ + .llvm_field_tags_buf = &llvm_field_tags_buf, + .llvm_field_types_buf = &llvm_field_types_buf, + }); + const llvm_field_types = llvm_field_types_buf[0..f80_layout.llvm_fields_len]; + const f80_llvm_ty = try o.builder.structType(.normal, llvm_field_types); + const f80_repr: packed struct { mantissa: u64, exponent: u16 } = @bitCast(val); + var llvm_field_vals_buf: [5]Builder.Constant = undefined; + const llvm_field_vals = llvm_field_vals_buf[0..f80_layout.llvm_fields_len]; + for ( + llvm_field_vals, + llvm_field_tags_buf[0..f80_layout.llvm_fields_len], + llvm_field_types, + ) |*llvm_field_val, llvm_field_tag, llvm_field_type| + llvm_field_val.* = switch (llvm_field_tag) { + .mantissa => try o.builder.intConst(llvm_field_type, f80_repr.mantissa), + .exponent => try o.builder.intConst(llvm_field_type, f80_repr.exponent), + .padding => try o.builder.undefConst(llvm_field_type), + }; + return o.builder.structConst(f80_llvm_ty, llvm_field_vals); + } + + pub fn f128Const(o: *Object, val: f128) Allocator.Error!Builder.Constant { + switch (std.zig.target.compilerRtFloatAbi(o.zcu.getTarget(), 128)) { + .hard => return o.builder.fp128Const(val), + .soft => {}, + } + var llvm_field_tags_buf: [5]SoftF128Layout.LlvmFieldTag = undefined; + var llvm_field_types_buf: [5]Builder.Type = undefined; + const f128_layout = try o.softF128Layout(.{ + .llvm_field_tags_buf = &llvm_field_tags_buf, + .llvm_field_types_buf = &llvm_field_types_buf, + }); + const llvm_field_types = llvm_field_types_buf[0..f128_layout.llvm_fields_len]; + const f128_llvm_ty = try o.builder.structType(.normal, llvm_field_types); + const f128_repr: packed struct { lo: u64, hi: u64 } = @bitCast(val); + var llvm_field_vals_buf: [5]Builder.Constant = undefined; + const llvm_field_vals = llvm_field_vals_buf[0..f128_layout.llvm_fields_len]; + for ( + llvm_field_vals, + llvm_field_tags_buf[0..f128_layout.llvm_fields_len], + llvm_field_types, + ) |*llvm_field_val, llvm_field_tag, llvm_field_type| + llvm_field_val.* = switch (llvm_field_tag) { + .lo => try o.builder.intConst(llvm_field_type, f128_repr.lo), + .hi => try o.builder.intConst(llvm_field_type, f128_repr.hi), + .padding => try o.builder.undefConst(llvm_field_type), + }; + return o.builder.structConst(f128_llvm_ty, llvm_field_vals); + } + + pub fn lowerConstRef( + o: *Object, + constant: Builder.Constant, + @"align": Builder.Alignment, + ) Allocator.Error!Builder.Constant { + assert(@"align" != .default); + const zcu = o.zcu; + const gpa = zcu.comp.gpa; + const gop = try o.const_map.getOrPut(gpa, constant); + if (gop.found_existing) { + // Keep the greater of the two alignments. + const llvm_variable = gop.value_ptr.*; + const llvm_old_align = llvm_variable.getAlignment(&o.builder); + const llvm_new_align = llvm_old_align.max(@"align"); + llvm_variable.setAlignment(llvm_new_align, &o.builder); + return llvm_variable.ptrConst(&o.builder).global.toConst(); + } + errdefer assert(o.const_map.remove(constant)); + + const llvm_ty = constant.typeOf(&o.builder); + const llvm_addrspace = toLlvmAddressSpace(.generic, zcu.getTarget()); + const llvm_variable = try o.builder.addVariable(.empty, llvm_ty, llvm_addrspace); + gop.value_ptr.* = llvm_variable; + try llvm_variable.setInitializer(constant, &o.builder); + llvm_variable.setMutability(.constant, &o.builder); + llvm_variable.setAlignment(@"align", &o.builder); + const llvm_global = llvm_variable.ptrConst(&o.builder).global; + llvm_global.setLinkage(.private, &o.builder); + llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); + return llvm_global.toConst(); + } + fn lowerPtr( o: *Object, ptr_val: InternPool.Index, @@ -3856,7 +4059,7 @@ pub const Object = struct { const orig_ptr_ty: Type = .fromInterned(uav.orig_ty); const base_ptr = try o.lowerUavRef( uav.val, - orig_ptr_ty.ptrAlignment(zcu), + orig_ptr_ty.ptrAlignment(zcu).toLlvm(), orig_ptr_ty.ptrAddressSpace(zcu), ); return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{ @@ -3865,8 +4068,8 @@ pub const Object = struct { }, .int => try o.builder.castConst( .inttoptr, - try o.builder.intConst(try o.lowerType(.usize, .by_value), offset), - try o.lowerType(.fromInterned(ptr.ty), .by_value), + try o.builder.intConst(try o.lowerType(.usize, .as_value), offset), + try o.lowerType(.fromInterned(ptr.ty), .as_value), ), .eu_payload => |eu_ptr| try o.lowerPtr( eu_ptr, @@ -3908,12 +4111,12 @@ pub const Object = struct { pub fn lowerPtrToVoid( o: *Object, - /// Must not be `.none`. - @"align": InternPool.Alignment, + /// Must not be `.default`. + @"align": Builder.Alignment, @"addrspace": std.lang.AddressSpace, ) Allocator.Error!Builder.Constant { const addr: u64 = @"align".toByteUnits().?; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const llvm_addr = try o.builder.intConst(llvm_usize, addr); const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(@"addrspace", o.zcu.getTarget())); return o.builder.castConst(.inttoptr, llvm_addr, llvm_ptr_ty); @@ -3922,11 +4125,11 @@ pub const Object = struct { pub fn lowerUavRef( o: *Object, uav_val: InternPool.Index, - /// Must not be `.none`. - @"align": InternPool.Alignment, + /// Must not be `.default`. + @"align": Builder.Alignment, @"addrspace": std.lang.AddressSpace, ) Allocator.Error!Builder.Constant { - assert(@"align" != .none); + assert(@"align" != .default); const zcu = o.zcu; const ip = &zcu.intern_pool; @@ -3951,19 +4154,18 @@ pub const Object = struct { // Keep the greater of the two alignments. const llvm_variable = gop.value_ptr.*; const llvm_old_align = llvm_variable.getAlignment(&o.builder); - const llvm_new_align = llvm_old_align.max(@"align".toLlvm()); + const llvm_new_align = llvm_old_align.max(@"align"); llvm_variable.setAlignment(llvm_new_align, &o.builder); return llvm_variable.ptrConst(&o.builder).global.toConst(); } errdefer assert(o.uav_map.remove(.{ .val = uav_val, .@"addrspace" = @"addrspace" })); - const llvm_ty = try o.lowerType(uav_ty, .in_memory); const llvm_name = try o.builder.strtabStringFmt("__anon_{d}", .{@backingInt(uav_val)}); - const llvm_variable = try o.builder.addVariable(llvm_name, llvm_ty, llvm_addrspace); + const llvm_variable = try o.builder.addVariable(llvm_name, .void, llvm_addrspace); gop.value_ptr.* = llvm_variable; try llvm_variable.setInitializer(try o.lowerValue(uav_val, .in_memory), &o.builder); llvm_variable.setMutability(.constant, &o.builder); - llvm_variable.setAlignment(@"align".toLlvm(), &o.builder); + llvm_variable.setAlignment(@"align", &o.builder); const llvm_global = llvm_variable.ptrConst(&o.builder).global; llvm_global.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); @@ -3982,7 +4184,7 @@ pub const Object = struct { .none => nav_ty.abiAlignment(zcu), else => |a| a, }; - return o.lowerPtrToVoid(nav_align, nav.resolved.?.@"addrspace"); + return o.lowerPtrToVoid(nav_align.toLlvm(), nav.resolved.?.@"addrspace"); } const gop = try o.nav_map.getOrPut(gpa, nav_id); @@ -4011,7 +4213,7 @@ pub const Object = struct { attributes: *Builder.FunctionAttributes.Wip, param_ty: Type, param_index: u32, - fn_info: InternPool.Key.FuncType, + fn_info: FuncInfo, llvm_arg_i: u32, ) Allocator.Error!void { const zcu = o.zcu; @@ -4051,19 +4253,26 @@ pub const Object = struct { }; } + pub const Byval = struct { alignment: InternPool.Alignment = .none }; pub fn addByRefParamAttrs( o: *Object, attributes: *Builder.FunctionAttributes.Wip, llvm_arg_i: u32, - byval: bool, + maybe_byval: ?Byval, param_ty: Type, ) Allocator.Error!void { const llvm_param_ty = try o.lowerType(param_ty, .in_memory); - const alignment = param_ty.abiAlignment(o.zcu).toLlvm(); - try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); - try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = .wrap(alignment) }, &o.builder); - if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = llvm_param_ty }, &o.builder); + try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); + try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder); + const alignment = if (maybe_byval) |byval| alignment: { + try attributes.addParamAttr(llvm_arg_i, .{ .byval = llvm_param_ty }, &o.builder); + break :alignment byval.alignment; + } else .none; + try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = .wrap(switch (alignment) { + .none => param_ty.abiAlignment(o.zcu), + else => alignment, + }.toLlvm()) }, &o.builder); } pub fn getErrorNameTable(o: *Object) Allocator.Error!Builder.Variable.Index { @@ -4071,18 +4280,18 @@ pub const Object = struct { const name = try o.builder.strtabString("__zig_error_name_table"); // TODO: Address space - const variable_index = try o.builder.addVariable(name, .ptr, .default); - variable_index.setMutability(.constant, &o.builder); - variable_index.setAlignment( + const llvm_variable = try o.builder.addVariable(name, .ptr, .default); + llvm_variable.setMutability(.constant, &o.builder); + llvm_variable.setAlignment( Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(), &o.builder, ); - const global_index = variable_index.ptrConst(&o.builder).global; - global_index.setLinkage(.private, &o.builder); - global_index.setUnnamedAddr(.unnamed_addr, &o.builder); + const llvm_global = llvm_variable.ptrConst(&o.builder).global; + llvm_global.setLinkage(.private, &o.builder); + llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); - o.error_name_table = variable_index; - return variable_index; + o.error_name_table = llvm_variable; + return llvm_variable; } pub fn getErrorsLen(o: *Object) Allocator.Error!Builder.Variable.Index { @@ -4090,13 +4299,13 @@ pub const Object = struct { if (o.errors_len_variable == .none) { const llvm_err_int_ty = try o.errorIntType(.in_memory); const name = try builder.strtabString("__zig_errors_len"); - const variable_index = try builder.addVariable(name, llvm_err_int_ty, .default); - variable_index.setMutability(.constant, builder); - variable_index.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder); - const global_index = variable_index.ptrConst(&o.builder).global; - global_index.setLinkage(.private, builder); - global_index.setUnnamedAddr(.unnamed_addr, builder); - o.errors_len_variable = variable_index; + const llvm_variable = try builder.addVariable(name, llvm_err_int_ty, .default); + llvm_variable.setMutability(.constant, builder); + llvm_variable.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder); + const llvm_global = llvm_variable.ptrConst(&o.builder).global; + llvm_global.setLinkage(.private, builder); + llvm_global.setUnnamedAddr(.unnamed_addr, builder); + o.errors_len_variable = llvm_variable; } return o.errors_len_variable; } @@ -4108,43 +4317,43 @@ pub const Object = struct { const gop = try o.enum_tag_name_map.getOrPut(o.gpa, enum_ty.toIntern()); if (gop.found_existing) return gop.value_ptr.*; errdefer assert(o.enum_tag_name_map.remove(enum_ty.toIntern())); - const function_index = try o.builder.addFunction( + const llvm_function = try o.builder.addFunction( // Dummy function type; `updateEnumTagNameFunction` will replace it with the correct type. // TODO: change the builder API so we don't need to do this. try o.builder.fnType(.void, &.{}, .normal), try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}), toLlvmAddressSpace(.generic, zcu.getTarget()), ); - gop.value_ptr.* = function_index; - try o.updateEnumTagNameFunction(enum_ty, function_index); - return function_index; + gop.value_ptr.* = llvm_function; + try o.updateEnumTagNameFunction(enum_ty, llvm_function); + return llvm_function; } fn updateEnumTagNameFunction( o: *Object, enum_ty: Type, - function_index: Builder.Function.Index, + llvm_function: Builder.Function.Index, ) Allocator.Error!void { const zcu = o.zcu; const ip = &zcu.intern_pool; const loaded_enum = ip.loadEnumType(enum_ty.toIntern()); - const llvm_usize_ty = try o.lowerType(.usize, .by_value); - const llvm_ret_ty = try o.lowerType(.slice_const_u8_sentinel_0, .by_value); - const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); + const llvm_ret_ty = try o.lowerType(.slice_const_u8_sentinel_0, .as_value); + const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value); - function_index.ptrConst(&o.builder).global.ptr(&o.builder).type = + llvm_function.ptrConst(&o.builder).global.ptr(&o.builder).type = try o.builder.fnType(llvm_ret_ty, &.{llvm_int_ty}, .normal); var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer); - function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); - function_index.setCallConv(.fastcc, &o.builder); - function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); + llvm_function.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); + llvm_function.setCallConv(.fastcc, &o.builder); + llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder); var wip = try Builder.WipFunction.init(&o.builder, .{ - .function = function_index, + .function = llvm_function, .strip = true, }); defer wip.deinit(); @@ -4163,23 +4372,23 @@ pub const Object = struct { for (0..loaded_enum.field_names.len) |field_index| { const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip)); const name_init = try o.builder.stringConst(name); - const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); - try name_variable_index.setInitializer(name_init, &o.builder); - name_variable_index.setMutability(.constant, &o.builder); - name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); - const name_global_index = name_variable_index.ptrConst(&o.builder).global; - name_global_index.setLinkage(.private, &o.builder); - name_global_index.setUnnamedAddr(.unnamed_addr, &o.builder); + const name_llvm_variable = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); + try name_llvm_variable.setInitializer(name_init, &o.builder); + name_llvm_variable.setMutability(.constant, &o.builder); + name_llvm_variable.setAlignment(comptime .fromByteUnits(1), &o.builder); + const name_llvm_global = name_llvm_variable.ptrConst(&o.builder).global; + name_llvm_global.setLinkage(.private, &o.builder); + name_llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); const name_val = try o.builder.structValue(llvm_ret_ty, &.{ - name_global_index.toConst(), + name_llvm_global.toConst(), try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1), }); const return_block = try wip.block(1, "Name"); const llvm_tag_val = switch (loaded_enum.field_values.getOrNone(ip, field_index)) { .none => try o.builder.intConst(llvm_int_ty, field_index), // auto-numbered - else => |tag_val_ip| try o.lowerValue(tag_val_ip, .by_value), + else => |tag_val_ip| try o.lowerValue(tag_val_ip, .as_value), }; try wip_switch.addCase(llvm_tag_val, return_block, &wip); @@ -4205,40 +4414,40 @@ pub const Object = struct { const gop = try o.named_enum_map.getOrPut(o.gpa, enum_ty.toIntern()); if (gop.found_existing) return gop.value_ptr.*; errdefer assert(o.named_enum_map.remove(enum_ty.toIntern())); - const function_index = try o.builder.addFunction( + const llvm_function = try o.builder.addFunction( // Dummy function type; `updateIsNamedEnumValue` will replace it with the correct type. // TODO: change the builder API so we don't need to do this. try o.builder.fnType(.void, &.{}, .normal), try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}), toLlvmAddressSpace(.generic, zcu.getTarget()), ); - gop.value_ptr.* = function_index; - try o.updateIsNamedEnumValueFunction(enum_ty, function_index); - return function_index; + gop.value_ptr.* = llvm_function; + try o.updateIsNamedEnumValueFunction(enum_ty, llvm_function); + return llvm_function; } fn updateIsNamedEnumValueFunction( o: *Object, enum_ty: Type, - function_index: Builder.Function.Index, + llvm_function: Builder.Function.Index, ) Allocator.Error!void { const zcu = o.zcu; const ip = &zcu.intern_pool; const loaded_enum = ip.loadEnumType(enum_ty.toIntern()); - const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .by_value); - function_index.ptrConst(&o.builder).global.ptr(&o.builder).type = + const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type), .as_value); + llvm_function.ptrConst(&o.builder).global.ptr(&o.builder).type = try o.builder.fnType(.i1, &.{llvm_int_ty}, .normal); var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer); - function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); - function_index.setCallConv(.fastcc, &o.builder); - function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); + llvm_function.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); + llvm_function.setCallConv(.fastcc, &o.builder); + llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder); var wip: Builder.WipFunction = try .init(&o.builder, .{ - .function = function_index, + .function = llvm_function, .strip = true, }); defer wip.deinit(); @@ -4252,7 +4461,7 @@ pub const Object = struct { if (loaded_enum.field_values.len > 0) { for (loaded_enum.field_values.get(ip)) |tag_val_ip| { - const llvm_tag_val = try o.lowerValue(tag_val_ip, .by_value); + const llvm_tag_val = try o.lowerValue(tag_val_ip, .as_value); try wip_switch.addCase(llvm_tag_val, named_block, &wip); } } else { @@ -4274,20 +4483,27 @@ pub const Object = struct { pub fn getLibcFunction( o: *Object, + pt: Zcu.PerThread, fn_name: Builder.StrtabString, - param_types: []const Builder.Type, - return_type: Builder.Type, + fn_info: FuncInfo, ) Allocator.Error!Builder.Function.Index { if (o.builder.getGlobal(fn_name)) |global| return switch (global.ptrConst(&o.builder).kind) { .alias => |alias| alias.getAliasee(&o.builder).ptrConst(&o.builder).kind.function, .function => |function| function, .variable, .replaced => unreachable, }; - return o.builder.addFunction( - try o.builder.fnType(return_type, param_types, .normal), + const llvm_function = try o.builder.addFunction( + try o.lowerFnType(fn_info), fn_name, toLlvmAddressSpace(.generic, o.zcu.getTarget()), ); + var attributes: Builder.FunctionAttributes.Wip = .{}; + defer attributes.deinit(&o.builder); + try o.addCallingConventionFnAttributes(pt, llvm_function, &attributes, .{ + .name = fn_name.slice(&o.builder).?, + }, fn_info); + llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder); + return llvm_function; } }; @@ -4324,7 +4540,7 @@ pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) std.lang.CallingConvention.SpirvFragmentOptions, std.lang.CallingConvention.SpirvMeshOptions, => .{ null, 0, 0 }, - else => @compileError("TODO: toLlvmCallConv" ++ @tagName(pl)), + else => @compileError("TODO: toLlvmCallConv(." ++ @tagName(pl) ++ ")"), }, }; return .{ @@ -4360,6 +4576,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const null, .x86_64_vectorcall => .x86_vectorcallcc, .x86_64_interrupt => .x86_intrcc, + .x86_64_preserve_none => .preserve_nonecc, .x86_stdcall => .x86_stdcallcc, .x86_fastcall => .x86_fastcallcc, .x86_thiscall => .x86_thiscallcc, @@ -4375,6 +4592,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const .x86_interrupt => .x86_intrcc, .aarch64_vfabi => .aarch64_vector_pcs, .aarch64_vfabi_sve => .aarch64_sve_vector_pcs, + .aarch64_preserve_none => .preserve_nonecc, .arm_aapcs => .arm_aapcscc, .arm_aapcs_vfp => .arm_aapcs_vfpcc, .riscv64_lp64_v => .riscv_vectorcallcc, @@ -4407,6 +4625,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const .x86_16_interrupt, .x86_sysv, .x86_win, + .x86_mingw, .x86_thiscall_mingw, .x86_64_x32, .aarch64_aapcs, @@ -4581,47 +4800,6 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.lang.AddressSpace, target: }; } -/// This function returns true if we expect LLVM to lower f16 correctly -/// and false if we expect LLVM to crash if it encounters an f16 type, -/// or if it produces miscompilations. -pub fn backendSupportsF16(target: *const std.Target) bool { - return switch (target.cpu.arch) { - .arm, - .armeb, - .thumb, - .thumbeb, - => target.abi.float() == .soft or target.cpu.has(.arm, .fullfp16), - else => true, - }; -} - -/// This function returns true if we expect LLVM to lower x86_fp80 correctly -/// and false if we expect LLVM to crash if it encounters an x86_fp80 type, -/// or if it produces miscompilations. -pub fn backendSupportsF80(target: *const std.Target) bool { - return switch (target.cpu.arch) { - .x86, .x86_64 => !target.cpu.has(.x86, .soft_float), - else => false, - }; -} - -/// This function returns true if we expect LLVM to lower f128 correctly, -/// and false if we expect LLVM to crash if it encounters an f128 type, -/// or if it produces miscompilations. -pub fn backendSupportsF128(target: *const std.Target) bool { - return switch (target.cpu.arch) { - // https://github.com/llvm/llvm-project/issues/121122 - .amdgcn, - => false, - .arm, - .armeb, - .thumb, - .thumbeb, - => target.abi.float() == .soft or target.cpu.has(.arm, .fp_armv8), - else => true, - }; -} - /// We need to insert extra padding if LLVM's isn't enough. /// However we don't want to ever call LLVMABIAlignmentOfType or /// LLVMABISizeOfType because these functions will trip assertions diff --git a/src/codegen/llvm/FuncGen.zig b/src/codegen/llvm/FuncGen.zig index d8b8eede7c09febaf5485ef0c013fff94934d8ef..14e31fd1c09f846fcef7417b46b7681423880cfd 100644 --- a/src/codegen/llvm/FuncGen.zig +++ b/src/codegen/llvm/FuncGen.zig @@ -164,12 +164,12 @@ fn resolveValue(self: *FuncGen, val: Value) Allocator.Error!Builder.Constant { const zcu = o.zcu; const ty = val.typeOf(zcu); if (!isByRef(ty, zcu)) { - return o.lowerValue(val.toIntern(), .by_value); + return o.lowerValue(val.toIntern(), .as_value); } else { // We need a pointer to a global constant, i.e. a UAV. return o.lowerUavRef( val.toIntern(), - ty.abiAlignment(zcu), + ty.abiAlignment(zcu).toLlvm(), target_util.defaultAddressSpace(zcu.getTarget(), .global_constant), ); } @@ -190,10 +190,10 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void { const fn_info = zcu.typeToFunc(fn_ty).?; const param_types = fn_info.param_types.get(ip); - var it = iterateParamTypes(o, fn_info); + var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types.get(ip)); // Populate `fg.ret_ptr`... - fg.ret_ptr = switch (try fnReturnStrat(o, fn_info)) { + fg.ret_ptr = switch (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type))) { .sret => rp: { defer it.llvm_index += 1; break :rp fg.wip.arg(it.llvm_index); @@ -218,7 +218,7 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void { switch (lowering) { .no_bits => continue, .byval => { - assert(!it.byval_attr); + assert(it.byval_attr == null); const param_index = it.zig_index - 1; const param_ty: Type = .fromInterned(param_types[param_index]); const param = fg.wip.arg(it.llvm_index - 1); @@ -237,15 +237,16 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void { .byref, .byref_mut => { const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); const param = fg.wip.arg(it.llvm_index - 1); + const alignment = if (it.byval_attr) |byval_attr| byval_attr.alignment else .none; - if (isByRef(param_ty, zcu)) { + if (alignment == .none and isByRef(param_ty, zcu)) { args.appendAssumeCapacity(param); } else { - args.appendAssumeCapacity(try fg.load(param, .none, param_ty, .normal)); + args.appendAssumeCapacity(try fg.load(param, alignment, param_ty, .normal)); } }, .abi_sized_int => { - assert(!it.byval_attr); + assert(it.byval_attr == null); const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); const param = fg.wip.arg(it.llvm_index - 1); @@ -260,18 +261,18 @@ pub fn genMainBody(fg: *FuncGen) TodoError!void { } }, .slice => { - assert(!it.byval_attr); + assert(it.byval_attr == null); const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); assert(!isByRef(param_ty, zcu)); const slice_val = try fg.wip.buildAggregate( - try o.lowerType(param_ty, .by_value), + try o.lowerType(param_ty, .as_value), &.{ fg.wip.arg(it.llvm_index - 2), fg.wip.arg(it.llvm_index - 1) }, "", ); args.appendAssumeCapacity(slice_val); }, .multiple_llvm_types => { - assert(!it.byval_attr); + assert(it.byval_attr == null); const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); const param_alignment = param_ty.abiAlignment(zcu); const llvm_ty = try o.builder.arrayType(it.offsets_buffer[it.types_len], .i8); @@ -696,7 +697,7 @@ fn genBodyDebugScope( .{ .di_flags = .{ .StaticMember = true }, .sp_flags = .{ - .Optimized = mod.optimize_mode != .Debug, + .Optimized = mod.optimize_mode != .debug, .Definition = true, .LocalToUnit = true, // inline functions cannot be exported }, @@ -721,29 +722,19 @@ fn genBodyDebugScope( try self.genBody(body, coverage_point); } -const CallAttr = enum { - Auto, - NeverTail, - NeverInline, - AlwaysTail, - AlwaysInline, -}; - -fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) Allocator.Error!Builder.Value { - const air_call = self.air.unwrapCall(inst); +fn airCall(fg: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) Allocator.Error!Builder.Value { + const o = fg.object; + const zcu = o.zcu; + const air_call = fg.air.unwrapCall(inst); const args = air_call.args; - const o = self.object; - const pt = self.pt; - const zcu = o.zcu; const ip = &zcu.intern_pool; - const callee_ty = self.typeOf(air_call.callee); + const callee_ty = fg.typeOf(air_call.callee); const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) { .@"fn" => callee_ty, .pointer => callee_ty.childType(zcu), else => unreachable, }; const fn_info = zcu.typeToFunc(zig_fn_ty).?; - const return_type: Type = .fromInterned(fn_info.return_type); const llvm_fn = llvm_fn: { // If the callee is a function *body*, we need to use a pointer to the global. if (air_call.callee.toInterned()) |ip_index| switch (ip.indexToKey(ip_index)) { @@ -752,22 +743,54 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier else => {}, }; // Otherwise, the operand is already a function pointer (possibly runtime-known). - break :llvm_fn try self.resolveInst(air_call.callee); + break :llvm_fn try fg.resolveInst(air_call.callee); }; + + const arg_types = try fg.gpa.alloc(InternPool.Index, args.len); + defer fg.gpa.free(arg_types); + const arg_values = try fg.gpa.alloc(Builder.Value, args.len); + defer fg.gpa.free(arg_values); + for (arg_types, arg_values, args) |*arg_type, *arg_value, arg| { + const arg_ty = fg.typeOf(arg); + arg_type.* = arg_ty.toIntern(); + arg_value.* = if (arg_ty.hasRuntimeBits(zcu)) try fg.resolveInst(arg) else .none; + } + return fg.buildCall(.{ + .is_unused = fg.liveness.isUnused(inst), + .modifier = modifier, + }, try o.lowerType(zig_fn_ty, .as_value), llvm_fn, .fromIntern(fn_info, ip), arg_types, arg_values); +} + +fn buildCall( + fg: *FuncGen, + opts: struct { + is_unused: bool = false, + modifier: std.lang.CallModifier = .auto, + }, + llvm_fn_ty: Builder.Type, + llvm_fn: Builder.Value, + fn_info: Object.FuncInfo, + arg_types: []const InternPool.Index, + arg_values: []const Builder.Value, +) Allocator.Error!Builder.Value { + const o = fg.object; + const pt = fg.pt; + const zcu = o.zcu; + const return_type: Type = .fromInterned(fn_info.return_type); const target = zcu.getTarget(); - const ret_strat = try fnReturnStrat(o, fn_info); + const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)); - var llvm_args = std.array_list.Managed(Builder.Value).init(self.gpa); - defer llvm_args.deinit(); + var llvm_args: std.ArrayList(Builder.Value) = .empty; + defer llvm_args.deinit(fg.gpa); var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); - if (self.disable_intrinsics) { + if (fg.disable_intrinsics) { try attributes.addFnAttr(.nobuiltin, &o.builder); } - switch (modifier) { + switch (opts.modifier) { .auto, .always_tail => {}, .never_tail, .never_inline => try attributes.addFnAttr(.@"noinline", &o.builder), .no_suspend, .always_inline, .compile_time => unreachable, @@ -775,10 +798,11 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier const sret_alloc: ?Builder.Value = switch (ret_strat) { .sret => sret_alloc: { - try attributes.addParamAttr(0, .{ .sret = try o.lowerType(return_type, .in_memory) }, &o.builder); + const alignment = return_type.abiAlignment(zcu).toLlvm(); + try o.addSRetFnAttributes(&attributes, try o.lowerType(return_type, .in_memory), alignment, .callsite); - const ptr = try self.buildZigAlloca(return_type, .none); - try llvm_args.append(ptr); + const ptr = try fg.buildZigAlloca(return_type, .none); + try llvm_args.append(fg.gpa, ptr); break :sret_alloc ptr; }, else => sret_alloc: { @@ -792,132 +816,111 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; if (err_return_tracing) { - assert(self.err_ret_trace != .none); - try llvm_args.append(self.err_ret_trace); + assert(fg.err_ret_trace != .none); + try llvm_args.append(fg.gpa, fg.err_ret_trace); } - var it = iterateParamTypes(o, fn_info); - while (try it.nextCall(self, args)) |lowering| switch (lowering) { - .no_bits => continue, - .byval => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); - if (isByRef(param_ty, zcu)) { - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - // We don't need to handle non-ABI-sized integer types in memory here since they are - // never by-ref. - const llvm_param_ty = try o.lowerType(param_ty, .in_memory); - const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, ""); - try llvm_args.append(loaded); - } else { - try llvm_args.append(llvm_arg); - } - }, - .byref => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); - if (isByRef(param_ty, zcu)) { - try llvm_args.append(llvm_arg); - } else { - const arg_ptr = try self.buildZigAlloca(param_ty, .none); - try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal); - try llvm_args.append(arg_ptr); - } - }, - .byref_mut => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); + var it = iterateParamTypes(o, fn_info.cc, fn_info.param_types); + while (try it.nextCall(arg_types)) |lowering| { + const arg_ty: Type = .fromInterned(arg_types[it.zig_index - 1]); + const arg_val = arg_values[it.zig_index - 1]; + switch (lowering) { + .no_bits => continue, + .byval => { + if (isByRef(arg_ty, zcu)) { + const alignment = arg_ty.abiAlignment(zcu).toLlvm(); + // We don't need to handle non-ABI-sized integer types in memory here since they are + // never by-ref. + const llvm_arg_ty = try o.lowerType(arg_ty, .memory_access); + const loaded = try fg.wip.load(.normal, llvm_arg_ty, arg_val, alignment, ""); + try llvm_args.append(fg.gpa, loaded); + } else { + try llvm_args.append(fg.gpa, arg_val); + } + }, + .byref => { + if (isByRef(arg_ty, zcu)) { + try llvm_args.append(fg.gpa, arg_val); + } else { + const arg_ptr = try fg.buildZigAlloca(arg_ty, .none); + try fg.store(arg_ptr, .none, arg_val, arg_ty, .normal); + try llvm_args.append(fg.gpa, arg_ptr); + } + }, + .byref_mut => { + const arg_ptr = try fg.buildZigAlloca(arg_ty, .none); + try fg.store(arg_ptr, .none, arg_val, arg_ty, .normal); + try llvm_args.append(fg.gpa, arg_ptr); + }, + .abi_sized_int => { + const int_llvm_ty = try o.builder.intType(@intCast(arg_ty.abiSize(zcu) * 8)); - const arg_ptr = try self.buildZigAlloca(param_ty, .none); - try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal); - try llvm_args.append(arg_ptr); - }, - .abi_sized_int => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); - const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(zcu) * 8)); + if (isByRef(arg_ty, zcu)) { + const alignment = arg_ty.abiAlignment(zcu).toLlvm(); + const loaded = try fg.wip.load(.normal, int_llvm_ty, arg_val, alignment, ""); + try llvm_args.append(fg.gpa, loaded); + } else { + // LLVM does not allow bitcasting structs so we must allocate + // a local, store as one type, and then load as another type. + const alignment = arg_ty.abiAlignment(zcu).toLlvm(); + const ptr = try fg.buildAlloca(int_llvm_ty, alignment); + try fg.store(ptr, .none, arg_val, arg_ty, .normal); + const loaded = try fg.wip.load(.normal, int_llvm_ty, ptr, alignment, ""); + try llvm_args.append(fg.gpa, loaded); + } + }, + .slice => { + const ptr = try fg.wip.extractValue(arg_val, &.{0}, ""); + const len = try fg.wip.extractValue(arg_val, &.{1}, ""); + try llvm_args.appendSlice(fg.gpa, &.{ ptr, len }); + }, + .multiple_llvm_types => { + const arg_alignment = arg_ty.abiAlignment(zcu); + const llvm_ty = try o.builder.arrayType(it.offsets_buffer[it.types_len], .i8); + const arg_ptr = try fg.buildAlloca(llvm_ty, arg_alignment.toLlvm()); + try fg.store(arg_ptr, .none, arg_val, arg_ty, .normal); - if (isByRef(param_ty, zcu)) { - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, ""); - try llvm_args.append(loaded); - } else { - // LLVM does not allow bitcasting structs so we must allocate - // a local, store as one type, and then load as another type. - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const ptr = try self.buildAlloca(int_llvm_ty, alignment); - try self.store(ptr, .none, llvm_arg, param_ty, .normal); - const loaded = try self.wip.load(.normal, int_llvm_ty, ptr, alignment, ""); - try llvm_args.append(loaded); - } - }, - .slice => { - const arg = args[it.zig_index - 1]; - const llvm_arg = try self.resolveInst(arg); - const ptr = try self.wip.extractValue(llvm_arg, &.{0}, ""); - const len = try self.wip.extractValue(llvm_arg, &.{1}, ""); - try llvm_args.appendSlice(&.{ ptr, len }); - }, - .multiple_llvm_types => { - const arg = args[it.zig_index - 1]; - const param_ty = self.typeOf(arg); - const llvm_arg = try self.resolveInst(arg); - const param_alignment = param_ty.abiAlignment(zcu); - const llvm_ty = try o.builder.arrayType(it.offsets_buffer[it.types_len], .i8); - const arg_ptr = try self.buildAlloca(llvm_ty, param_alignment.toLlvm()); - try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal); + try llvm_args.ensureUnusedCapacity(fg.gpa, it.types_len); + for (it.types_buffer[0..it.types_len], it.offsets_buffer[0..it.types_len]) |field_ty, offset| { + const field_ptr = try fg.ptraddConst(arg_ptr, offset); + const loaded = try fg.wip.load(.normal, field_ty, field_ptr, arg_alignment.offset(offset).toLlvm(), ""); + llvm_args.appendAssumeCapacity(loaded); + } + }, + .float_array => |count| { + const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: { + const ptr = try fg.buildZigAlloca(arg_ty, .none); + try fg.store(ptr, .none, arg_val, arg_ty, .normal); + break :ptr ptr; + } else arg_val; - try llvm_args.ensureUnusedCapacity(it.types_len); - for (it.types_buffer[0..it.types_len], it.offsets_buffer[0..it.types_len]) |field_ty, offset| { - const field_ptr = try self.ptraddConst(arg_ptr, offset); - const loaded = try self.wip.load(.normal, field_ty, field_ptr, param_alignment.offset(offset).toLlvm(), ""); - llvm_args.appendAssumeCapacity(loaded); - } - }, - .float_array => |count| { - const arg = args[it.zig_index - 1]; - const arg_ty = self.typeOf(arg); - const arg_val = try self.resolveInst(arg); + const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, zcu).?, .memory_access); + const array_ty = try o.builder.arrayType(count, float_ty); - const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: { - const ptr = try self.buildZigAlloca(arg_ty, .none); - try self.store(ptr, .none, arg_val, arg_ty, .normal); - break :ptr ptr; - } else arg_val; + const loaded = try fg.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), ""); + try llvm_args.append(fg.gpa, loaded); + }, + .i32_array, .i64_array => |arr_len| { + const elem_size: u8 = if (lowering == .i32_array) 32 else 64; - const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, zcu).?, .in_memory); - const array_ty = try o.builder.arrayType(count, float_ty); + const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: { + const ptr = try fg.buildZigAlloca(arg_ty, .none); + try fg.store(ptr, .none, arg_val, arg_ty, .normal); + break :ptr ptr; + } else arg_val; - const loaded = try self.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), ""); - try llvm_args.append(loaded); - }, - .i32_array, .i64_array => |arr_len| { - const elem_size: u8 = if (lowering == .i32_array) 32 else 64; - const arg = args[it.zig_index - 1]; - const arg_ty = self.typeOf(arg); - const arg_val = try self.resolveInst(arg); - - const arg_ptr: Builder.Value = if (!isByRef(arg_ty, zcu)) ptr: { - const ptr = try self.buildZigAlloca(arg_ty, .none); - try self.store(ptr, .none, arg_val, arg_ty, .normal); - break :ptr ptr; - } else arg_val; - - const array_ty = try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size))); - const loaded = try self.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), ""); - try llvm_args.append(loaded); - }, - }; + const array_ty = try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size))); + const loaded = try fg.wip.load(.normal, array_ty, arg_ptr, arg_ty.abiAlignment(zcu).toLlvm(), ""); + try llvm_args.append(fg.gpa, loaded); + }, + } + } const cc_info = llvm.toLlvmCallConv(fn_info.cc, target).?; { // Add argument attributes. - it = iterateParamTypes(o, fn_info); + it = iterateParamTypes(o, fn_info.cc, fn_info.param_types); it.llvm_index += @intFromBool(ret_strat == .sret); it.llvm_index += @intFromBool(err_return_tracing); var remaining_inreg_int = cc_info.inreg_int_params; @@ -925,7 +928,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier while (try it.next()) |lowering| switch (lowering) { .byval => { const param_index = it.zig_index - 1; - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]); + const param_ty = Type.fromInterned(fn_info.param_types[param_index]); if (!isByRef(param_ty, zcu)) { try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1); } @@ -947,7 +950,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier }, .byref => { const param_index = it.zig_index - 1; - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[param_index]); + const param_ty: Type = .fromInterned(fn_info.param_types[param_index]); try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, it.byval_attr, param_ty); }, .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), @@ -961,8 +964,8 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier => continue, .slice => { - assert(!it.byval_attr); - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); + assert(it.byval_attr == null); + const param_ty = Type.fromInterned(fn_info.param_types[it.zig_index - 1]); const ptr_info = param_ty.ptrInfo(zcu); const llvm_arg_i = it.llvm_index - 2; @@ -989,8 +992,8 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier }; } - const call = try self.wip.call( - switch (modifier) { + const call = try fg.wip.call( + switch (opts.modifier) { .auto, .never_inline => .normal, .never_tail => .notail, .always_tail => .musttail, @@ -998,19 +1001,14 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier }, cc_info.llvm_cc, try attributes.finish(&o.builder), - try o.lowerType(zig_fn_ty, .by_value), + llvm_fn_ty, llvm_fn, llvm_args.items, "", ); - if (fn_info.return_type == .noreturn_type and modifier != .always_tail) { - return .none; - } - - if (self.liveness.isUnused(inst)) { - return .none; - } + if (opts.is_unused) return .none; + if (fn_info.return_type == .noreturn_type and opts.modifier != .always_tail) return .none; // We exit this `switch` if we have a pointer to the return value. const ret_val_ptr: Builder.Value = switch (ret_strat) { @@ -1020,15 +1018,15 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier .sret => sret_alloc.?, .mem_cast => |llvm_ret_ty| ret_val_ptr: { const alignment = return_type.abiAlignment(zcu).toLlvm(); - const ptr = try self.buildAlloca(llvm_ret_ty, alignment); - _ = try self.wip.store(.normal, call, ptr, alignment); + const ptr = try fg.buildAlloca(llvm_ret_ty, alignment); + _ = try fg.wip.store(.normal, call, ptr, alignment); break :ret_val_ptr ptr; }, }; if (isByRef(return_type, zcu)) { return ret_val_ptr; } else { - return self.load(ret_val_ptr, .none, return_type, .normal); + return fg.load(ret_val_ptr, .none, return_type, .normal); } } @@ -1038,7 +1036,7 @@ fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) Allocator.Error!v const target = zcu.getTarget(); const panic_func = zcu.funcInfo(zcu.std_lang_decl_values.get(panic_id.toStdLangDecl())); const fn_info = zcu.typeToFunc(.fromInterned(panic_func.ty)).?; - const llvm_panic_fn_ty = try o.lowerType(.fromInterned(panic_func.ty), .by_value); + const llvm_panic_fn_ty = try o.lowerType(.fromInterned(panic_func.ty), .as_value); const llvm_panic_fn_ref = try o.lowerNavRef(panic_func.owner_nav); @@ -1067,7 +1065,7 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?; - const ret_strat = try fnReturnStrat(o, fn_info); + const ret_strat = try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type)); const val_is_undef = if (un_op.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false; const ret_ty_align = ret_ty.abiAlignment(zcu); @@ -1076,7 +1074,7 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo .none => try self.buildZigAlloca(ret_ty, .none), else => |rp| rp, }; - const len = try o.builder.intValue(try o.lowerType(.usize, .by_value), ret_ty.abiSize(zcu)); + const len = try o.builder.intValue(try o.lowerType(.usize, .as_value), ret_ty.abiSize(zcu)); _ = try self.wip.callMemSet( rp, ret_ty_align.toLlvm(), @@ -1141,7 +1139,7 @@ fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!void { const ret_ty = ptr_ty.childType(zcu); const fn_info = zcu.typeToFunc(.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?; const ptr = try self.resolveInst(un_op); - switch (try fnReturnStrat(o, fn_info)) { + switch (try fnReturnStrat(o, fn_info.cc, .fromInterned(fn_info.return_type))) { .void => _ = try self.wip.retVoid(), .sret => { assert(self.ret_ptr != .none); @@ -1165,7 +1163,7 @@ fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const list = try self.resolveInst(ty_op.operand); const arg_ty = ty_op.ty.toType(); - const llvm_arg_ty = try self.object.lowerType(arg_ty, .by_value); + const llvm_arg_ty = try self.object.lowerType(arg_ty, .as_value); return self.wip.vaArg(list, llvm_arg_ty, ""); } @@ -1378,7 +1376,7 @@ fn lowerBlock( if (have_block_result) { const llvm_ty: Builder.Type = switch (isByRef(inst_ty, zcu)) { true => .ptr, - false => try o.lowerType(inst_ty, .by_value), + false => try o.lowerType(inst_ty, .as_value), }; parent_bb.ptr(&self.wip).incoming = @intCast(breaks.list.len); const phi = try self.wip.phi(llvm_ty, ""); @@ -1485,7 +1483,7 @@ fn lowerSwitchDispatch( const table_index = try self.wip.conv( .unsigned, try self.wip.bin(.@"sub nuw", cond, jmp_table.min.toValue(), ""), - try o.lowerType(.usize, .by_value), + try o.lowerType(.usize, .as_value), "", ); const target_ptr_ptr = try self.ptraddScaled( @@ -1510,7 +1508,7 @@ fn lowerSwitchDispatch( // The switch prongs will correspond to our scalar cases. Ranges will // be handled by conditional branches in the `else` prong. - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const cond_int = if (cond_ty.zigTypeTag(zcu) == .pointer) try self.wip.cast(.ptrtoint, cond, llvm_usize, "") else @@ -1725,7 +1723,7 @@ fn lowerTry( if (err_union_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, ); }; - const zero = try o.builder.intValue(try o.errorIntType(.by_value), 0); + const zero = try o.builder.intValue(try o.errorIntType(.as_value), 0); const is_err = try fg.wip.icmp(.ne, loaded, zero, ""); const return_block = try fg.wip.block(1, "TryRet"); @@ -1862,8 +1860,8 @@ fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Tod const table_includes_else = item_count != table_len; break :jmp_table .{ - .min = try o.lowerValue(min.toIntern(), .by_value), - .max = try o.lowerValue(max.toIntern(), .by_value), + .min = try o.lowerValue(min.toIntern(), .as_value), + .max = try o.lowerValue(max.toIntern(), .as_value), .in_bounds_hint = if (table_includes_else) .none else switch (switch_br.getElseHint()) { .none, .cold => .none, .unpredictable => .unpredictable, @@ -2021,142 +2019,102 @@ fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand_ty = self.typeOf(ty_op.operand); const array_ty = operand_ty.childType(zcu); - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const len = try o.builder.intValue(llvm_usize, array_ty.arrayLen(zcu)); - const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst), .by_value); + const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst), .as_value); const operand = try self.resolveInst(ty_op.operand); return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, ""); } -fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { - const o = self.object; +fn airFloatFromInt(fg: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { + const o = fg.object; const zcu = o.zcu; - const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; + const ty_op = fg.air.instructions.items(.data)[@backingInt(inst)].ty_op; - const operand = try self.resolveInst(ty_op.operand); - const operand_ty = self.typeOf(ty_op.operand); + const operand = try fg.resolveInst(ty_op.operand); + const operand_ty = fg.typeOf(ty_op.operand); const operand_scalar_ty = operand_ty.scalarType(zcu); - const is_signed_int = operand_scalar_ty.isSignedInt(zcu); + const operand_scalar_info = operand_scalar_ty.intInfo(zcu); - const dest_ty = self.typeOfIndex(inst); + const dest_ty = fg.typeOfIndex(inst); const dest_scalar_ty = dest_ty.scalarType(zcu); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); const target = zcu.getTarget(); - if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv( - if (is_signed_int) .signed else .unsigned, - operand, - dest_llvm_ty, - "", - ); + if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target)) + return fg.wip.conv(.fromStdLang(operand_scalar_info.signedness), operand, try o.lowerType(dest_ty, .as_value), ""); - const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(zcu))) orelse { - return self.todo("float_from_int on {d} bit integer", .{operand_scalar_ty.bitSize(zcu)}); + const rt_int_ty = compilerRtPromoteInt(operand_scalar_info) orelse { + return fg.todo("float_from_int on {d} bit integer", .{operand_scalar_info.bits}); }; - const rt_int_ty = try o.builder.intType(rt_int_bits); - var extended = try self.wip.conv( - if (is_signed_int) .signed else .unsigned, + const vector_len = if (operand_ty.isVector(zcu)) operand_ty.vectorLen(zcu) else null; + const rt_llvm_int_ty = try o.lowerType(rt_int_ty, .as_value); + const extended = try fg.wip.conv( + .fromStdLang(operand_scalar_info.signedness), operand, - rt_int_ty, + if (vector_len) |len| + try o.builder.vectorType(.normal, len, rt_llvm_int_ty) + else + rt_llvm_int_ty, "", ); - const dest_bits = dest_scalar_ty.floatBits(target); - const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits); - const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); - const sign_prefix = if (is_signed_int) "" else "un"; const fn_name = try o.builder.strtabStringFmt("__float{s}{s}i{s}f", .{ - sign_prefix, - compiler_rt_operand_abbrev, - compiler_rt_dest_abbrev, + switch (operand_scalar_info.signedness) { + .signed => "", + .unsigned => "un", + }, + compilerRtIntAbbrev(rt_int_ty.intInfo(zcu).bits), + compilerRtFloatAbbrev(target, dest_scalar_ty.floatBits(target)), }); - - var param_type = rt_int_ty; - if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) { - // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard - // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have. - param_type = try o.builder.vectorType(.normal, 2, .i64); - extended = try self.wip.cast(.bitcast, extended, param_type, ""); - } - - const libc_fn = try o.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty); - return self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - &.{extended}, - "", - ); + return fg.buildElementwiseCall(fn_name, .{ + .cc = target.cCallingConvention().?, + .param_types = &.{rt_int_ty.toIntern()}, + .return_type = dest_scalar_ty.toIntern(), + }, &.{extended}, vector_len); } fn airIntFromFloat( - self: *FuncGen, + fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind, ) TodoError!Builder.Value { _ = fast; - const o = self.object; + const o = fg.object; const zcu = o.zcu; const target = zcu.getTarget(); - const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; + const ty_op = fg.air.instructions.items(.data)[@backingInt(inst)].ty_op; - const operand = try self.resolveInst(ty_op.operand); - const operand_ty = self.typeOf(ty_op.operand); + const operand = try fg.resolveInst(ty_op.operand); + const operand_ty = fg.typeOf(ty_op.operand); const operand_scalar_ty = operand_ty.scalarType(zcu); - const dest_ty = self.typeOfIndex(inst); + const dest_ty = fg.typeOfIndex(inst); const dest_scalar_ty = dest_ty.scalarType(zcu); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); + const dest_llvm_ty = try o.lowerType(dest_ty, .as_value); + const dest_scalar_info = dest_scalar_ty.intInfo(zcu); - if (intrinsicsAllowed(operand_scalar_ty, target)) { + if (intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target)) { // TODO set fast math flag - return self.wip.conv( - if (dest_scalar_ty.isSignedInt(zcu)) .signed else .unsigned, - operand, - dest_llvm_ty, - "", - ); + return fg.wip.conv(.fromStdLang(dest_scalar_info.signedness), operand, dest_llvm_ty, ""); } - const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(zcu))) orelse { - return self.todo("int_from_float to {d} bit integer", .{dest_scalar_ty.bitSize(zcu)}); + const rt_int_ty = compilerRtPromoteInt(dest_scalar_info) orelse { + return fg.todo("int_from_float to {d} bit integer", .{dest_scalar_info.bits}); }; - const ret_ty = try o.builder.intType(rt_int_bits); - const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: { - // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard - // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have. - break :b try o.builder.vectorType(.normal, 2, .i64); - } else ret_ty; - - const operand_bits = operand_scalar_ty.floatBits(target); - const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); - - const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits); - const sign_prefix = if (dest_scalar_ty.isSignedInt(zcu)) "" else "uns"; - const fn_name = try o.builder.strtabStringFmt("__fix{s}{s}f{s}i", .{ - sign_prefix, - compiler_rt_operand_abbrev, - compiler_rt_dest_abbrev, + switch (dest_scalar_info.signedness) { + .signed => "", + .unsigned => "uns", + }, + compilerRtFloatAbbrev(target, operand_scalar_ty.floatBits(target)), + compilerRtIntAbbrev(rt_int_ty.intInfo(zcu).bits), }); - - const operand_llvm_ty = try o.lowerType(operand_ty, .by_value); - const libc_fn = try o.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty); - var result = try self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - &.{operand}, - "", - ); - - if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, ""); - if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, ""); - return result; + const result = try fg.buildElementwiseCall(fn_name, .{ + .cc = target.cCallingConvention().?, + .param_types = &.{operand_scalar_ty.toIntern()}, + .return_type = rt_int_ty.toIntern(), + }, &.{operand}, if (operand_ty.isVector(zcu)) operand_ty.vectorLen(zcu) else null); + return fg.wip.cast(.trunc, result, try o.lowerType(dest_ty, .as_value), ""); } fn sliceOrArrayPtr(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value { @@ -2167,7 +2125,7 @@ fn sliceOrArrayPtr(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!B fn sliceOrArrayLenInBytes(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value { const o = fg.object; const zcu = o.zcu; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); switch (ty.ptrSize(zcu)) { .slice => { const len = try fg.wip.extractValue(ptr, &.{1}, ""); @@ -2365,7 +2323,7 @@ fn airAggFieldVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder. }, .float => { // bitcast int->float - return self.wip.cast(.bitcast, field_int_val, try o.lowerType(field_ty, .by_value), ""); + return self.wip.cast(.bitcast, field_int_val, try o.lowerType(field_ty, .as_value), ""); }, } } @@ -2395,8 +2353,8 @@ fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build const field_offset = parent_ty.structFieldOffset(extra.field_index, zcu); if (field_offset == 0) return field_ptr; - const res_ty = try o.lowerType(ty_pl.ty.toType(), .by_value); - const llvm_usize = try o.lowerType(.usize, .by_value); + const res_ty = try o.lowerType(ty_pl.ty.toType(), .as_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const field_ptr_int = try self.wip.cast(.ptrtoint, field_ptr, llvm_usize, ""); const base_ptr_int = try self.wip.bin( @@ -2516,7 +2474,7 @@ fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index, is_arg: bool) Allocator.Er }, "", ); - } else if (owner_mod.optimize_mode == .Debug and !self.is_naked) { + } else if (owner_mod.optimize_mode == .debug and !self.is_naked) { // We avoid taking this path for naked functions because there's no guarantee that such // functions even have a valid stack pointer, making the `alloca` + `store` unsafe. @@ -2612,7 +2570,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { const output_inst = try self.resolveInst(output.operand); const output_ty = self.typeOf(output.operand); assert(output_ty.zigTypeTag(zcu) == .pointer); - const elem_llvm_ty = try o.lowerType(output_ty.childType(zcu), .by_value); + const elem_llvm_ty = try o.lowerType(output_ty.childType(zcu), .as_value); switch (constraint[0]) { '=' => {}, @@ -2650,7 +2608,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { llvm_ret_indirect[output.index] = false; const ret_ty = self.typeOfIndex(inst); - llvm_ret_types[llvm_ret_i] = try o.lowerType(ret_ty, .by_value); + llvm_ret_types[llvm_ret_i] = try o.lowerType(ret_ty, .as_value); llvm_ret_i += 1; } @@ -2689,7 +2647,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); } else { const alignment = arg_ty.abiAlignment(zcu).toLlvm(); - const arg_llvm_ty = try o.lowerType(arg_ty, .by_value); + const arg_llvm_ty = try o.lowerType(arg_ty, .as_value); const load_inst = try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, ""); llvm_param_values[llvm_param_i] = load_inst; llvm_param_types[llvm_param_i] = arg_llvm_ty; @@ -2729,7 +2687,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { llvm_param_attrs[llvm_param_i] = if (constraint[0] == '*') blk: { if (!is_by_ref) self.maybeMarkAllowZeroAccess(arg_ty.ptrInfo(zcu)); - break :blk try o.lowerType(if (is_by_ref) arg_ty else arg_ty.childType(zcu), .by_value); + break :blk try o.lowerType(if (is_by_ref) arg_ty else arg_ty.childType(zcu), .as_value); } else .none; llvm_param_i += 1; @@ -2743,7 +2701,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { if (constraint[0] != '+') continue; const rw_ty = self.typeOf(output.operand); - const llvm_elem_ty = try o.lowerType(rw_ty.childType(zcu), .by_value); + const llvm_elem_ty = try o.lowerType(rw_ty.childType(zcu), .as_value); if (llvm_ret_indirect[output.index]) { llvm_param_values[llvm_param_i] = llvm_rw_vals[output.index]; llvm_param_types[llvm_param_i] = llvm_rw_vals[output.index].typeOfWip(&self.wip); @@ -2957,7 +2915,7 @@ fn airIsNonNull( )); return self.wip.icmp(cond, slice_ptr, try o.builder.nullValue(ptr_ty), ""); } - return self.wip.icmp(cond, loaded, try o.builder.zeroInitValue(try o.lowerType(optional_ty, .by_value)), ""); + return self.wip.icmp(cond, loaded, try o.builder.zeroInitValue(try o.lowerType(optional_ty, .as_value)), ""); } comptime assert(optional_layout_version == 3); @@ -2986,18 +2944,17 @@ fn airIsErr( const operand_ty = self.typeOf(un_op); const err_union_ty = if (operand_is_ptr) operand_ty.childType(zcu) else operand_ty; const payload_ty = err_union_ty.errorUnionPayload(zcu); - const zero_err = try o.builder.intValue(try o.errorIntType(.by_value), 0); + const zero_err = try o.builder.intValue(try o.errorIntType(.as_value), 0); const access_kind: Builder.MemoryAccessKind = if (operand_is_ptr and operand_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; if (err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) { - const val: Builder.Constant = switch (cond) { + return switch (cond) { .eq => .true, // 0 == 0 .ne => .false, // 0 != 0 else => unreachable, }; - return val.toValue(); } if (operand_is_ptr) self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu)); @@ -3156,7 +3113,7 @@ fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) Allocator.Erro const err_union_ptr_align = err_union_ptr_ty.ptrAlignment(zcu); const payload_ty = err_union_ty.errorUnionPayload(zcu); - const non_error_val = try o.builder.intValue(try o.errorIntType(.by_value), 0); + const non_error_val = try o.builder.intValue(try o.errorIntType(.as_value), 0); const access_kind: Builder.MemoryAccessKind = if (err_union_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -3234,7 +3191,7 @@ fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error! const payload_ty = self.typeOf(ty_op.operand); assert(payload_ty.hasRuntimeBits(zcu)); assert(isByRef(err_un_ty, zcu)); // error unions with runtime bits are always by-ref - const ok_err_code = try o.builder.intValue(try o.errorIntType(.by_value), 0); + const ok_err_code = try o.builder.intValue(try o.errorIntType(.as_value), 0); const result_ptr = try self.buildZigAlloca(err_un_ty, .none); @@ -3273,7 +3230,7 @@ fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build const o = self.object; const pl_op = self.air.instructions.items(.data)[@backingInt(inst)].pl_op; const index = pl_op.payload; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); return self.wip.callIntrinsic(.normal, .none, .@"wasm.memory.size", &.{llvm_usize}, &.{ try o.builder.intValue(.i32, index), }, ""); @@ -3283,7 +3240,7 @@ fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build const o = self.object; const pl_op = self.air.instructions.items(.data)[@backingInt(inst)].pl_op; const index = pl_op.payload; - const llvm_isize = try o.lowerType(.isize, .by_value); + const llvm_isize = try o.lowerType(.isize, .as_value); return self.wip.callIntrinsic(.normal, .none, .@"wasm.memory.grow", &.{llvm_isize}, &.{ try o.builder.intValue(.i32, index), try self.resolveInst(pl_op.operand), }, ""); @@ -3310,7 +3267,7 @@ fn airMin(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { .normal, .none, if (scalar_ty.isSignedInt(zcu)) .smin else .umin, - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs }, "", ); @@ -3330,7 +3287,7 @@ fn airMax(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { .normal, .none, if (scalar_ty.isSignedInt(zcu)) .smax else .umax, - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs }, "", ); @@ -3342,7 +3299,7 @@ fn airSlice(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ptr = try self.resolveInst(bin_op.lhs); const len = try self.resolveInst(bin_op.rhs); const inst_ty = self.typeOfIndex(inst); - return self.wip.buildAggregate(try self.object.lowerType(inst_ty, .by_value), &.{ ptr, len }, ""); + return self.wip.buildAggregate(try self.object.lowerType(inst_ty, .as_value), &.{ ptr, len }, ""); } fn airAdd(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { @@ -3373,7 +3330,7 @@ fn airSafeArithmetic( const scalar_ty = inst_ty.scalarType(zcu); const intrinsic = if (scalar_ty.isSignedInt(zcu)) signed_intrinsic else unsigned_intrinsic; - const llvm_inst_ty = try o.lowerType(inst_ty, .by_value); + const llvm_inst_ty = try o.lowerType(inst_ty, .as_value); const results = try fg.wip.callIntrinsic(.normal, .none, intrinsic, &.{llvm_inst_ty}, &.{ lhs, rhs }, ""); @@ -3423,7 +3380,7 @@ fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value .normal, .none, if (scalar_ty.isSignedInt(zcu)) .@"sadd.sat" else .@"uadd.sat", - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs }, "", ); @@ -3462,7 +3419,7 @@ fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value .normal, .none, if (scalar_ty.isSignedInt(zcu)) .@"ssub.sat" else .@"usub.sat", - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs }, "", ); @@ -3501,7 +3458,7 @@ fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value .normal, .none, if (scalar_ty.isSignedInt(zcu)) .@"smul.fix.sat" else .@"umul.fix.sat", - &.{try o.lowerType(inst_ty, .by_value)}, + &.{try o.lowerType(inst_ty, .as_value)}, &.{ lhs, rhs, .@"0" }, "", ); @@ -3545,8 +3502,8 @@ fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) return self.buildFloatOp(.floor, fast, inst_ty, 1, .{result}); } if (scalar_ty.isSignedInt(zcu)) { - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); + const scalar_llvm_ty = try o.lowerType(scalar_ty, .as_value); + const inst_llvm_ty = try o.lowerType(inst_ty, .as_value); const ExpectedContents = [std.math.big.int.calcTwosCompLimbCount(256)]std.math.big.Limb; var bfa_buf: ExpectedContents = undefined; @@ -3594,8 +3551,8 @@ fn airDivCeil(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) return self.buildFloatOp(.ceil, fast, inst_ty, 1, .{result}); } if (scalar_ty.isSignedInt(zcu)) { - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); + const scalar_llvm_ty = try o.lowerType(scalar_ty, .as_value); + const inst_llvm_ty = try o.lowerType(inst_ty, .as_value); const ExpectedContents = [std.math.big.int.calcTwosCompLimbCount(256)]std.math.big.Limb; var bfa_buf: ExpectedContents = undefined; @@ -3634,8 +3591,8 @@ fn airDivCeil(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) const correction = try self.wip.cast(.zext, need_correction, inst_llvm_ty, "divCeil.correction"); return self.wip.bin(.@"add nsw", div, correction, "divCeil"); } else { - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); + const scalar_llvm_ty = try o.lowerType(scalar_ty, .as_value); + const inst_llvm_ty = try o.lowerType(inst_ty, .as_value); const zero = try o.builder.splatValue( inst_llvm_ty, @@ -3692,15 +3649,17 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo const lhs = try self.resolveInst(bin_op.lhs); const rhs = try self.resolveInst(bin_op.rhs); const inst_ty = self.typeOfIndex(inst); - const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); const scalar_ty = inst_ty.scalarType(zcu); if (scalar_ty.isRuntimeFloat()) { const a = try self.buildFloatOp(.fmod, fast, inst_ty, 2, .{ lhs, rhs }); const b = try self.buildFloatOp(.add, fast, inst_ty, 2, .{ a, rhs }); const c = try self.buildFloatOp(.fmod, fast, inst_ty, 2, .{ b, rhs }); - const zero = try o.builder.zeroInitValue(inst_llvm_ty); - const ltz = try self.buildFloatCmp(fast, .lt, inst_ty, .{ lhs, zero }); + const zero = if (isByRef(inst_ty, zcu)) zero: { + const zero = try o.builder.zeroInitConst(try o.lowerType(inst_ty, .in_memory)); + break :zero try o.lowerConstRef(zero, inst_ty.abiAlignment(zcu).toLlvm()); + } else try o.builder.zeroInitConst(try o.lowerType(inst_ty, .as_value)); + const ltz = try self.buildFloatCmp(fast, .lt, inst_ty, .{ lhs, zero.toValue() }); return self.wip.select(fast, ltz, c, a, ""); } if (scalar_ty.isSignedInt(zcu)) { @@ -3709,6 +3668,7 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), self.gpa); const allocator = bfa.allocator(); + const inst_llvm_ty = try o.lowerType(inst_ty, .as_value); const scalar_bits = scalar_ty.intInfo(zcu).bits; var smin_big_int: std.math.big.int.Mutable = .{ .limbs = try allocator.alloc( @@ -3721,7 +3681,7 @@ fn airMod(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allo defer allocator.free(smin_big_int.limbs); smin_big_int.setTwosCompIntLimit(.min, .signed, scalar_bits); const smin = try o.builder.splatValue(inst_llvm_ty, try o.builder.bigIntConst( - try o.lowerType(scalar_ty, .by_value), + try o.lowerType(scalar_ty, .as_value), smin_big_int.toConst(), )); @@ -3757,7 +3717,7 @@ fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ty_pl = self.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; const ptr_or_slice = try self.resolveInst(bin_op.lhs); - const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); const ptr_ty = self.typeOf(bin_op.lhs); const elem_ty = ptr_ty.indexableElem(zcu); const ptr = switch (ptr_ty.ptrSize(zcu)) { @@ -3790,7 +3750,7 @@ fn airOverflow( assert(isByRef(inst_ty, zcu)); // auto structs are by-ref const intrinsic = if (scalar_ty.isSignedInt(zcu)) signed_intrinsic else unsigned_intrinsic; - const llvm_lhs_ty = try o.lowerType(lhs_ty, .by_value); + const llvm_lhs_ty = try o.lowerType(lhs_ty, .as_value); const results = try self.wip.callIntrinsic(.normal, .none, intrinsic, &.{llvm_lhs_ty}, &.{ lhs, rhs }, ""); @@ -3818,34 +3778,97 @@ fn airOverflow( } fn buildElementwiseCall( - self: *FuncGen, - llvm_fn: Builder.Function.Index, - args_vectors: []const Builder.Value, - result_vector: Builder.Value, - vector_len: usize, + fg: *FuncGen, + fn_name: Builder.StrtabString, + fn_info: Object.FuncInfo, + arg_values: []const Builder.Value, + vector_len: ?u32, ) Allocator.Error!Builder.Value { - const o = self.object; - assert(args_vectors.len <= 3); + const o = fg.object; + const zcu = o.zcu; + const llvm_fn = try fg.object.getLibcFunction(fg.pt, fn_name, fn_info); - var i: usize = 0; - var result = result_vector; - while (i < vector_len) : (i += 1) { - const index_i32 = try o.builder.intValue(.i32, i); + const iterations = vector_len orelse 1; + const ret_ty: Type = .fromInterned(fn_info.return_type); + const ret_is_by_ref = isByRef(ret_ty, zcu); + if (iterations > 1 and (fn_info.return_type == .void_type or ret_is_by_ref) and + for (fn_info.param_types) |param_type| { + if (!isByRef(.fromInterned(param_type), zcu)) break false; + } else true) + { + const entry_block = fg.wip.cursor.block; + const loop_block = try fg.wip.block(2, "elementwise.loop"); + const done_block = try fg.wip.block(1, "elementwise.done"); - var args: [3]Builder.Value = undefined; - for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| { - arg_elem.* = try self.wip.extractElement(arg_vector, index_i32, ""); + const result_ptr = if (fn_info.return_type == .void_type) .none else result_ptr: { + const ret_llvm_ty = try o.lowerType(ret_ty, .in_memory); + break :result_ptr try fg.buildAlloca( + if (vector_len) |len| try o.builder.arrayType(len, ret_llvm_ty) else ret_llvm_ty, + ret_ty.abiAlignment(zcu).toLlvm(), + ); + }; + _ = try fg.wip.br(loop_block); + + fg.wip.cursor = .{ .block = loop_block }; + const index = try fg.wip.phi(.i32, "elementwise.index"); + + var arg_elems_buf: [3]Builder.Value = undefined; + const arg_elems = arg_elems_buf[0..arg_values.len]; + for (arg_elems, fn_info.param_types, arg_values) |*arg_elem, param_type, arg_value| { + const arg_elem_ptr = try fg.ptraddScaled(arg_value, index.toValue(), Type.fromInterned(param_type).abiSize(zcu)); + arg_elem.* = try fg.load(arg_elem_ptr, .none, .fromInterned(param_type), .normal); + } + const result_elem = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, arg_elems); + if (fn_info.return_type == .void_type) { + assert(result_elem == .none); + } else if (result_elem != .none) { + const result_elem_ptr = try fg.ptraddScaled(result_ptr, index.toValue(), ret_ty.abiSize(zcu)); + try fg.store(result_elem_ptr, .none, result_elem, ret_ty, .normal); } - const result_elem = try self.wip.call( - .normal, - .ccc, - .none, - llvm_fn.typeOf(&o.builder), - llvm_fn.toValue(&o.builder), - args[0..args_vectors.len], - "", + + const next_index = try fg.wip.bin(.@"add nuw", index.toValue(), try o.builder.intValue(.i32, 1), "elementwise.next_index"); + index.finish(&.{ try o.builder.intValue(.i32, 0), next_index }, &.{ entry_block, loop_block }, &fg.wip); + const is_done = try fg.wip.icmp(.eq, next_index, try o.builder.intValue(.i32, iterations), "elementwise.is_done"); + _ = try fg.wip.brCond(is_done, done_block, loop_block, .none); + + fg.wip.cursor = .{ .block = done_block }; + return result_ptr; + } + + var result = if (fn_info.return_type == .void_type) .none else if (ret_is_by_ref) result: { + const ret_llvm_ty = try o.lowerType(ret_ty, .in_memory); + break :result try fg.buildAlloca( + if (vector_len) |len| try o.builder.arrayType(len, ret_llvm_ty) else ret_llvm_ty, + ret_ty.abiAlignment(zcu).toLlvm(), ); - result = try self.wip.insertElement(result, result_elem, index_i32, ""); + } else if (vector_len) |len| try o.builder.poisonValue( + try o.builder.vectorType(.normal, len, try o.lowerType(ret_ty, .as_value)), + ) else .none; + for (0..iterations) |index| { + const index_value = try o.builder.intValue(.i32, index); + var arg_elems_buf: [3]Builder.Value = undefined; + const arg_elems = arg_elems_buf[0..arg_values.len]; + for (arg_elems, fn_info.param_types, arg_values) |*arg_elem_value, param_type, arg_value| { + const arg_ty: Type = .fromInterned(param_type); + if (isByRef(arg_ty, zcu)) { + const arg_elem_ptr = try fg.ptraddConst(arg_value, index * arg_ty.abiSize(zcu)); + arg_elem_value.* = try fg.load(arg_elem_ptr, .none, .fromInterned(param_type), .normal); + } else if (vector_len) |_| { + arg_elem_value.* = try fg.wip.extractElement(arg_value, index_value, "elementwise.arg_elem"); + } else arg_elem_value.* = arg_value; + } + const result_elem = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, arg_elems); + if (fn_info.return_type == .void_type) { + assert(result_elem == .none); + } else if (ret_is_by_ref) { + const result_elem_ptr = try fg.ptraddConst(result, index * ret_ty.abiSize(zcu)); + try fg.store(result_elem_ptr, .none, result_elem, ret_ty, .normal); + } else if (vector_len) |_| { + result = try fg.wip.insertElement(result, result_elem, index_value, "elementwise.result"); + } else { + assert(result == .none); + result = result_elem; + } } return result; } @@ -3853,19 +3876,18 @@ fn buildElementwiseCall( /// Creates a floating point comparison by lowering to the appropriate /// hardware instruction or softfloat routine for the target fn buildFloatCmp( - self: *FuncGen, + fg: *FuncGen, fast: Builder.FastMathKind, pred: math.CompareOperator, ty: Type, params: [2]Builder.Value, ) Allocator.Error!Builder.Value { - const o = self.object; + const o = fg.object; const zcu = o.zcu; const target = zcu.getTarget(); const scalar_ty = ty.scalarType(zcu); - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - if (intrinsicsAllowed(scalar_ty, target)) { + if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) { const cond: Builder.FloatCondition = switch (pred) { .eq => .oeq, .neq => .une, @@ -3874,53 +3896,33 @@ fn buildFloatCmp( .gt => .ogt, .gte => .oge, }; - return self.wip.fcmp(fast, cond, params[0], params[1], ""); + return fg.wip.fcmp(fast, cond, params[0], params[1], ""); } - const float_bits = scalar_ty.floatBits(target); - const compiler_rt_float_abbrev = compilerRtFloatAbbrev(float_bits); - const fn_base_name = switch (pred) { - .neq => "ne", - .eq => "eq", - .lt => "lt", - .lte => "le", - .gt => "gt", - .gte => "ge", - }; - const fn_name = try o.builder.strtabStringFmt("__{s}{s}f2", .{ fn_base_name, compiler_rt_float_abbrev }); - - const libc_fn = try o.getLibcFunction(fn_name, &.{ scalar_llvm_ty, scalar_llvm_ty }, .i32); - - const int_cond: Builder.IntegerCondition = switch (pred) { + const fn_name = try o.builder.strtabStringFmt("__{s}{s}f2", .{ + switch (pred) { + .neq => "ne", + .eq => "eq", + .lt => "lt", + .lte => "le", + .gt => "gt", + .gte => "ge", + }, + compilerRtFloatAbbrev(target, scalar_ty.floatBits(target)), + }); + const result = try fg.buildElementwiseCall(fn_name, .{ + .cc = target.cCallingConvention().?, + .param_types = &.{ scalar_ty.toIntern(), scalar_ty.toIntern() }, + .return_type = .i32_type, + }, ¶ms, if (ty.isVector(zcu)) ty.vectorLen(zcu) else null); + return fg.wip.icmp(switch (pred) { .eq => .eq, .neq => .ne, .lt => .slt, .lte => .sle, .gt => .sgt, .gte => .sge, - }; - - if (ty.zigTypeTag(zcu) == .vector) { - const vec_len = ty.vectorLen(zcu); - const vector_result_ty = try o.builder.vectorType(.normal, vec_len, .i32); - - const init = try o.builder.poisonValue(vector_result_ty); - const result = try self.buildElementwiseCall(libc_fn, ¶ms, init, vec_len); - - const zero_vector = try o.builder.splatValue(vector_result_ty, .@"0"); - return self.wip.icmp(int_cond, result, zero_vector, ""); - } - - const result = try self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - ¶ms, - "", - ); - return self.wip.icmp(int_cond, result, .@"0", ""); + }, result, try o.builder.splatValue(result.typeOfWip(&fg.wip), .@"0"), ""); } const FloatOp = enum { @@ -3949,32 +3951,30 @@ const FloatOp = enum { trunc, }; -const FloatOpStrat = union(enum) { - intrinsic: []const u8, - libc: Builder.String, -}; - /// Creates a floating point operation (add, sub, fma, sqrt, exp, etc.) /// by lowering to the appropriate hardware instruction or softfloat /// routine for the target fn buildFloatOp( - self: *FuncGen, + fg: *FuncGen, comptime op: FloatOp, fast: Builder.FastMathKind, ty: Type, comptime params_len: usize, params: [params_len]Builder.Value, ) Allocator.Error!Builder.Value { - const o = self.object; + const o = fg.object; const zcu = o.zcu; const target = zcu.getTarget(); const scalar_ty = ty.scalarType(zcu); - const llvm_ty = try o.lowerType(ty, .by_value); - if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) { + switch (op) { // Some operations are dedicated LLVM instructions, not available as intrinsics - .neg => return self.wip.un(.fneg, params[0], ""), - .add, .sub, .mul, .div, .fmod => return self.wip.bin(switch (fast) { + .neg => if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) return fg.wip.un(.fneg, params[0], ""), + .add, .sub, .mul, .div, .fmod => if (intrinsicsAllowed(switch (op) { + else => unreachable, + .add, .sub, .mul, .div => .compiler_rt, + .fmod => .libc, + }, scalar_ty, target)) return fg.wip.bin(switch (fast) { .normal => switch (op) { .add => .fadd, .sub => .fsub, @@ -3992,6 +3992,7 @@ fn buildFloatOp( else => unreachable, }, }, params[0], params[1], ""), + .fma, .fmax, .fmin, .ceil, @@ -4006,9 +4007,10 @@ fn buildFloatOp( .round, .sin, .sqrt, + .tan, .trunc, - .fma, - => return self.wip.callIntrinsic(fast, .none, switch (op) { + => if (intrinsicsAllowed(.libc, scalar_ty, target)) return fg.wip.callIntrinsic(fast, .none, switch (op) { + .fma => .fma, .fmax => .maxnum, .fmin => .minnum, .ceil => .ceil, @@ -4023,39 +4025,154 @@ fn buildFloatOp( .round => .round, .sin => .sin, .sqrt => .sqrt, + .tan => .tan, .trunc => .trunc, - .fma => .fma, else => unreachable, - }, &.{llvm_ty}, ¶ms, ""), - .tan => unreachable, - }; + }, &.{try o.lowerType(ty, .as_value)}, ¶ms, ""), + } const float_bits = scalar_ty.floatBits(target); const fn_name = switch (op) { - .neg => { - // In this case we can generate a softfloat negation by XORing the - // bits with a constant. + // In these cases we can generate a softfloat operation by modifying the sign bit using a bitwise operation. + .neg, .fabs => if (isByRef(scalar_ty, zcu)) { + const is_vector = ty.toIntern() != scalar_ty.toIntern(); + const result_ptr = try fg.buildZigAlloca(ty, .none); + const entry_block = fg.wip.cursor.block; + const loop_block, const done_block, const llvm_usize_ty, const offset, const elem, const result_elem = if (is_vector) loop: { + const loop_block = try fg.wip.block(2, "neg_fabs.loop"); + const done_block = try fg.wip.block(1, "neg_fabs.done"); + _ = try fg.wip.br(loop_block); + + fg.wip.cursor = .{ .block = loop_block }; + const llvm_usize_ty = try o.lowerType(.usize, .as_value); + const offset = try fg.wip.phi(llvm_usize_ty, "neg_fabs.offset"); + break :loop .{ + loop_block, + done_block, + llvm_usize_ty, + offset, + try fg.ptraddScaled(params[0], offset.toValue(), 1), + try fg.ptraddScaled(result_ptr, offset.toValue(), 1), + }; + } else .{ undefined, undefined, undefined, undefined, params[0], result_ptr }; + switch (scalar_ty.floatBits(target)) { + else => unreachable, + 80 => { + const f80_layout = o.softF80Layout(.{}) catch unreachable; + const mantissa = try fg.load( + try fg.ptraddConst(elem, f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + .u64, + .normal, + ); + const exponent = try fg.load( + try fg.ptraddConst(elem, f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + .u16, + .normal, + ); + const exponent_sign_bit: u16 = 1 << (16 - 1); + const updated_exponent = try fg.wip.bin(switch (op) { + else => unreachable, + .neg => .xor, + .fabs => .@"and", + }, exponent, try o.builder.intValue(.i16, switch (op) { + else => unreachable, + .neg => exponent_sign_bit, + .fabs => exponent_sign_bit - 1, + }), "neg_fabs.updated_exponent"); + try fg.store( + try fg.ptraddConst(result_elem, f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + mantissa, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_elem, f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + updated_exponent, + .u16, + .normal, + ); + }, + 128 => { + const f128_layout = o.softF128Layout(.{}) catch unreachable; + const lo = try fg.load( + try fg.ptraddConst(elem, f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + .u64, + .normal, + ); + const hi = try fg.load( + try fg.ptraddConst(elem, f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + .u64, + .normal, + ); + const hi_sign_bit: u64 = 1 << (64 - 1); + const updated_hi = try fg.wip.bin(switch (op) { + else => unreachable, + .neg => .xor, + .fabs => .@"and", + }, hi, try o.builder.intValue(.i64, switch (op) { + else => unreachable, + .neg => hi_sign_bit, + .fabs => hi_sign_bit - 1, + }), "neg_fabs.updated_hi"); + try fg.store( + try fg.ptraddConst(result_elem, f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + lo, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_elem, f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + updated_hi, + .u64, + .normal, + ); + }, + } + if (is_vector) { + const next_offset = try fg.wip.bin(.@"add nuw", offset.toValue(), try o.builder.intValue(llvm_usize_ty, scalar_ty.abiSize(zcu)), "neg_fabs.next_offset"); + offset.finish(&.{ try o.builder.intValue(llvm_usize_ty, 0), next_offset }, &.{ entry_block, loop_block }, &fg.wip); + const is_done = try fg.wip.icmp(.eq, next_offset, try o.builder.intValue(llvm_usize_ty, ty.abiSize(zcu)), "neg_fabs.is_done"); + _ = try fg.wip.brCond(is_done, done_block, loop_block, .none); + + fg.wip.cursor = .{ .block = done_block }; + } + return result_ptr; + } else { const int_ty = try o.builder.intType(@intCast(float_bits)); const cast_ty = switch (ty.zigTypeTag(zcu)) { .vector => try o.builder.vectorType(.normal, ty.vectorLen(zcu), int_ty), else => int_ty, }; - const sign_mask = try o.builder.splatValue( - cast_ty, - try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)), - ); - const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, ""); - const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, ""); - return self.wip.cast(.bitcast, result, llvm_ty, ""); + const sign_bit = @as(u128, 1) << @intCast(float_bits - 1); + const bitwise_rhs = try o.builder.splatValue(cast_ty, try o.builder.intConst(int_ty, switch (op) { + else => unreachable, + .neg => sign_bit, + .fabs => sign_bit - 1, + })); + const bitcasted_operand = try fg.wip.cast(.bitcast, params[0], cast_ty, ""); + const result = try fg.wip.bin(switch (op) { + else => unreachable, + .neg => .xor, + .fabs => .@"and", + }, bitcasted_operand, bitwise_rhs, ""); + const llvm_ty = try o.lowerType(ty, .as_value); + return fg.wip.cast(.bitcast, result, llvm_ty, ""); }, .add, .sub, .div, .mul => try o.builder.strtabStringFmt("__{s}{s}f3", .{ - @tagName(op), compilerRtFloatAbbrev(float_bits), + @tagName(op), compilerRtFloatAbbrev(target, float_bits), }), .ceil, .cos, .exp, .exp2, - .fabs, .floor, .fma, .fmax, @@ -4073,27 +4190,27 @@ fn buildFloatOp( libcFloatPrefix(float_bits), @tagName(op), libcFloatSuffix(float_bits), }), }; + return fg.buildElementwiseCall(fn_name, .{ + .cc = target.cCallingConvention().?, + .param_types = &@as([params_len]InternPool.Index, @splat(scalar_ty.toIntern())), + .return_type = scalar_ty.toIntern(), + }, ¶ms, if (ty.isVector(zcu)) ty.vectorLen(zcu) else null); +} - const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); - const libc_fn = try o.getLibcFunction( - fn_name, - @as([3]Builder.Type, @splat(scalar_llvm_ty))[0..params.len], - scalar_llvm_ty, - ); - if (ty.zigTypeTag(zcu) == .vector) { - const result = try o.builder.poisonValue(llvm_ty); - return self.buildElementwiseCall(libc_fn, ¶ms, result, ty.vectorLen(zcu)); - } - - return self.wip.call( - fast.toCallKind(), - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - ¶ms, - "", - ); +/// Creates a floating point cast operation by lowering to the specified softfloat routine. +fn buildFloatCastCall( + fg: *FuncGen, + dest_ty: Type, + fn_name: Builder.StrtabString, + operand_ty: Type, + operand: Builder.Value, +) Allocator.Error!Builder.Value { + const zcu = fg.object.zcu; + return fg.buildElementwiseCall(fn_name, .{ + .cc = zcu.getTarget().cCallingConvention().?, + .param_types = &.{operand_ty.scalarType(zcu).toIntern()}, + .return_type = dest_ty.scalarType(zcu).toIntern(), + }, &.{operand}, if (operand_ty.isVector(zcu)) operand_ty.vectorLen(zcu) else null); } fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -4129,7 +4246,7 @@ fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Buil const dest_ty = self.typeOfIndex(inst); assert(isByRef(dest_ty, zcu)); // auto structs are by-ref - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .as_value), ""); const result = try self.wip.bin(.shl, lhs, casted_rhs, ""); const reconstructed = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(zcu)) @@ -4196,7 +4313,7 @@ fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val } const lhs_scalar_ty = lhs_ty.scalarType(zcu); - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .as_value), ""); return self.wip.bin(if (lhs_scalar_ty.isSignedInt(zcu)) .@"shl nsw" else @@ -4217,7 +4334,7 @@ fn airShl(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { // features which we do not use. Therefore this branch is currently impossible. unreachable; } - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .as_value), ""); return self.wip.bin(.shl, lhs, casted_rhs, ""); } @@ -4231,8 +4348,8 @@ fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const lhs_ty = self.typeOf(bin_op.lhs); const lhs_info = lhs_ty.intInfo(zcu); - const llvm_lhs_ty = try o.lowerType(lhs_ty, .by_value); - const llvm_lhs_scalar_ty = try o.lowerType(lhs_ty.scalarType(zcu), .by_value); + const llvm_lhs_ty = try o.lowerType(lhs_ty, .as_value); + const llvm_lhs_scalar_ty = try o.lowerType(lhs_ty.scalarType(zcu), .as_value); const rhs_ty = self.typeOf(bin_op.rhs); if (lhs_ty.isVector(zcu) and !rhs_ty.isVector(zcu)) { @@ -4242,8 +4359,8 @@ fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value } const rhs_info = rhs_ty.intInfo(zcu); assert(rhs_info.signedness == .unsigned); - const llvm_rhs_ty = try o.lowerType(rhs_ty, .by_value); - const llvm_rhs_scalar_ty = try o.lowerType(rhs_ty.scalarType(zcu), .by_value); + const llvm_rhs_ty = try o.lowerType(rhs_ty, .as_value); + const llvm_rhs_scalar_ty = try o.lowerType(rhs_ty.scalarType(zcu), .as_value); const result = try self.wip.callIntrinsic( .normal, @@ -4319,7 +4436,7 @@ fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) Allocator.Error! } const lhs_scalar_ty = lhs_ty.scalarType(zcu); - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .as_value), ""); const is_signed_int = lhs_scalar_ty.isSignedInt(zcu); return self.wip.bin(if (is_exact) @@ -4340,7 +4457,7 @@ fn airAbs(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { .normal, .none, .abs, - &.{try o.lowerType(operand_ty, .by_value)}, + &.{try o.lowerType(operand_ty, .as_value)}, &.{ operand, .false }, "", ), @@ -4354,7 +4471,7 @@ fn airIntCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! const zcu = o.zcu; const ty_op = fg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const dest_ty = fg.typeOfIndex(inst); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); + const dest_llvm_ty = try o.lowerType(dest_ty, .as_value); const operand = try fg.resolveInst(ty_op.operand); const operand_ty = fg.typeOf(ty_op.operand); const operand_info = operand_ty.intInfo(zcu); @@ -4382,8 +4499,8 @@ fn airIntCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! if (!have_min_check and !have_max_check) break :bounds_check; - const operand_llvm_ty = try o.lowerType(operand_ty, .by_value); - const operand_scalar_llvm_ty = try o.lowerType(operand_scalar, .by_value); + const operand_llvm_ty = try o.lowerType(operand_ty, .as_value); + const operand_scalar_llvm_ty = try o.lowerType(operand_scalar, .as_value); const is_vector = operand_ty.zigTypeTag(zcu) == .vector; assert(is_vector == (dest_ty.zigTypeTag(zcu) == .vector)); @@ -4461,7 +4578,7 @@ fn airIntCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); - const dest_llvm_ty = try self.object.lowerType(self.typeOfIndex(inst), .by_value); + const dest_llvm_ty = try self.object.lowerType(self.typeOfIndex(inst), .as_value); return self.wip.cast(.trunc, operand, dest_llvm_ty, ""); } @@ -4471,32 +4588,20 @@ fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.typeOf(ty_op.operand); + const operand_scalar_ty = operand_ty.scalarType(zcu); const dest_ty = self.typeOfIndex(inst); + const dest_scalar_ty = dest_ty.scalarType(zcu); const target = zcu.getTarget(); - if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) { - return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .by_value), ""); - } else { - const operand_llvm_ty = try o.lowerType(operand_ty, .by_value); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); - - const dest_bits = dest_ty.floatBits(target); - const src_bits = operand_ty.floatBits(target); - const fn_name = try o.builder.strtabStringFmt("__trunc{s}f{s}f2", .{ - compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits), - }); - - const libc_fn = try o.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty); - return self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - &.{operand}, - "", - ); - } + if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target) and + intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target)) + return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .as_value), ""); + const dest_bits = dest_scalar_ty.floatBits(target); + const src_bits = operand_scalar_ty.floatBits(target); + const fn_name = try o.builder.strtabStringFmt("__trunc{s}f{s}f2", .{ + compilerRtFloatAbbrev(target, src_bits), compilerRtFloatAbbrev(target, dest_bits), + }); + return self.buildFloatCastCall(dest_ty, fn_name, operand_ty, operand); } fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -4505,38 +4610,20 @@ fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.typeOf(ty_op.operand); + const operand_scalar_ty = operand_ty.scalarType(zcu); const dest_ty = self.typeOfIndex(inst); + const dest_scalar_ty = dest_ty.scalarType(zcu); const target = zcu.getTarget(); - if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) { - return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .by_value), ""); - } else { - const operand_llvm_ty = try o.lowerType(operand_ty, .by_value); - const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); - - const dest_bits = dest_ty.scalarType(zcu).floatBits(target); - const src_bits = operand_ty.scalarType(zcu).floatBits(target); - const fn_name = try o.builder.strtabStringFmt("__extend{s}f{s}f2", .{ - compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits), - }); - - const libc_fn = try o.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty); - if (dest_ty.isVector(zcu)) return self.buildElementwiseCall( - libc_fn, - &.{operand}, - try o.builder.poisonValue(dest_llvm_ty), - dest_ty.vectorLen(zcu), - ); - return self.wip.call( - .normal, - .ccc, - .none, - libc_fn.typeOf(&o.builder), - libc_fn.toValue(&o.builder), - &.{operand}, - "", - ); - } + if (intrinsicsAllowed(.compiler_rt, dest_scalar_ty, target) and + intrinsicsAllowed(.compiler_rt, operand_scalar_ty, target)) + return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .as_value), ""); + const dest_bits = dest_scalar_ty.floatBits(target); + const src_bits = operand_scalar_ty.floatBits(target); + const fn_name = try o.builder.strtabStringFmt("__extend{s}f{s}f2", .{ + compilerRtFloatAbbrev(target, src_bits), compilerRtFloatAbbrev(target, dest_bits), + }); + return self.buildFloatCastCall(dest_ty, fn_name, operand_ty, operand); } fn airBitCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Builder.Value { @@ -4558,12 +4645,145 @@ fn airBitCast(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! // * bool/int/float <-> bool/int/float // * `@Vector(n, A)` <-> `@Vector(n, B)` // - // All of these cases can be handled by LLVM's `bitcast` instruction. + // Most of these cases can be handled by LLVM's `bitcast` instruction, except when + // a non-native type like `f80` is used. - assert(!isByRef(operand_ty, zcu)); - assert(!isByRef(dest_ty, zcu)); + if (isByRef(operand_ty, zcu)) { + const operand_scalar_ty = operand_ty.scalarType(zcu); + const target = zcu.getTarget(); + const bits = operand_scalar_ty.floatBits(target); + const dest_scalar_ty = dest_ty.scalarType(zcu); + if (isByRef(dest_ty, zcu)) { + assert(dest_scalar_ty.floatBits(target) == bits); + return operand; + } + assert(dest_scalar_ty.intInfo(zcu).bits == bits); - const llvm_dest_ty = try o.lowerType(dest_ty, .by_value); + const len = if (operand_ty.toIntern() != operand_scalar_ty.toIntern()) + operand_ty.vectorLen(zcu) + else + null; + const operand_scalar_size = operand_scalar_ty.abiSize(zcu); + var result = if (len) |_| + try o.builder.poisonValue(try o.lowerType(dest_ty, .as_value)) + else + undefined; + for (0..len orelse 1) |index| { + const result_elem = result_elem: switch (bits) { + else => unreachable, + 80 => { + const f80_layout = o.softF80Layout(.{}) catch unreachable; + const mantissa = try fg.load( + try fg.ptraddConst(operand, operand_scalar_size * index + f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + .u64, + .normal, + ); + const exponent = try fg.load( + try fg.ptraddConst(operand, operand_scalar_size * index + f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + .u16, + .normal, + ); + const casted_mantissa = try fg.wip.cast(.zext, mantissa, .i80, "bitCast.casted_mantissa"); + const casted_exponent = try fg.wip.cast(.zext, exponent, .i80, "bitCast.casted_exponent"); + const shifted_exponent = try fg.wip.bin(.@"shl nuw", casted_exponent, try o.builder.intValue(.i80, 64), "bitCast.shifted_exponent"); + break :result_elem try fg.wip.bin(.@"or", casted_mantissa, shifted_exponent, "bitCast.result_elem"); + }, + 128 => { + const f128_layout = o.softF128Layout(.{}) catch unreachable; + const lo = try fg.load( + try fg.ptraddConst(operand, operand_scalar_size * index + f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + .u64, + .normal, + ); + const hi = try fg.load( + try fg.ptraddConst(operand, operand_scalar_size * index + f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + .u64, + .normal, + ); + const casted_lo = try fg.wip.cast(.zext, lo, .i128, "bitCast.casted_lo"); + const casted_hi = try fg.wip.cast(.zext, hi, .i128, "bitCast.casted_hi"); + const shifted_hi = try fg.wip.bin(.@"shl nuw", casted_hi, try o.builder.intValue(.i128, 64), "bitCast.shifted_hi"); + break :result_elem try fg.wip.bin(.@"or", casted_lo, shifted_hi, "bitCast.result_elem"); + }, + }; + result = if (len) |_| + try fg.wip.insertElement(result, result_elem, try o.builder.intValue(.i32, index), "elementwise.result") + else + result_elem; + } + return result; + } + + if (isByRef(dest_ty, zcu)) { + const dest_scalar_ty = dest_ty.scalarType(zcu); + const bits = dest_scalar_ty.floatBits(zcu.getTarget()); + assert(dest_scalar_ty.isRuntimeFloat()); + const operand_scalar_ty = operand_ty.scalarType(zcu); + assert(operand_scalar_ty.intInfo(zcu).bits == bits); + + const len = if (operand_ty.toIntern() != operand_scalar_ty.toIntern()) + operand_ty.vectorLen(zcu) + else + null; + const operand_scalar_size = operand_scalar_ty.abiSize(zcu); + const result_ptr = try fg.buildZigAlloca(dest_ty, .none); + for (0..len orelse 1) |index| { + const operand_elem = if (len) |_| + try fg.wip.extractElement(operand, try o.builder.intValue(.i32, index), "elementwise.operand_elem") + else + operand; + switch (bits) { + else => unreachable, + 80 => { + const f80_layout = o.softF80Layout(.{}) catch unreachable; + const mantissa = try fg.wip.cast(.trunc, operand_elem, .i64, "bitCast.mantissa"); + const shifted_exponent = try fg.wip.bin(.lshr, operand_elem, try o.builder.intValue(.i80, 64), "bitCast.shifted_exponent"); + const exponent = try fg.wip.cast(.@"trunc nuw", shifted_exponent, .i16, "bitCast.exponent"); + try fg.store( + try fg.ptraddConst(result_ptr, operand_scalar_size * index + f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + mantissa, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_ptr, operand_scalar_size * index + f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + exponent, + .u16, + .normal, + ); + }, + 128 => { + const f128_layout = o.softF128Layout(.{}) catch unreachable; + const lo = try fg.wip.cast(.trunc, operand_elem, .i64, "bitCast.lo"); + const shifted_hi = try fg.wip.bin(.lshr, operand_elem, try o.builder.intValue(.i128, 64), "bitCast.shifted_hi"); + const hi = try fg.wip.cast(.@"trunc nuw", shifted_hi, .i64, "bitCast.hi"); + try fg.store( + try fg.ptraddConst(result_ptr, operand_scalar_size * index + f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + lo, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_ptr, operand_scalar_size * index + f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + hi, + .u64, + .normal, + ); + }, + } + } + return result_ptr; + } + + const llvm_dest_ty = try o.lowerType(dest_ty, .as_value); const result = try fg.wip.cast(.bitcast, operand, llvm_dest_ty, ""); if (safety and dest_ty.zigTypeTag(zcu) == .@"enum" and !dest_ty.isNonexhaustiveEnum(zcu)) { const llvm_fn = try o.getIsNamedEnumValueFunction(dest_ty); @@ -4606,7 +4826,7 @@ fn airPtrFromInt(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val assert(dest_ty.scalarType(zcu).isPtrAtRuntime(zcu)); const operand = try fg.resolveInst(ty_op.operand); - const llvm_dest_ty = try o.lowerType(dest_ty, .by_value); + const llvm_dest_ty = try o.lowerType(dest_ty, .as_value); return fg.wip.cast(.inttoptr, operand, llvm_dest_ty, ""); } @@ -4620,7 +4840,7 @@ fn airIntFromPtr(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val assert(dest_ty.scalarType(zcu).toIntern() == .usize_type); const operand = try fg.resolveInst(ty_op.operand); - const llvm_dest_ty = try o.lowerType(dest_ty, .by_value); + const llvm_dest_ty = try o.lowerType(dest_ty, .as_value); return fg.wip.cast(.ptrtoint, operand, llvm_dest_ty, ""); } @@ -4689,7 +4909,7 @@ fn airArg(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { }, "", ); - } else if (mod.optimize_mode == .Debug) { + } else if (mod.optimize_mode == .debug) { const alloca = try self.buildZigAlloca(inst_ty, .none); try self.store(alloca, .none, arg_val, inst_ty, .normal); _ = try self.wip.callIntrinsic( @@ -4730,7 +4950,7 @@ fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ptr_align = ptr_ty.ptrAlignment(zcu); const elem_ty = ptr_ty.childType(zcu); if (!elem_ty.hasRuntimeBits(zcu)) { - return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue(); + return (try o.lowerPtrToVoid(ptr_align.toLlvm(), ptr_ty.ptrAddressSpace(zcu))).toValue(); } return self.buildZigAlloca(elem_ty, ptr_align); } @@ -4743,7 +4963,7 @@ fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ptr_align = ptr_ty.ptrAlignment(zcu); const elem_ty = ptr_ty.childType(zcu); if (!elem_ty.hasRuntimeBits(zcu)) { - return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue(); + return (try o.lowerPtrToVoid(ptr_align.toLlvm(), ptr_ty.ptrAddressSpace(zcu))).toValue(); } return self.buildZigAlloca(elem_ty, ptr_align); } @@ -4754,10 +4974,7 @@ fn buildZigAlloca(fg: *FuncGen, ty: Type, @"align": InternPool.Alignment) Alloca .none => ty.abiAlignment(o.zcu), else => |a| a, }; - return fg.buildAlloca( - try o.lowerType(ty, .in_memory), - resolved_align.toLlvm(), - ); + return fg.buildAlloca(try o.lowerType(ty, .in_memory), resolved_align.toLlvm()); } /// Unlike `WipFunction.alloca`, this puts the alloca instruction at the top of the function. @@ -4820,7 +5037,7 @@ fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Bu // unexpected call in the user's code. This is problematic if the code in question is // not ready to correctly make calls yet, such as in our early PIE startup code, or in // the early stages of a dynamic linker, etc. - if (!safety and owner_mod.optimize_mode == .Debug) { + if (!safety and owner_mod.optimize_mode == .debug) { return .none; } @@ -4832,7 +5049,7 @@ fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Bu return .none; } - const len = try o.builder.intValue(try o.lowerType(.usize, .by_value), elem_ty.abiSize(zcu)); + const len = try o.builder.intValue(try o.lowerType(.usize, .as_value), elem_ty.abiSize(zcu)); _ = try fg.wip.callMemSet( ptr, ptr_alignment.toLlvm(), @@ -4850,24 +5067,31 @@ fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Bu const elem = try fg.resolveInst(bin_op.rhs); if (ptr_info.flags.vector_index != .none) { - // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. - const vec_ty = try fg.pt.vectorType(.{ - .len = ptr_info.packed_offset.host_size, - .child = elem_ty.toIntern(), - }); + if (isByRef(elem_ty, zcu)) { + const offset = @backingInt(ptr_info.flags.vector_index) * elem_ty.abiSize(zcu); + const elem_ptr = try fg.ptraddConst(ptr, offset); + try fg.store(elem_ptr, ptr_alignment.offset(offset), elem, elem_ty, access_kind); + } else { + // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. + const vec_ty = try fg.pt.vectorType(.{ + .len = ptr_info.packed_offset.host_size, + .child = elem_ty.toIntern(), + }); - const loaded_vector = try fg.load(ptr, ptr_alignment, vec_ty, access_kind); - const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index); - const modified_vector = try fg.wip.insertElement(loaded_vector, elem, index_val, ""); + const loaded_vector = try fg.load(ptr, ptr_alignment, vec_ty, access_kind); + const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index); + const modified_vector = try fg.wip.insertElement(loaded_vector, elem, index_val, ""); + + try fg.store(ptr, ptr_alignment, modified_vector, vec_ty, access_kind); + } - try fg.store(ptr, ptr_alignment, modified_vector, vec_ty, access_kind); return .none; } if (ptr_info.packed_offset.host_size != 0) { // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. const backing_int_ty = try fg.pt.intType(.unsigned, @intCast(ptr_info.packed_offset.host_size * 8)); - const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .by_value); + const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .as_value); const backing_int_val = try fg.load(ptr, ptr_alignment, backing_int_ty, access_kind); @@ -4927,32 +5151,98 @@ fn airLoad(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { if (ptr_info.flags.is_volatile) .@"volatile" else .normal; if (ptr_info.flags.vector_index != .none) { - // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. - const vec_ty = try fg.pt.vectorType(.{ - .len = ptr_info.packed_offset.host_size, - .child = elem_ty.toIntern(), - }); - const vector_val = try fg.load(ptr, ptr_align, vec_ty, access_kind); - const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index); - return fg.wip.extractElement(vector_val, index_val, ""); + if (isByRef(elem_ty, zcu)) { + const elem_size = elem_ty.abiSize(zcu); + const offset = @backingInt(ptr_info.flags.vector_index) * elem_size; + const elem_ptr = try fg.ptraddConst(ptr, offset); + return fg.load(elem_ptr, ptr_align.offset(offset), elem_ty, access_kind); + } else { + // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. + const vec_ty = try fg.pt.vectorType(.{ + .len = ptr_info.packed_offset.host_size, + .child = elem_ty.toIntern(), + }); + const vector_val = try fg.load(ptr, ptr_align, vec_ty, access_kind); + const index_val = try o.builder.intValue(.i32, ptr_info.flags.vector_index); + return fg.wip.extractElement(vector_val, index_val, ""); + } } if (ptr_info.packed_offset.host_size == 0) { return fg.load(ptr, ptr_align, elem_ty, access_kind); } - assert(!isByRef(elem_ty, zcu)); // all packable types are by-val - // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate this usage of `pt`. const backing_int_ty = try fg.pt.intType(.unsigned, @intCast(ptr_info.packed_offset.host_size * 8)); - const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .by_value); + const llvm_backing_int_ty = try o.lowerType(backing_int_ty, .as_value); const backing_int_val = try fg.load(ptr, ptr_align, backing_int_ty, .normal); const elem_bits = ptr_ty.childType(zcu).bitSize(zcu); const shift_amt = try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset); const shifted_value = try fg.wip.bin(.lshr, backing_int_val, shift_amt, ""); - const elem_llvm_ty = try o.lowerType(elem_ty, .by_value); + + if (isByRef(elem_ty, zcu)) { + const result_ptr = try fg.buildZigAlloca(elem_ty, .none); + switch (elem_ty.floatBits(zcu.getTarget())) { + else => unreachable, + 80 => { + const f80_layout = o.softF80Layout(.{}) catch unreachable; + const mantissa = try fg.wip.cast(.trunc, shifted_value, .i64, "load.mantissa"); + const shifted_exponent = try fg.wip.bin( + .lshr, + backing_int_val, + try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset + 64), + "load.shifted_exponent", + ); + const exponent = try fg.wip.cast(.trunc, shifted_exponent, .i16, "load.exponent"); + + try fg.store( + try fg.ptraddConst(result_ptr, f80_layout.mantissa_offset), + f80_layout.alignment.offset(f80_layout.mantissa_offset), + mantissa, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_ptr, f80_layout.exponent_offset), + f80_layout.alignment.offset(f80_layout.exponent_offset), + exponent, + .u16, + .normal, + ); + }, + 128 => { + const f128_layout = o.softF128Layout(.{}) catch unreachable; + const lo = try fg.wip.cast(.trunc, shifted_value, .i64, "load.lo"); + const shifted_hi = try fg.wip.bin( + .lshr, + backing_int_val, + try o.builder.intValue(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset + 64), + "load.shifted_hi", + ); + const hi = try fg.wip.cast(.trunc, shifted_hi, .i64, "load.hi"); + + try fg.store( + try fg.ptraddConst(result_ptr, f128_layout.lo_offset), + f128_layout.alignment.offset(f128_layout.lo_offset), + lo, + .u64, + .normal, + ); + try fg.store( + try fg.ptraddConst(result_ptr, f128_layout.hi_offset), + f128_layout.alignment.offset(f128_layout.hi_offset), + hi, + .u64, + .normal, + ); + }, + } + return result_ptr; + } + + const elem_llvm_ty = try o.lowerType(elem_ty, .as_value); if (elem_ty.zigTypeTag(zcu) == .float or elem_ty.zigTypeTag(zcu) == .vector) { const same_size_int = try o.builder.intType(@intCast(elem_bits)); @@ -5002,7 +5292,7 @@ fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.V fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { _ = inst; const o = self.object; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); if (!target_util.supportsReturnAddress(self.object.zcu.getTarget(), self.ownerModule().optimize_mode)) { // https://github.com/ziglang/zig/issues/11946 return o.builder.intValue(llvm_usize, 0); @@ -5014,7 +5304,7 @@ fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { _ = inst; const result = try self.wip.callIntrinsic(.normal, .none, .frameaddress, &.{.ptr}, &.{.@"0"}, ""); - return self.wip.cast(.ptrtoint, result, try self.object.lowerType(.usize, .by_value), ""); + return self.wip.cast(.ptrtoint, result, try self.object.lowerType(.usize, .as_value), ""); } fn airCmpxchg( @@ -5031,7 +5321,7 @@ fn airCmpxchg( var expected_value = try self.resolveInst(extra.expected_value); var new_value = try self.resolveInst(extra.new_value); const operand_ty = ptr_ty.childType(zcu); - const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); + const llvm_operand_ty = try o.lowerType(operand_ty, .as_value); const llvm_abi_ty = try self.getAtomicAbiType(operand_ty, false); if (llvm_abi_ty != .none) { // operand needs widening and truncating @@ -5101,7 +5391,7 @@ fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float); const ordering = toLlvmAtomicOrdering(extra.ordering()); const llvm_abi_ty = try self.getAtomicAbiType(operand_ty, op == .xchg); - const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); + const llvm_operand_ty = try o.lowerType(operand_ty, .as_value); const access_kind: Builder.MemoryAccessKind = if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -5130,7 +5420,7 @@ fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va // If we are storing a pointer we need to convert to and from a plain old integer. const non_ptr_operand = switch (operand_ty.zigTypeTag(zcu)) { - .pointer => try self.wip.cast(.ptrtoint, operand, try o.lowerType(.usize, .by_value), ""), + .pointer => try self.wip.cast(.ptrtoint, operand, try o.lowerType(.usize, .as_value), ""), else => operand, }; @@ -5169,7 +5459,7 @@ fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.V Type.fromInterned(info.child).abiAlignment(zcu)).toLlvm(); const access_kind: Builder.MemoryAccessKind = if (info.flags.is_volatile) .@"volatile" else .normal; - const elem_llvm_ty = try o.lowerType(elem_ty, .by_value); + const elem_llvm_ty = try o.lowerType(elem_ty, .as_value); self.maybeMarkAllowZeroAccess(info); @@ -5503,11 +5793,11 @@ fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Intrinsic) .normal, .none, intrinsic, - &.{try o.lowerType(operand_ty, .by_value)}, + &.{try o.lowerType(operand_ty, .as_value)}, &.{ operand, .false }, "", ); - return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .by_value), ""); + return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .as_value), ""); } fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Intrinsic) Allocator.Error!Builder.Value { @@ -5521,11 +5811,11 @@ fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Intrinsic) .normal, .none, intrinsic, - &.{try o.lowerType(operand_ty, .by_value)}, + &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, "", ); - return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .by_value), ""); + return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .as_value), ""); } fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -5538,7 +5828,7 @@ fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val const inst_ty = self.typeOfIndex(inst); var operand = try self.resolveInst(ty_op.operand); - var llvm_operand_ty = try o.lowerType(operand_ty, .by_value); + var llvm_operand_ty = try o.lowerType(operand_ty, .as_value); if (bits % 16 == 8) { // If not an even byte-multiple, we need zero-extend + shift-left 1 byte @@ -5559,7 +5849,7 @@ fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val const result = try self.wip.callIntrinsic(.normal, .none, .bswap, &.{llvm_operand_ty}, &.{operand}, ""); - return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .by_value), ""); + return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .as_value), ""); } fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -5579,7 +5869,7 @@ fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Bui for (0..names.len) |name_index| { const err_int = ip.getErrorValueIfExists(names.get(ip)[name_index]).?; - const this_tag_int_value = try o.builder.intConst(try o.errorIntType(.by_value), err_int); + const this_tag_int_value = try o.builder.intConst(try o.errorIntType(.as_value), err_int); try wip_switch.addCase(this_tag_int_value, valid_block, &self.wip); } self.wip.cursor = .{ .block = valid_block }; @@ -5638,7 +5928,7 @@ fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va const slice_ty = self.typeOfIndex(inst); // If operand is small (e.g. `u8`), then signedness becomes a problem -- GEP always treats the index as signed. - const operand_usize = try self.wip.conv(.unsigned, operand, try o.lowerType(.usize, .by_value), ""); + const operand_usize = try self.wip.conv(.unsigned, operand, try o.lowerType(.usize, .as_value), ""); const error_name_table_ptr = try o.getErrorNameTable(); const error_name_ptr = try self.ptraddScaled(error_name_table_ptr.toValue(&o.builder), operand_usize, slice_ty.abiSize(zcu)); @@ -5649,7 +5939,7 @@ fn airSplat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const scalar = try self.resolveInst(ty_op.operand); const vector_ty = self.typeOfIndex(inst); - return self.wip.splatVector(try self.object.lowerType(vector_ty, .by_value), scalar, ""); + return self.wip.splatVector(try self.object.lowerType(vector_ty, .as_value), scalar, ""); } fn airSelect(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -5672,9 +5962,9 @@ fn airShuffleOne(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val const operand = try fg.resolveInst(unwrapped.operand); const mask = unwrapped.mask; const operand_ty = fg.typeOf(unwrapped.operand); - const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); - const llvm_result_ty = try o.lowerType(unwrapped.result_ty, .by_value); - const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu), .by_value); + const llvm_operand_ty = try o.lowerType(operand_ty, .as_value); + const llvm_result_ty = try o.lowerType(unwrapped.result_ty, .as_value); + const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu), .as_value); const llvm_poison_elem = try o.builder.poisonConst(llvm_elem_ty); const llvm_poison_mask_elem = try o.builder.poisonConst(.i32); const llvm_mask_ty = try o.builder.vectorType(.normal, @intCast(mask.len), .i32); @@ -5704,7 +5994,7 @@ fn airShuffleOne(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val .elem => llvm_poison_elem, .value => |val| if (!Value.fromInterned(val).isUndef(zcu)) elem: { any_defined_comptime_value = true; - break :elem try o.lowerValue(val, .by_value); + break :elem try o.lowerValue(val, .as_value); } else llvm_poison_elem, }; } @@ -5776,7 +6066,7 @@ fn airShuffleTwo(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val const unwrapped = fg.air.unwrapShuffleTwo(zcu, inst); const mask = unwrapped.mask; - const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu), .by_value); + const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu), .as_value); const llvm_mask_ty = try o.builder.vectorType(.normal, @intCast(mask.len), .i32); const llvm_poison_mask_elem = try o.builder.poisonConst(.i32); @@ -5848,95 +6138,25 @@ fn airShuffleTwo(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val ); } -/// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result. -/// -/// Equivalent to: -/// ``` -/// var accum: T = init; -/// for (0..i) |i| { -/// accum = llvm_fn(accum, vec[i]); -/// } -/// // result is 'accum' -/// ``` -fn buildReducedCall( - self: *FuncGen, - llvm_fn: Builder.Function.Index, - operand_vector: Builder.Value, - vector_len: usize, - accum_init: Builder.Value, -) Allocator.Error!Builder.Value { - const o = self.object; - const llvm_usize_ty = try o.lowerType(.usize, .by_value); - const llvm_vector_len = try o.builder.intValue(llvm_usize_ty, vector_len); - const llvm_result_ty = accum_init.typeOfWip(&self.wip); - - const entry_block = self.wip.cursor.block; - - const cond_block = try self.wip.block(2, "ReduceLoopCond"); - const body_block = try self.wip.block(1, "ReduceLoopBody"); - const exit_block = try self.wip.block(1, "ReduceLoopExit"); - - _ = try self.wip.br(cond_block); - - // ReduceLoopCond: - // %index = phi iN [0, %Entry], [%new_index, %ReduceLoopBody] - // %accum = phi T [%accum_init, %Entry], [%new_accum, %ReduceLoopBody] - // %cond = icmp ult iN %index, %vector_len - // br i1 %cond, label %ReduceLoopBody, label %ReduceLoopExit - self.wip.cursor = .{ .block = cond_block }; - const index = try self.wip.phi(llvm_usize_ty, ""); - const accum = try self.wip.phi(llvm_result_ty, ""); - const cond = try self.wip.icmp(.ult, index.toValue(), llvm_vector_len, ""); - _ = try self.wip.brCond(cond, body_block, exit_block, .none); - - // ReduceLoopBody: - // %elem = extractelement %operand_vec, iN %index - // %new_accum = call T @llvm_fn(T %accum, T %elem) - // %new_index = add nuw iN %index, 1 - // br label %ReduceLoopCond - self.wip.cursor = .{ .block = body_block }; - const elem = try self.wip.extractElement(operand_vector, index.toValue(), ""); - const new_accum = try self.wip.call( - .normal, - .ccc, - .none, - llvm_fn.typeOf(&o.builder), - llvm_fn.toValue(&o.builder), - &.{ accum.toValue(), elem }, - "", - ); - const new_index = try self.wip.bin(.@"add nuw", index.toValue(), try o.builder.intValue(llvm_usize_ty, 1), ""); - _ = try self.wip.br(cond_block); - - const index_init = try o.builder.intValue(llvm_usize_ty, 0); - index.finish(&.{ index_init, new_index }, &.{ entry_block, body_block }, &self.wip); - accum.finish(&.{ accum_init, new_accum }, &.{ entry_block, body_block }, &self.wip); - - self.wip.cursor = .{ .block = exit_block }; - return accum.toValue(); -} - -fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { - const o = self.object; +fn airReduce(fg: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { + const o = fg.object; const zcu = o.zcu; const target = zcu.getTarget(); - const reduce = self.air.instructions.items(.data)[@backingInt(inst)].reduce; - const operand = try self.resolveInst(reduce.operand); - const operand_ty = self.typeOf(reduce.operand); - const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); - const scalar_ty = self.typeOfIndex(inst); - const llvm_scalar_ty = try o.lowerType(scalar_ty, .by_value); + const reduce = fg.air.instructions.items(.data)[@backingInt(inst)].reduce; + const operand = try fg.resolveInst(reduce.operand); + const operand_ty = fg.typeOf(reduce.operand); + const scalar_ty = fg.typeOfIndex(inst); switch (reduce.operation) { - .And, .Or, .Xor => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { + .And, .Or, .Xor => return fg.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { .And => .@"vector.reduce.and", .Or => .@"vector.reduce.or", .Xor => .@"vector.reduce.xor", else => unreachable, - }, &.{llvm_operand_ty}, &.{operand}, ""), + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""), .Min, .Max => switch (scalar_ty.zigTypeTag(zcu)) { - .int => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { + .int => return fg.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { .Min => if (scalar_ty.isSignedInt(zcu)) .@"vector.reduce.smin" else @@ -5946,29 +6166,29 @@ fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) A else .@"vector.reduce.umax", else => unreachable, - }, &.{llvm_operand_ty}, &.{operand}, ""), - .float => if (intrinsicsAllowed(scalar_ty, target)) - return self.wip.callIntrinsic(fast, .none, switch (reduce.operation) { + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""), + .float => if (intrinsicsAllowed(.libc, scalar_ty, target)) + return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) { .Min => .@"vector.reduce.fmin", .Max => .@"vector.reduce.fmax", else => unreachable, - }, &.{llvm_operand_ty}, &.{operand}, ""), + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""), else => unreachable, }, .Add, .Mul => switch (scalar_ty.zigTypeTag(zcu)) { - .int => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { + .int => return fg.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { .Add => .@"vector.reduce.add", .Mul => .@"vector.reduce.mul", else => unreachable, - }, &.{llvm_operand_ty}, &.{operand}, ""), - .float => if (intrinsicsAllowed(scalar_ty, target)) - return self.wip.callIntrinsic(fast, .none, switch (reduce.operation) { + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{operand}, ""), + .float => if (intrinsicsAllowed(.compiler_rt, scalar_ty, target)) + return fg.wip.callIntrinsic(fast, .none, switch (reduce.operation) { .Add => .@"vector.reduce.fadd", .Mul => .@"vector.reduce.fmul", else => unreachable, - }, &.{llvm_operand_ty}, &.{ switch (reduce.operation) { - .Add => try o.builder.fpValue(llvm_scalar_ty, -0.0), - .Mul => try o.builder.fpValue(llvm_scalar_ty, 1.0), + }, &.{try o.lowerType(operand_ty, .as_value)}, &.{ switch (reduce.operation) { + .Add => try o.builder.fpValue(try o.lowerType(scalar_ty, .as_value), -0.0), + .Mul => try o.builder.fpValue(try o.lowerType(scalar_ty, .as_value), 1.0), else => unreachable, }, operand }, ""), else => unreachable, @@ -5986,62 +6206,119 @@ fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) A libcFloatPrefix(float_bits), libcFloatSuffix(float_bits), }), .Add => try o.builder.strtabStringFmt("__add{s}f3", .{ - compilerRtFloatAbbrev(float_bits), + compilerRtFloatAbbrev(target, float_bits), }), .Mul => try o.builder.strtabStringFmt("__mul{s}f3", .{ - compilerRtFloatAbbrev(float_bits), + compilerRtFloatAbbrev(target, float_bits), }), else => unreachable, }; - - const libc_fn = try o.getLibcFunction(fn_name, &.{ llvm_scalar_ty, llvm_scalar_ty }, llvm_scalar_ty); - const init_val = switch (llvm_scalar_ty) { - .i16 => try o.builder.intValue(.i16, @as(i16, @bitCast( - @as(f16, switch (reduce.operation) { - .Min, .Max => std.math.nan(f16), - .Add => -0.0, - .Mul => 1.0, - else => unreachable, - }), - ))), - .i80 => try o.builder.intValue(.i80, @as(i80, @bitCast( - @as(f80, switch (reduce.operation) { - .Min, .Max => std.math.nan(f80), - .Add => -0.0, - .Mul => 1.0, - else => unreachable, - }), - ))), - .i128 => try o.builder.intValue(.i128, @as(i128, @bitCast( - @as(f128, switch (reduce.operation) { - .Min, .Max => std.math.nan(f128), - .Add => -0.0, - .Mul => 1.0, - else => unreachable, - }), - ))), + const fn_info: Object.FuncInfo = .{ + .cc = target.cCallingConvention().?, + .param_types = &.{ scalar_ty.toIntern(), scalar_ty.toIntern() }, + .return_type = scalar_ty.toIntern(), + }; + const llvm_fn = try fg.object.getLibcFunction(fg.pt, fn_name, fn_info); + const init = switch (float_bits) { else => unreachable, + 16 => try o.f16Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f16), + .Add => -0.0, + .Mul => 1.0, + }), + 32 => try o.f32Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f32), + .Add => -0.0, + .Mul => 1.0, + }), + 64 => try o.f64Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f64), + .Add => -0.0, + .Mul => 1.0, + }), + 80 => try o.f80Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f80), + .Add => -0.0, + .Mul => 1.0, + }), + 128 => try o.f128Const(switch (reduce.operation) { + else => unreachable, + .Min, .Max => std.math.nan(f128), + .Add => -0.0, + .Mul => 1.0, + }), }; - return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(zcu), init_val); + const iterations = operand_ty.vectorLen(zcu); + const is_by_ref = isByRef(operand_ty, zcu); + if (iterations > 1 and is_by_ref) { + const init_ref = try o.lowerConstRef(init, scalar_ty.abiAlignment(zcu).toLlvm()); + + const entry_block = fg.wip.cursor.block; + const loop_block = try fg.wip.block(2, "reduce.loop"); + const done_block = try fg.wip.block(1, "reduce.loop"); + + _ = try fg.wip.br(loop_block); + + fg.wip.cursor = .{ .block = loop_block }; + const index = try fg.wip.phi(.i32, "reduce.index"); + const result = try fg.wip.phi(.ptr, "reduce.result"); + + const rhs_elem_ptr = try fg.ptraddScaled(operand, index.toValue(), scalar_ty.abiSize(zcu)); + const rhs_elem = try fg.load(rhs_elem_ptr, .none, scalar_ty, .normal); + const next_result = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, &.{ result.toValue(), rhs_elem }); + + const next_index = try fg.wip.bin(.@"add nuw", index.toValue(), try o.builder.intValue(.i32, 1), "reduce.next_index"); + index.finish(&.{ try o.builder.intValue(.i32, 0), next_index }, &.{ entry_block, loop_block }, &fg.wip); + result.finish(&.{ init_ref.toValue(), next_result }, &.{ entry_block, loop_block }, &fg.wip); + const is_done = try fg.wip.icmp(.eq, next_index, try o.builder.intValue(.i32, iterations), "reduce.is_done"); + _ = try fg.wip.brCond(is_done, done_block, loop_block, .none); + + fg.wip.cursor = .{ .block = done_block }; + return next_result; + } + var result = init.toValue(); + for (0..iterations) |index| { + const index_value = try o.builder.intValue(.i32, index); + const rhs_elem = if (is_by_ref) rhs_elem: { + const rhs_elem_ptr = try fg.ptraddConst(operand, index * scalar_ty.abiSize(zcu)); + break :rhs_elem try fg.load(rhs_elem_ptr, .none, scalar_ty, .normal); + } else try fg.wip.extractElement(operand, index_value, "reduce.rhs_elem"); + result = try fg.buildCall(.{}, llvm_fn.typeOf(&o.builder), llvm_fn.toValue(&o.builder), fn_info, fn_info.param_types, &.{ result, rhs_elem }); + } + return result; } -fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { - const o = self.object; +fn airAggregateInit(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const o = fg.object; const zcu = o.zcu; const ip = &zcu.intern_pool; - const ty_pl = self.air.instructions.items(.data)[@backingInt(inst)].ty_pl; - const result_ty = self.typeOfIndex(inst); + const ty_pl = fg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; + const result_ty = fg.typeOfIndex(inst); const len: usize = @intCast(result_ty.arrayLen(zcu)); - const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[ty_pl.payload..][0..len]); + const elements: []const Air.Inst.Ref = @ptrCast(fg.air.extra.items[ty_pl.payload..][0..len]); switch (result_ty.zigTypeTag(zcu)) { - .vector => { - const llvm_result_ty = try o.lowerType(result_ty, .by_value); + .vector => if (isByRef(result_ty, zcu)) { + const elem_ty = result_ty.childType(zcu); + const elem_size = elem_ty.abiSize(zcu); + const result_ptr = try fg.buildZigAlloca(result_ty, .none); + for (elements, 0..) |elem, elem_index| { + const elem_ptr = try fg.ptraddConst(result_ptr, elem_index * elem_size); + const llvm_elem = try fg.resolveInst(elem); + try fg.store(elem_ptr, .none, llvm_elem, elem_ty, .normal); + } + return result_ptr; + } else { + const llvm_result_ty = try o.lowerType(result_ty, .as_value); var vector = try o.builder.poisonValue(llvm_result_ty); - for (elements, 0..) |elem, i| { - const index_u32 = try o.builder.intValue(.i32, i); - const llvm_elem = try self.resolveInst(elem); - vector = try self.wip.insertElement(vector, llvm_elem, index_u32, ""); + for (elements, 0..) |elem, elem_index| { + const elem_index_val = try o.builder.intValue(.i32, elem_index); + const llvm_elem = try fg.resolveInst(elem); + vector = try fg.wip.insertElement(vector, llvm_elem, elem_index_val, ""); } return vector; }, @@ -6057,18 +6334,18 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde for (elements, struct_type.field_types.get(ip)) |elem, field_ty| { if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue; - const non_int_val = try self.resolveInst(elem); + const non_int_val = try fg.resolveInst(elem); const ty_bit_size: u16 = @intCast(Type.fromInterned(field_ty).bitSize(zcu)); const small_int_ty = try o.builder.intType(ty_bit_size); const small_int_val = if (Type.fromInterned(field_ty).isPtrAtRuntime(zcu)) - try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "") + try fg.wip.cast(.ptrtoint, non_int_val, small_int_ty, "") else - try self.wip.cast(.bitcast, non_int_val, small_int_ty, ""); + try fg.wip.cast(.bitcast, non_int_val, small_int_ty, ""); const shift_rhs = try o.builder.intValue(int_ty, running_bits); const extended_int_val = - try self.wip.conv(.unsigned, small_int_val, int_ty, ""); - const shifted = try self.wip.bin(.shl, extended_int_val, shift_rhs, ""); - running_int = try self.wip.bin(.@"or", running_int, shifted, ""); + try fg.wip.conv(.unsigned, small_int_val, int_ty, ""); + const shifted = try fg.wip.bin(.shl, extended_int_val, shift_rhs, ""); + running_int = try fg.wip.bin(.@"or", running_int, shifted, ""); running_bits += ty_bit_size; } return running_int; @@ -6078,19 +6355,19 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde // TODO in debug builds init to undef so that the padding will be 0xaa // even if we fully populate the fields. const struct_align = result_ty.abiAlignment(zcu); - const alloca_inst = try self.buildZigAlloca(result_ty, .none); + const alloca_inst = try fg.buildZigAlloca(result_ty, .none); for (elements, 0..) |elem, field_index| { if (result_ty.structFieldIsComptime(field_index, zcu)) continue; const field_ty = result_ty.fieldType(field_index, zcu); if (!field_ty.hasRuntimeBits(zcu)) continue; const offset = result_ty.structFieldOffset(field_index, zcu); - const field_ptr = try self.ptraddConst(alloca_inst, offset); + const field_ptr = try fg.ptraddConst(alloca_inst, offset); const field_ptr_align = struct_align.offset(offset); - const llvm_field_val = try self.resolveInst(elem); + const llvm_field_val = try fg.resolveInst(elem); - try self.store(field_ptr, field_ptr_align, llvm_field_val, field_ty, .normal); + try fg.store(field_ptr, field_ptr_align, llvm_field_val, field_ty, .normal); } return alloca_inst; @@ -6099,21 +6376,21 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde .array => { assert(isByRef(result_ty, zcu)); - const alloca_inst = try self.buildZigAlloca(result_ty, .none); + const alloca_inst = try fg.buildZigAlloca(result_ty, .none); const array_info = result_ty.arrayInfo(zcu); const elem_size = array_info.elem_type.abiSize(zcu); for (elements, 0..) |elem, i| { - const elem_ptr = try self.ptraddConst(alloca_inst, elem_size * i); - const llvm_elem = try self.resolveInst(elem); - try self.store(elem_ptr, .none, llvm_elem, array_info.elem_type, .normal); + const elem_ptr = try fg.ptraddConst(alloca_inst, elem_size * i); + const llvm_elem = try fg.resolveInst(elem); + try fg.store(elem_ptr, .none, llvm_elem, array_info.elem_type, .normal); } if (array_info.sentinel) |sent_val| { - const elem_ptr = try self.ptraddConst(alloca_inst, elem_size * array_info.len); - const llvm_elem = try self.resolveValue(sent_val); - try self.store(elem_ptr, .none, llvm_elem.toValue(), array_info.elem_type, .normal); + const elem_ptr = try fg.ptraddConst(alloca_inst, elem_size * array_info.len); + const llvm_elem = try fg.resolveValue(sent_val); + try fg.store(elem_ptr, .none, llvm_elem.toValue(), array_info.elem_type, .normal); } return alloca_inst; @@ -6153,10 +6430,10 @@ fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va const loaded_enum = ip.loadEnumType(tag_ty.toIntern()); const llvm_tag_val = switch (loaded_enum.field_values.getOrNone(ip, extra.field_index)) { .none => try o.builder.intConst( - try o.lowerType(.fromInterned(union_obj.enum_tag_type), .by_value), + try o.lowerType(.fromInterned(union_obj.enum_tag_type), .as_value), extra.field_index, // auto-numbered ), - else => |tag_val_ip| try o.lowerValue(tag_val_ip, .by_value), + else => |tag_val_ip| try o.lowerValue(tag_val_ip, .as_value), }; const tag_ptr = try self.ptraddConst(result_ptr, layout.tagOffset()); try self.store(tag_ptr, layout.tag_align, llvm_tag_val.toValue(), tag_ty, .normal); @@ -6218,7 +6495,7 @@ fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde const ty_op = self.air.instructions.items(.data)[@backingInt(inst)].ty_op; const inst_ty = self.typeOfIndex(inst); const operand = try self.resolveInst(ty_op.operand); - return self.wip.cast(.addrspacecast, operand, try self.object.lowerType(inst_ty, .by_value), ""); + return self.wip.cast(.addrspacecast, operand, try self.object.lowerType(inst_ty, .as_value), ""); } fn workIntrinsic( @@ -6370,7 +6647,7 @@ fn load( }; if (isByRef(load_ty, zcu)) { - const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); const result_ptr = try fg.buildZigAlloca(load_ty, .none); _ = try fg.wip.callMemCpy( result_ptr, @@ -6384,11 +6661,14 @@ fn load( return result_ptr; } - const llvm_memory_ty = try o.lowerType(load_ty, .in_memory); - const llvm_value_ty = try o.lowerType(load_ty, .by_value); + const llvm_access_ty = try o.lowerType(load_ty, .memory_access); + const llvm_value_ty = try o.lowerType(load_ty, .as_value); - if (llvm_memory_ty != llvm_value_ty) { - assert(load_ty.isAbiInt(zcu)); + if (llvm_access_ty != llvm_value_ty) { + const signedness: std.lang.Signedness = switch (load_ty.toIntern()) { + .bool_type => .unsigned, + else => load_ty.intInfo(zcu).signedness, + }; // `load_ty` is an integer type with padding bits. In theory, we shouldn't need any special // handling for these, as LLVM's documented semantics are a valid implementation of Zig's // semantics. However: @@ -6401,13 +6681,13 @@ fn load( // // Therefore, we handle these memory accesses specially: in this case we will actually load // the next-largest "natural" integer type and then truncate to `load_ty`. - const loaded = try fg.wip.load(access_kind, llvm_memory_ty, ptr, llvm_ptr_align, ""); + const loaded = try fg.wip.load(access_kind, llvm_access_ty, ptr, llvm_ptr_align, ""); // For packed structs, current Zig semantics don't really allow us to make the padding bits // well-defined. This should be solved once https://github.com/ziglang/zig/issues/24061 is // implemented, but until then, do a normal trunc for packed types. return fg.wip.cast(switch (load_ty.zigTypeTag(zcu)) { .@"struct", .@"union" => .trunc, - else => switch (load_ty.intInfo(zcu).signedness) { + else => switch (signedness) { .unsigned => .@"trunc nuw", .signed => .@"trunc nsw", }, @@ -6443,7 +6723,7 @@ fn store( }; if (isByRef(elem_ty, zcu)) { - const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); _ = try fg.wip.callMemCpy( ptr, llvm_ptr_align, @@ -6456,45 +6736,34 @@ fn store( return; } - assert(elem.typeOfWip(&fg.wip) == try o.lowerType(elem_ty, .by_value)); + assert(elem.typeOfWip(&fg.wip) == try o.lowerType(elem_ty, .as_value)); - const llvm_memory_ty = try o.lowerType(elem_ty, .in_memory); - const llvm_value_ty = try o.lowerType(elem_ty, .by_value); + const llvm_access_ty = try o.lowerType(elem_ty, .memory_access); + const llvm_value_ty = try o.lowerType(elem_ty, .as_value); - if (llvm_memory_ty != llvm_value_ty) { - assert(elem_ty.isAbiInt(zcu)); + if (llvm_access_ty != llvm_value_ty) { + const signedness: std.lang.Signedness = switch (elem_ty.toIntern()) { + .bool_type => .unsigned, + else => elem_ty.intInfo(zcu).signedness, + }; // `elem_ty` is an integer type with padding bits, so we need to handle it specially---see // the corresponding comment in `FuncGen.load` for more details. - const extended = try fg.wip.cast(switch (elem_ty.intInfo(zcu).signedness) { + const extended = try fg.wip.cast(switch (signedness) { .unsigned => .zext, .signed => .sext, - }, elem, llvm_memory_ty, ""); - _ = try fg.wip.storeAtomic( - access_kind, - extended, - ptr, - fg.sync_scope, - .none, - llvm_ptr_align, - ); + }, elem, llvm_access_ty, ""); + _ = try fg.wip.store(access_kind, extended, ptr, llvm_ptr_align); return; } // `elem_ty` is a simple by-val type which requires no special handling. - _ = try fg.wip.storeAtomic( - access_kind, - elem, - ptr, - fg.sync_scope, - .none, - llvm_ptr_align, - ); + _ = try fg.wip.store(access_kind, elem, ptr, llvm_ptr_align); } fn valgrindMarkUndef(fg: *FuncGen, ptr: Builder.Value, len: Builder.Value) Allocator.Error!void { const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545; const o = fg.object; - const usize_ty = try o.lowerType(.usize, .by_value); + const usize_ty = try o.lowerType(.usize, .as_value); const zero = try o.builder.intValue(usize_ty, 0); const req = try o.builder.intValue(usize_ty, VG_USERREQ__MAKE_MEM_UNDEFINED); const ptr_as_usize = try fg.wip.cast(.ptrtoint, ptr, usize_ty, ""); @@ -6516,7 +6785,7 @@ fn valgrindClientRequest( const target = zcu.getTarget(); if (!target_util.hasValgrindSupport(target, .stage2_llvm)) return default_value; - const llvm_usize = try o.lowerType(.usize, .by_value); + const llvm_usize = try o.lowerType(.usize, .as_value); const usize_align = Type.usize.abiAlignment(zcu).toLlvm(); const array_llvm_ty = try o.builder.arrayType(6, llvm_usize); @@ -6650,13 +6919,14 @@ fn typeOfIndex(fg: *FuncGen, inst: Air.Inst.Index) Type { const ParamTypeIterator = struct { object: *Object, - fn_info: InternPool.Key.FuncType, + cc: std.lang.CallingConvention, + param_types: []const InternPool.Index, zig_index: u32, llvm_index: u32, types_len: u32, types_buffer: [8]Builder.Type, offsets_buffer: [9]u64, - byval_attr: bool, + byval_attr: ?Object.Byval, const Lowering = union(enum) { no_bits, @@ -6672,88 +6942,78 @@ const ParamTypeIterator = struct { }; pub fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering { - if (it.zig_index >= it.fn_info.param_types.len) return null; - const ip = &it.object.zcu.intern_pool; - const ty = it.fn_info.param_types.get(ip)[it.zig_index]; - it.byval_attr = false; + if (it.zig_index >= it.param_types.len) return null; + const ty = it.param_types[it.zig_index]; + it.byval_attr = null; return nextInner(it, Type.fromInterned(ty)); } /// `airCall` uses this instead of `next` so that it can take into account variadic functions. - fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) Allocator.Error!?Lowering { - const ip = &it.object.zcu.intern_pool; - if (it.zig_index >= it.fn_info.param_types.len) { - if (it.zig_index >= args.len) { + fn nextCall(it: *ParamTypeIterator, arg_types: []const InternPool.Index) Allocator.Error!?Lowering { + if (it.zig_index >= it.param_types.len) { + if (it.zig_index >= arg_types.len) { return null; } else { - return nextInner(it, fg.typeOf(args[it.zig_index])); + return nextInner(it, .fromInterned(arg_types[it.zig_index])); } } else { - return nextInner(it, Type.fromInterned(it.fn_info.param_types.get(ip)[it.zig_index])); + return nextInner(it, .fromInterned(it.param_types[it.zig_index])); } } fn nextInner(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering { const zcu = it.object.zcu; - const target = zcu.getTarget(); - + ty.assertHasLayout(zcu); if (!ty.hasRuntimeBits(zcu)) { it.zig_index += 1; return .no_bits; } - switch (it.fn_info.cc) { + switch (it.cc) { .@"inline" => unreachable, .auto => { it.zig_index += 1; it.llvm_index += 1; + + // Match the c calling convention in some cases to avoid llvm bugs. + const target = zcu.getTarget(); + if (target.cpu.arch == .x86_64 and ty.isVector(zcu) and ty.childType(zcu).toIntern() == .bool_type) return switch (ty.vectorLen(zcu)) { + 0 => .no_bits, + 1...32 => .abi_sized_int, + 33...64 => { + it.types_buffer[0..1].* = .{.double}; + it.offsets_buffer[0..2].* = .{ 0, 8 }; + it.types_len = 1; + return .multiple_llvm_types; + }, + else => .byval, + }; + if (ty.isSlice(zcu) or (ty.zigTypeTag(zcu) == .optional and ty.optionalChild(zcu).isSlice(zcu) and !ty.ptrAllowsZero(zcu))) { it.llvm_index += 1; return .slice; - } else if (isByRef(ty, zcu)) { - return .byref; - } else if (target.cpu.arch.isX86() and - !target.cpu.has(.x86, .avx512f) and - ty.totalVectorBits(zcu) >= 512) - { - // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns - // "512-bit vector arguments require 'avx512f' for AVX512" - return .byref; - } else { - return .byval; } + if (isByRef(ty, zcu)) return .byref; + return .byval; }, .async => { @panic("TODO implement async function lowering in the LLVM backend"); }, - .x86_64_sysv, .x86_64_x32 => return it.nextSystemV(ty), - .x86_64_win => return it.nextWin64(ty), - .x86_stdcall => { - it.zig_index += 1; - it.llvm_index += 1; - - if (isScalar(zcu, ty)) { - return .byval; - } else { - it.byval_attr = true; - return .byref; - } - }, .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => { it.zig_index += 1; it.llvm_index += 1; switch (aarch64_c_abi.classifyType(ty, zcu)) { .memory => return .byref_mut, - .float_array => |len| return Lowering{ .float_array = len }, + .float_array => |len| return .{ .float_array = len }, .byval => return .byval, .integer => { - it.types_len = 1; it.types_buffer[0..1].* = .{.i64}; it.offsets_buffer[0..2].* = .{ 0, 8 }; + it.types_len = 1; return .multiple_llvm_types; }, - .double_integer => return Lowering{ .i64_array = 2 }, + .double_integer => return .{ .i64_array = 2 }, } }, .arm_aapcs, .arm_aapcs_vfp => { @@ -6761,26 +7021,101 @@ const ParamTypeIterator = struct { it.llvm_index += 1; switch (arm_c_abi.classifyType(ty, zcu, .arg)) { .memory => { - it.byval_attr = true; + it.byval_attr = .{}; return .byref; }, .byval => return .byval, - .i32_array => |size| return Lowering{ .i32_array = size }, - .i64_array => |size| return Lowering{ .i64_array = size }, + .i32_array => |size| return .{ .i32_array = size }, + .i64_array => |size| return .{ .i64_array = size }, } }, + .loongarch32_ilp32, .loongarch64_lp64 => switch (loongarch_c_abi.classifyType(ty, zcu)) { + .ignored => { + it.zig_index += 1; + return .no_bits; + }, + .gar, .far => { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; + }, + .member => |member_ty| { + it.types_buffer[0..1].* = .{ + try it.object.lowerType(member_ty, .as_value), + }; + it.offsets_buffer[0..2].* = .{ 0, member_ty.abiSize(zcu) }; + it.types_len = 1; + it.zig_index += 1; + it.llvm_index += 1; + return .multiple_llvm_types; + }, + .member_pair => |member_tys| { + it.types_buffer[0..2].* = .{ + try it.object.lowerType(member_tys[0], .as_value), + try it.object.lowerType(member_tys[1], .as_value), + }; + const first_size = member_tys[0].abiSize(zcu); + const second_size = member_tys[0].abiSize(zcu); + it.offsets_buffer[0..3].* = .{ 0, first_size, first_size + second_size }; + it.types_len = 2; + it.zig_index += 1; + it.llvm_index += 2; + return .multiple_llvm_types; + }, + .memory_gar => { + switch (it.cc) { + else => unreachable, + .loongarch32_ilp32 => { + it.types_buffer[0..1].* = .{.i32}; + it.offsets_buffer[0..2].* = .{ 0, 4 }; + }, + .loongarch64_lp64 => { + it.types_buffer[0..1].* = .{.i64}; + it.offsets_buffer[0..2].* = .{ 0, 8 }; + }, + } + it.types_len = 1; + it.zig_index += 1; + it.llvm_index += 1; + return .multiple_llvm_types; + }, + .memory_gar_pair => { + it.zig_index += 1; + it.llvm_index += 1; + return switch (it.cc) { + else => unreachable, + .loongarch32_ilp32 => .{ .i32_array = 2 }, + .loongarch64_lp64 => .{ .i64_array = 2 }, + }; + }, + .address => { + it.zig_index += 1; + it.llvm_index += 1; + return .byref; + }, + }, .mips_o32 => { it.zig_index += 1; it.llvm_index += 1; switch (mips_c_abi.classifyType(ty, zcu, .arg)) { .memory => { - it.byval_attr = true; + it.byval_attr = .{}; return .byref; }, .byval => return .byval, - .i32_array => |size| return Lowering{ .i32_array = size }, + .i32_array => |size| return .{ .i32_array = size }, } }, + .powerpc64_elf_v2 => { + it.zig_index += 1; + it.llvm_index += 1; + if (isByRef(ty, zcu)) return switch (ty.abiSize(zcu)) { + 1...8 => .abi_sized_int, + 9...64 => |abi_size| .{ .i64_array = @intCast(@divCeil(abi_size, 8)) }, + else => .byref, + }; + return .byval; // TODO + }, .riscv64_lp64, .riscv32_ilp32 => { it.zig_index += 1; it.llvm_index += 1; @@ -6788,7 +7123,7 @@ const ParamTypeIterator = struct { .memory => return .byref_mut, .byval => return .byval, .integer => return .abi_sized_int, - .double_integer => return Lowering{ .i64_array = 2 }, + .double_integer => return .{ .i64_array = 2 }, .fields => { it.types_len = 0; var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (zcu.typeToStruct(ty)) |loaded_struct| @@ -6798,7 +7133,7 @@ const ParamTypeIterator = struct { while (field_it.next()) |field_index| { const field_ty = ty.fieldType(field_index, zcu); if (!field_ty.hasRuntimeBits(zcu)) continue; - it.types_buffer[it.types_len] = try it.object.lowerType(field_ty, .by_value); + it.types_buffer[it.types_len] = try it.object.lowerType(field_ty, .as_value); it.offsets_buffer[it.types_len] = ty.structFieldOffset(field_index, zcu); it.types_len += 1; } @@ -6808,28 +7143,105 @@ const ParamTypeIterator = struct { }, } }, - .wasm_mvp => switch (wasm_c_abi.classifyType(ty, zcu)) { + .s390x_sysv, .s390x_sysv_vx => { + it.zig_index += 1; + switch (s390x_c_abi.classifyType(ty, .arg, zcu)) { + .none => return .no_bits, + .double_or_float, .vector, .simple => { + it.llvm_index += 1; + return .byval; + }, + .simple_aggregate => { + it.llvm_index += 1; + return .abi_sized_int; + }, + .pointer => { + it.llvm_index += 1; + return .byref_mut; + }, + } + }, + .wasm_mvp => switch (wasm_c_abi.classifyTypeForLlvm(ty, zcu)) { .direct => |scalar_ty| { if (isScalar(zcu, ty)) { it.zig_index += 1; it.llvm_index += 1; return .byval; } else { - it.types_buffer[0..1].* = .{try it.object.lowerType(scalar_ty, .by_value)}; + it.types_buffer[0..1].* = .{try it.object.lowerType(scalar_ty, .as_value)}; it.offsets_buffer[0..2].* = .{ 0, scalar_ty.abiSize(zcu) }; it.types_len = 1; - it.llvm_index += 1; it.zig_index += 1; + it.llvm_index += 1; return .multiple_llvm_types; } }, .indirect => { it.zig_index += 1; it.llvm_index += 1; - it.byval_attr = true; + it.byval_attr = .{}; return .byref; }, }, + .x86_stdcall => { + it.zig_index += 1; + it.llvm_index += 1; + + if (isScalar(zcu, ty)) { + return .byval; + } else { + it.byval_attr = .{}; + return .byref; + } + }, + .x86_sysv, .x86_win, .x86_mingw => { + if (isByRef(ty, zcu)) { + var items_buf: [1]codegen.FlattenedItem = undefined; + if (codegen.flattenType(&items_buf, ty, zcu, .{ + .allow_arrays = false, + })) |items| one_float: { + if (items.len != 1 or items[0].offset != 0) break :one_float; + const item_ty = items[0].type orelse break :one_float; + if (!item_ty.isRuntimeFloat()) break :one_float; + it.types_buffer[0..1].*, it.offsets_buffer[0..2].* = + switch (item_ty.floatBits(zcu.getTarget())) { + else => unreachable, + 32 => .{ .{.float}, .{ 0, 4 } }, + 64 => .{ .{.double}, .{ 0, 8 } }, + 16, 80, 128 => break :one_float, + }; + it.types_len = 1; + it.zig_index += 1; + it.llvm_index += 1; + return .multiple_llvm_types; + } + it.zig_index += 1; + it.llvm_index += 1; + it.byval_attr = .{ .alignment = .@"4" }; + return .byref; + } + if (ty.isAbiInt(zcu)) switch (ty.intInfo(zcu).bits) { + else => unreachable, + 8, 16, 32, 64 => { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; + }, + 128 => { + it.types_buffer[0..2].* = .{ .i64, .i64 }; + it.offsets_buffer[0..3].* = .{ 0, 8, 16 }; + it.types_len = 2; + it.zig_index += 1; + it.llvm_index += 2; + return .multiple_llvm_types; + }, + }; + it.zig_index += 1; + it.llvm_index += 1; + return .byval; + }, + .x86_64_sysv, .x86_64_x32 => return try it.next_x86_64_sysv(ty), + .x86_64_win => return it.next_x86_64_win(ty), // TODO investigate other callconvs else => { it.zig_index += 1; @@ -6839,7 +7251,7 @@ const ParamTypeIterator = struct { } } - fn nextWin64(it: *ParamTypeIterator, ty: Type) ?Lowering { + fn next_x86_64_win(it: *ParamTypeIterator, ty: Type) Lowering { const zcu = it.object.zcu; switch (x86_64_abi.classifyWindows(ty, zcu, zcu.getTarget(), .arg)) { .integer => { @@ -6880,119 +7292,114 @@ const ParamTypeIterator = struct { } } - fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering { - const zcu = it.object.zcu; - const ip = &zcu.intern_pool; - ty.assertHasLayout(zcu); - const classes = x86_64_abi.classifySystemV(ty, zcu, zcu.getTarget(), .arg); - if (classes[0] == .memory) { - it.zig_index += 1; - it.llvm_index += 1; - it.byval_attr = true; - return .byref; - } - if (isScalar(zcu, ty)) { - it.zig_index += 1; - it.llvm_index += 1; - return .byval; - } - var types_index: u32 = 0; - var offset: u64 = 0; - for (classes) |class| { - switch (class) { - .integer => { - it.types_buffer[types_index] = .i64; - it.offsets_buffer[types_index] = offset; - types_index += 1; - }, - .sse => { - it.types_buffer[types_index] = .double; - it.offsets_buffer[types_index] = offset; - types_index += 1; - }, - .sseup => { - if (it.types_buffer[types_index - 1] == .double) { - it.types_buffer[types_index - 1] = .fp128; - } else { - it.types_buffer[types_index] = .double; - it.offsets_buffer[types_index] = offset; - types_index += 1; + fn next_x86_64_sysv(it: *ParamTypeIterator, ty: Type) Allocator.Error!Lowering { + const o = it.object; + const zcu = o.zcu; + const target = zcu.getTarget(); + const classes = x86_64_abi.classifySystemV(ty, zcu, target, .arg); + var types_len: u32 = 0; + const classes_len = for (classes, 0..) |class, class_index| switch (class) { + .integer => { + it.types_buffer[types_len] = try o.builder.intType(@min(8 * ty.abiSize(zcu) - 64 * class_index, 64)); + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + }, + .sse => { + it.types_buffer[types_len] = .double; + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + }, + .sseup => { + if (it.types_buffer[types_len - 1] == .double) { + if (ty.isVector(zcu)) { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; } - }, - .float => { - it.types_buffer[types_index] = .float; - it.offsets_buffer[types_index] = offset; - types_index += 1; - }, - .float_combine => { - it.types_buffer[types_index] = try it.object.builder.vectorType(.normal, 2, .float); - it.offsets_buffer[types_index] = offset; - types_index += 1; - }, - .x87 => { - it.zig_index += 1; - it.llvm_index += 1; - it.byval_attr = true; - return .byref; - }, - .x87up => unreachable, - .none => break, - .memory => unreachable, // handled above - .win_i128 => unreachable, // windows only - .bool_vector_mask, - .integer_per_element, - .sse_per_element, - .sse_sse_x87_per_qword, - .sse_per_xword, - .sse_per_yword, - .sse_per_zword, - => unreachable, // vectors already handled by `isScalar` above - } - offset += 8; - } - const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer}); - if (first_non_integer == null or classes[first_non_integer.?] == .none) { - assert(first_non_integer orelse classes.len == types_index); - if (types_index == 1) { + it.types_buffer[types_len - 1] = .fp128; + } else { + it.types_buffer[types_len] = .double; + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + } + }, + .float => { + it.types_buffer[types_len] = .float; + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + }, + .float_combine => { + it.types_buffer[types_len] = try it.object.builder.vectorType(.normal, 2, .float); + it.offsets_buffer[types_len] = 8 * class_index; + types_len += 1; + }, + .x87 => { it.zig_index += 1; it.llvm_index += 1; - return .abi_sized_int; - } - if (it.llvm_index + types_index > 6) { + it.byval_attr = .{}; + return .byref; + }, + .x87up => unreachable, + .none => break class_index, + .memory => { + it.zig_index += 1; + it.llvm_index += 1; + it.byval_attr = .{}; + return .byref; + }, + .win_i128 => unreachable, // windows only + .bool_vector_mask, + .integer_per_element, + .sse_per_element, + .sse_sse_x87_per_qword, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; + }, + } else classes.len; + if (types_len > 1) { + if (it.llvm_index + classes_len > 6) { it.zig_index += 1; it.llvm_index += 1; - it.byval_attr = true; + it.byval_attr = .{}; return .byref; } - switch (ip.indexToKey(ty.toIntern())) { - .struct_type => { - const size = ty.abiSize(zcu); - assert(@divCeil(size, 8) == types_index); - if (size % 8 > 0) { - it.types_buffer[types_index - 1] = - try it.object.builder.intType(@intCast(size % 8 * 8)); - } - }, - else => {}, + } else if (!isByRef(ty, zcu)) { + const llvm_ty = try o.lowerType(ty, .as_value); + if (it.types_buffer[0] == llvm_ty or + (it.types_buffer[0] == .i64 and llvm_ty.isPointer(&o.builder))) + { + it.zig_index += 1; + it.llvm_index += 1; + return .byval; } } - it.offsets_buffer[types_index] = offset; - it.types_len = types_index; - it.llvm_index += types_index; + it.offsets_buffer[types_len] = 8 * classes_len; + it.types_len = types_len; + it.llvm_index += types_len; it.zig_index += 1; return .multiple_llvm_types; } }; -pub fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) ParamTypeIterator { +pub fn iterateParamTypes( + object: *Object, + cc: std.lang.CallingConvention, + param_types: []const InternPool.Index, +) ParamTypeIterator { return .{ .object = object, - .fn_info = fn_info, + .cc = cc, + .param_types = param_types, .zig_index = 0, .llvm_index = 0, .types_len = undefined, .types_buffer = undefined, .offsets_buffer = undefined, - .byval_attr = false, + .byval_attr = null, }; } @@ -7017,54 +7424,68 @@ pub const FnReturnStrat = union(enum) { /// In order to support the C calling convention, some return types need to be lowered /// completely differently in the function prototype to honor the C ABI, and then /// be effectively bitcasted to the actual return type. -pub fn fnReturnStrat(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat { +pub fn fnReturnStrat(o: *Object, cc: std.lang.CallingConvention, ret_ty: Type) Allocator.Error!FnReturnStrat { const zcu = o.zcu; - const ret_ty: Type = .fromInterned(fn_info.return_type); ret_ty.assertHasLayout(zcu); if (!ret_ty.hasRuntimeBits(zcu)) return .void; - switch (fn_info.cc) { + return switch (cc) { .@"inline" => unreachable, .auto => { - if (isByRef(ret_ty, zcu)) return .sret; - + // Match the c calling convention in some cases to avoid llvm bugs. const target = zcu.getTarget(); - if (target.cpu.arch.isX86() and - !target.cpu.has(.x86, .avx512f) and - ret_ty.totalVectorBits(zcu) >= 512) - { - // As of LLVM 18, passing a vector byval with fastcc that is 512 bits or more returns - // "512-bit vector arguments require 'avx512f' for AVX512" - return .sret; - } - - return .by_val; + if (target.cpu.arch == .x86_64 and ret_ty.isVector(zcu) and ret_ty.childType(zcu).toIntern() == .bool_type) return switch (ret_ty.vectorLen(zcu)) { + 0 => .void, + 1...8 => .{ .mem_cast = .i8 }, + 9...16 => .{ .mem_cast = .i16 }, + 17...32 => .{ .mem_cast = .i32 }, + 33...64 => .{ .mem_cast = .double }, + else => .by_val, + }; + return if (isByRef(ret_ty, zcu)) .sret else .by_val; }, - .x86_64_sysv, .x86_64_x32 => return lowerSystemVFnRetTy(o, fn_info), - .x86_64_win => return lowerWin64FnRetTy(o, fn_info), - .x86_stdcall => if (isScalar(zcu, ret_ty)) { - assert(!isByRef(ret_ty, zcu)); - return .by_val; - } else return .sret, - .x86_fastcall => return lowerX86FastcallFnRetTy(o, zcu, ret_ty), - .x86_sysv, .x86_win => return if (isByRef(ret_ty, zcu)) .sret else .by_val, .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => switch (aarch64_c_abi.classifyType(ret_ty, zcu)) { - .memory => return .sret, - .float_array, .byval => return .forceByVal(o, ret_ty), - .integer => return .{ .mem_cast = .i64 }, - .double_integer => return .{ .mem_cast = try o.builder.arrayType(2, .i64) }, + .memory => .sret, + .float_array, .byval => .forceByVal(o, ret_ty), + .integer => .{ .mem_cast = .i64 }, + .double_integer => .{ .mem_cast = try o.builder.arrayType(2, .i64) }, }, .arm_aapcs, .arm_aapcs_vfp => switch (arm_c_abi.classifyType(ret_ty, zcu, .ret)) { - .memory, .i64_array => return .sret, - .i32_array => |len| return if (len == 1) .{ .mem_cast = .i32 } else .sret, - .byval => return .forceByVal(o, ret_ty), + .memory, .i64_array => .sret, + .i32_array => |len| if (len == 1) .{ .mem_cast = .i32 } else .sret, + .byval => .forceByVal(o, ret_ty), + }, + .loongarch32_ilp32, .loongarch64_lp64 => switch (loongarch_c_abi.classifyType(ret_ty, zcu)) { + .ignored => .void, + .gar, .far => .by_val, + .member => |member_ty| .{ .mem_cast = try o.lowerType(member_ty, .as_value) }, + .member_pair => |member_tys| .{ .mem_cast = try o.builder.structType(.normal, &.{ + try o.lowerType(member_tys[0], .as_value), + try o.lowerType(member_tys[1], .as_value), + }) }, + .memory_gar => .{ .mem_cast = switch (cc) { + else => unreachable, + .loongarch32_ilp32 => .i32, + .loongarch64_lp64 => .i64, + } }, + .memory_gar_pair => .{ .mem_cast = try o.builder.arrayType(2, switch (cc) { + else => unreachable, + .loongarch32_ilp32 => .i32, + .loongarch64_lp64 => .i64, + }) }, + .address => .sret, }, .mips_o32 => switch (mips_c_abi.classifyType(ret_ty, zcu, .ret)) { - .memory, .i32_array => return .sret, - .byval => return .forceByVal(o, ret_ty), + .memory, .i32_array => .sret, + .byval => .forceByVal(o, ret_ty), }, + .powerpc64_elf_v2 => if (isByRef(ret_ty, zcu)) switch (ret_ty.abiSize(zcu)) { + 1...8 => .{ .mem_cast = try o.builder.intType(@intCast(ret_ty.abiSize(zcu) * 8)) }, + 9...16 => .{ .mem_cast = try o.builder.structType(.normal, &.{ .i64, .i64 }) }, + else => .sret, + } else .by_val, // TODO .riscv64_lp64, .riscv32_ilp32 => switch (riscv_c_abi.classifyType(ret_ty, zcu)) { - .memory => return .sret, - .integer => return .{ .mem_cast = try o.builder.intType(@intCast(ret_ty.abiSize(zcu) * 8)) }, + .memory => .sret, + .integer => .{ .mem_cast = try o.builder.intType(@intCast(ret_ty.abiSize(zcu) * 8)) }, .double_integer => { const integer: Builder.Type = switch (zcu.getTarget().cpu.arch) { .riscv64, .riscv64be => .i64, @@ -7073,34 +7494,78 @@ pub fn fnReturnStrat(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err }; return .{ .mem_cast = try o.builder.structType(.normal, &.{ integer, integer }) }; }, - .byval => return .forceByVal(o, ret_ty), + .byval => .forceByVal(o, ret_ty), .fields => { var types_len: usize = 0; var types: [8]Builder.Type = undefined; for (0..ret_ty.structFieldCount(zcu)) |field_index| { const field_ty = ret_ty.fieldType(field_index, zcu); if (!field_ty.hasRuntimeBits(zcu)) continue; - types[types_len] = try o.lowerType(field_ty, .by_value); + types[types_len] = try o.lowerType(field_ty, .as_value); types_len += 1; } return .{ .mem_cast = try o.builder.structType(.normal, types[0..types_len]) }; }, }, - .wasm_mvp => switch (wasm_c_abi.classifyType(ret_ty, zcu)) { + .s390x_sysv, .s390x_sysv_vx => switch (s390x_c_abi.classifyType(ret_ty, .ret, zcu)) { + .none => .void, + .double_or_float, .vector, .simple => .by_val, + .simple_aggregate => unreachable, + .pointer => .sret, + }, + .wasm_mvp => switch (wasm_c_abi.classifyTypeForLlvm(ret_ty, zcu)) { .direct => |scalar_ty| if (scalar_ty.toIntern() == ret_ty.toIntern()) { assert(!isByRef(ret_ty, zcu)); return .by_val; - } else { - return .{ .mem_cast = try o.lowerType(scalar_ty, .by_value) }; - }, - .indirect => return .sret, + } else .{ .mem_cast = try o.lowerType(scalar_ty, .as_value) }, + .indirect => .sret, }, + .x86_stdcall => if (isScalar(zcu, ret_ty)) { + assert(!isByRef(ret_ty, zcu)); + return .by_val; + } else .sret, + .x86_fastcall => fnReturnStrat_x86_fastcall(o, zcu, ret_ty), + .x86_sysv, .x86_win, .x86_mingw => if (isByRef(ret_ty, zcu)) { + switch (cc) { + else => unreachable, + .x86_sysv => return .sret, + .x86_win => {}, + .x86_mingw => { + var items_buf: [1]codegen.FlattenedItem = undefined; + if (codegen.flattenType(&items_buf, ret_ty, zcu, .{})) |items| one_float: { + if (items.len != 1 or items[0].offset != 0) break :one_float; + const item_ty = items[0].type orelse break :one_float; + if (!item_ty.isRuntimeFloat()) break :one_float; + return .{ .mem_cast = switch (item_ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16 => .half, + 32 => .float, + 64 => .double, + 80, 128 => break :one_float, + } }; + } + }, + } + return switch (ret_ty.abiSize(zcu)) { + 0 => .void, + 1 => .{ .mem_cast = .i8 }, + 2 => .{ .mem_cast = .i16 }, + 4 => .{ .mem_cast = .i32 }, + 8 => .{ .mem_cast = .i64 }, + else => .sret, + }; + } else if (ret_ty.isAbiInt(zcu) and ret_ty.intInfo(zcu).bits > 64) + .sret + else + .by_val, + .x86_64_sysv, .x86_64_x32 => fnReturnStrat_x86_64_sysv(o, ret_ty), + .x86_64_win => fnReturnStrat_x86_64_win(o, ret_ty), // TODO investigate other callconvs - else => return .forceByVal(o, ret_ty), - } + else => .forceByVal(o, ret_ty), + }; } -fn lowerX86FastcallFnRetTy(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnReturnStrat { +fn fnReturnStrat_x86_fastcall(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnReturnStrat { if (isScalar(zcu, ty)) { assert(!isByRef(ty, zcu)); return .by_val; @@ -7115,9 +7580,8 @@ fn lowerX86FastcallFnRetTy(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnRe return .sret; } -fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat { +fn fnReturnStrat_x86_64_win(o: *Object, ret_ty: Type) Allocator.Error!FnReturnStrat { const zcu = o.zcu; - const ret_ty = Type.fromInterned(fn_info.return_type); switch (x86_64_abi.classifyWindows(ret_ty, zcu, zcu.getTarget(), .ret)) { .integer => if (isScalar(zcu, ret_ty)) { assert(!isByRef(ret_ty, zcu)); @@ -7150,78 +7614,65 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err } } -fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat { +fn fnReturnStrat_x86_64_sysv(o: *Object, ret_ty: Type) Allocator.Error!FnReturnStrat { const zcu = o.zcu; - const ip = &zcu.intern_pool; - const ret_ty = Type.fromInterned(fn_info.return_type); - if (isScalar(zcu, ret_ty)) { - assert(!isByRef(ret_ty, zcu)); - return .by_val; - } const classes = x86_64_abi.classifySystemV(ret_ty, zcu, zcu.getTarget(), .ret); - var types_index: u32 = 0; var types_buffer: [8]Builder.Type = undefined; - for (classes) |class| { - switch (class) { - .integer => { - types_buffer[types_index] = .i64; - types_index += 1; - }, - .sse => { - types_buffer[types_index] = .double; - types_index += 1; - }, - .sseup => { - if (types_buffer[types_index - 1] == .double) { - types_buffer[types_index - 1] = .fp128; - } else { - types_buffer[types_index] = .double; - types_index += 1; - } - }, - .float => { - types_buffer[types_index] = .float; - types_index += 1; - }, - .float_combine => { - types_buffer[types_index] = try o.builder.vectorType(.normal, 2, .float); - types_index += 1; - }, - .x87 => { - if (types_index != 0 or classes[2] != .none) return .sret; - types_buffer[types_index] = .x86_fp80; - types_index += 1; - }, - .x87up => continue, - .none => break, - .memory => return .sret, - .win_i128 => unreachable, // windows only - .bool_vector_mask, - .integer_per_element, - .sse_per_element, - .sse_sse_x87_per_qword, - .sse_per_xword, - .sse_per_yword, - .sse_per_zword, - => unreachable, // vectors already handled by `isScalar` above - } + var types_len: u32 = 0; + for (classes, 0..) |class, class_index| switch (class) { + .integer => { + types_buffer[types_len] = try o.builder.intType(@min(8 * ret_ty.abiSize(zcu) - 64 * class_index, 64)); + types_len += 1; + }, + .sse => { + types_buffer[types_len] = .double; + types_len += 1; + }, + .sseup => { + if (types_buffer[types_len - 1] == .double) { + if (ret_ty.isVector(zcu)) return .by_val; + types_buffer[types_len - 1] = .fp128; + } else { + types_buffer[types_len] = .double; + types_len += 1; + } + }, + .float => { + types_buffer[types_len] = .float; + types_len += 1; + }, + .float_combine => { + types_buffer[types_len] = try o.builder.vectorType(.normal, 2, .float); + types_len += 1; + }, + .x87 => { + if (types_len > 0 or classes[2] != .none) return .sret; + types_buffer[types_len] = .x86_fp80; + types_len += 1; + }, + .x87up => continue, + .none => break, + .memory => return if (ret_ty.isVector(zcu)) .by_val else .sret, + .win_i128 => unreachable, // windows only + .bool_vector_mask, + .integer_per_element, + .sse_per_element, + .sse_sse_x87_per_qword, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => return .by_val, + }; + if (types_len > 1) return .{ .mem_cast = try o.builder.structType(.normal, types_buffer[0..types_len]) }; + if (!isByRef(ret_ty, zcu)) { + const llvm_ty = try o.lowerType(ret_ty, .as_value); + if (types_buffer[0] == llvm_ty) return .by_val; + if (types_buffer[0] == .i64 and llvm_ty.isPointer(&o.builder)) return .by_val; + if (types_buffer[0] == .double and llvm_ty.isVector(&o.builder) and + llvm_ty.vectorLen(&o.builder) == 1 and + llvm_ty.scalarType(&o.builder) == .double) return .by_val; } - const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer}); - if (first_non_integer == null or classes[first_non_integer.?] == .none) { - assert(first_non_integer orelse classes.len == types_index); - switch (ip.indexToKey(ret_ty.toIntern())) { - .struct_type => { - const size = ret_ty.abiSize(zcu); - assert(@divCeil(size, 8) == types_index); - if (size % 8 > 0) { - types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8)); - } - }, - else => {}, - } - if (types_index == 1) return .{ .mem_cast = types_buffer[0] }; - } - return .{ .mem_cast = try o.builder.structType(.normal, types_buffer[0..types_index]) }; + return .{ .mem_cast = types_buffer[0] }; } /// This function deliberately does not handle `_BitInt` because it typically @@ -7234,15 +7685,22 @@ pub fn ccAbiPromoteInt(cc: std.lang.CallingConvention, zcu: *Zcu, ty: Type) ?std else => {}, } - const ty_tag = ty.zigTypeTag(zcu); - const int_info = switch (ty_tag) { - .bool => Type.u1.intInfo(zcu), - else => if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else return null, - }; - - assert(int_info.bits == 0 or (int_info.bits == 1 and ty_tag == .bool) or std.math.isPowerOfTwo(int_info.bits)); - const target = zcu.getTarget(); + const int_info: std.lang.Type.Int = if (ty.toIntern() == .bool_type) + .{ .signedness = .unsigned, .bits = 1 } + else if (ty.isAbiInt(zcu)) + ty.intInfo(zcu) + else if (ty.isRuntimeFloat()) switch (ty.floatBits(target)) { + else => unreachable, + 16, 32, 64 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => return null, + .soft => .{ .signedness = .unsigned, .bits = bits }, + }, + 80, 128 => return null, + } else return null; + + assert(int_info.bits == 0 or (int_info.bits == 1 and ty.toIntern() == .bool_type) or std.math.isPowerOfTwo(int_info.bits)); + return switch (target.cpu.arch) { .aarch64, .aarch64_be, @@ -7338,15 +7796,26 @@ pub fn isByRef(ty: Type, zcu: *const Zcu) bool { .void, .bool, .int, - .float, .pointer, .error_set, .@"fn", .@"enum", - .vector, .@"anyframe", => false, + .float, .vector => { + const target = zcu.getTarget(); + const scalar_ty = ty.scalarType(zcu); + return if (scalar_ty.isRuntimeFloat()) switch (scalar_ty.floatBits(target)) { + else => unreachable, + 16, 32, 64 => false, + 80, 128 => |bits| switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => false, + .soft => true, + }, + } else false; + }, + .array, .frame, => ty.hasRuntimeBits(zcu), @@ -7392,7 +7861,7 @@ fn getAtomicAbiType(fg: *const FuncGen, ty: Type, is_rmw_xchg: bool) Allocator.E fn ptraddConst(fg: *FuncGen, ptr: Builder.Value, offset: u64) Allocator.Error!Builder.Value { if (offset == 0) return ptr; const o = fg.object; - const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const llvm_usize_ty = try o.lowerType(.usize, .as_value); const offset_val = try o.builder.intValue(llvm_usize_ty, offset); return fg.wip.gep(.inbounds, .i8, ptr, &.{offset_val}, ""); } @@ -7407,12 +7876,19 @@ fn ptraddScaled(fg: *FuncGen, ptr: Builder.Value, index: Builder.Value, scale: u return fg.wip.gep(.inbounds, llvm_scale_ty, ptr, &.{index}, ""); } -fn compilerRtIntBits(bits: u16) ?u16 { - inline for (.{ 32, 64, 128 }) |b| { - if (bits <= b) { - return b; - } - } +fn compilerRtPromoteInt(int_info: InternPool.Key.IntType) ?Type { + if (int_info.bits <= 32) return switch (int_info.signedness) { + .signed => .i32, + .unsigned => .u32, + }; + if (int_info.bits <= 64) return switch (int_info.signedness) { + .signed => .i64, + .unsigned => .u64, + }; + if (int_info.bits <= 128) return switch (int_info.signedness) { + .signed => .i128, + .unsigned => .u128, + }; return null; } @@ -7471,13 +7947,21 @@ fn appendConstraints( } /// LLVM does not support all relevant intrinsics for all targets, so we -/// may need to manually generate a compiler-rt call. -fn intrinsicsAllowed(scalar_ty: Type, target: *const std.Target) bool { - return switch (scalar_ty.toIntern()) { - .f16_type => llvm.backendSupportsF16(target), - .f80_type => (target.cTypeBitSize(.longdouble) == 80) and llvm.backendSupportsF80(target), - .f128_type => (target.cTypeBitSize(.longdouble) == 128) and llvm.backendSupportsF128(target), - else => true, +/// may need to manually generate a compiler-rt call using a soft type. +fn intrinsicsAllowed(kind: enum { compiler_rt, libc }, scalar_ty: Type, target: *const std.Target) bool { + if (!scalar_ty.isRuntimeFloat()) return true; + const bits = scalar_ty.floatBits(target); + // Since upstream musl/msvc do not actually define the *f128 functions, llvm decides + // that it is a much better idea to just emit a call to the entirely wrong function as + // a fallback. We wouldn't want any linker errors when trying to perform an operation + // that isn't actually implemented anywhere, now would we! + if (bits == 128 and target.cpu.arch.isX86() and !target.abi.isGnu()) return switch (kind) { + .compiler_rt => true, + .libc => false, + }; + return switch (std.zig.target.compilerRtFloatAbi(target, bits)) { + .hard => true, + .soft => false, }; } @@ -7823,12 +8307,14 @@ const Builder = std.zig.llvm.Builder; const assert = std.debug.assert; const math = std.math; -const x86_64_abi = @import("../x86_64/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("../riscv64/abi.zig"); +const loongarch_c_abi = @import("../loongarch/abi.zig"); const mips_c_abi = @import("../mips/abi.zig"); +const riscv_c_abi = @import("../riscv64/abi.zig"); +const s390x_c_abi = @import("../s390x/abi.zig"); +const wasm_c_abi = @import("../wasm/abi.zig"); +const x86_64_abi = @import("../x86_64/abi.zig"); const Zcu = @import("../../Zcu.zig"); const Air = @import("../../Air.zig"); diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index e4f4d6eafefcca250babb49e4a907eba22866d22..a312285db3310ba0fc69dffe55d56e484c293e50 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -331,6 +331,8 @@ extern fn ZigLLVMWriteArchive( file_names_ptr: [*]const [*:0]const u8, file_names_len: usize, archive_kind: ArchiveKind, + err_file_index_out: *usize, + err_msg_out: *[*:0]u8, ) bool; pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions; diff --git a/src/codegen/loongarch/abi.zig b/src/codegen/loongarch/abi.zig new file mode 100644 index 0000000000000000000000000000000000000000..ba9b79d39d5be3d10e20176bc5574c9205df5ad7 --- /dev/null +++ b/src/codegen/loongarch/abi.zig @@ -0,0 +1,133 @@ +const std = @import("std"); +const InternPool = @import("../../InternPool.zig"); +const Type = @import("../../Type.zig"); +const Zcu = @import("../../Zcu.zig"); + +pub const Class = union(enum) { + ignored, + gar, + far, + member: Type, + member_pair: [2]Type, + memory_gar, + memory_gar_pair, + address, + + fn combineMember(container_class: Class, member_class: Class, member_ty: Type) Class { + const second_member_ty = switch (member_class) { + .ignored => return container_class, + .gar, .far => member_ty, + .member => |second_member_ty| second_member_ty, + .member_pair, .memory_gar, .memory_gar_pair, .address => return .address, + }; + return switch (container_class) { + .ignored => .{ .member = second_member_ty }, + .gar, .far, .memory_gar, .memory_gar_pair => unreachable, + .member => |first_member_ty| .{ .member_pair = .{ first_member_ty, second_member_ty } }, + .member_pair, .address => .address, + }; + } +}; + +pub fn classifyType(ty: Type, zcu: *Zcu) Class { + return Classifier.init(zcu).classifyType(ty); +} + +const Classifier = struct { + zcu: *Zcu, + target: *const std.Target, + grlen: u8, + frlen: u8, + + fn init(zcu: *Zcu) Classifier { + const target = zcu.getTarget(); + return .{ + .zcu = zcu, + .target = target, + .grlen = switch (target.cpu.arch) { + else => unreachable, + .loongarch32 => 32, + .loongarch64 => 64, + }, + .frlen = if (target.cpu.has(.loongarch, .d)) + 64 + else if (target.cpu.has(.loongarch, .f)) + 32 + else + 0, + }; + } + + fn classifyType(c: Classifier, ty: Type) Class { + switch (ty.zigTypeTag(c.zcu)) { + .type, + .comptime_float, + .comptime_int, + .undefined, + .null, + .error_union, + .error_set, + .@"fn", + .@"opaque", + .frame, + .@"anyframe", + .enum_literal, + .spirv, + => unreachable, + .void, .noreturn => return .ignored, + .bool => return .gar, + .int, .@"enum" => { + const bits = ty.intInfo(c.zcu).bits; + if (bits == 0) return .ignored; + if (bits <= c.grlen) return .gar; + if (bits <= 2 * c.grlen) return .memory_gar_pair; + return .address; + }, + .float => { + const bits = ty.floatBits(c.target); + if (bits <= c.frlen) return .far; + if (bits <= c.grlen) return .gar; + if (bits <= 2 * c.grlen) return .memory_gar_pair; + return .address; + }, + .pointer, .optional => return .gar, + .array => { + var class: Class = .ignored; + const elem_ty = ty.childType(c.zcu); + const elem_class = c.classifyType(elem_ty); + for (0..std.math.lossyCast(usize, ty.arrayLenIncludingSentinel(c.zcu))) |_| { + class = class.combineMember(elem_class, elem_ty); + if (class == .address) break; + } + if (class != .address) return class; + }, + .@"struct" => switch (ty.containerLayout(c.zcu)) { + .auto => unreachable, + .@"extern" => { + var class: Class = .ignored; + var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (c.zcu.typeToStruct(ty)) |loaded_struct| + loaded_struct.iterateRuntimeOrder(&c.zcu.intern_pool) + else + .{ .runtime_order = null, .fields_len = ty.structFieldCount(c.zcu), .next_index = 0 }; + while (field_it.next()) |field_index| { + const field_ty = ty.fieldType(field_index, c.zcu); + class = class.combineMember(c.classifyType(field_ty), field_ty); + if (class == .address) break; + } + if (class != .address) return class; + }, + .@"packed" => return c.classifyType(ty.backingIntType(c.zcu)), + }, + .@"union" => switch (ty.containerLayout(c.zcu)) { + .auto => unreachable, + .@"extern" => {}, + .@"packed" => return c.classifyType(ty.backingIntType(c.zcu)), + }, + .vector => {}, + } + const size = ty.abiSize(c.zcu); + if (size <= @divExact(c.grlen, 8)) return .memory_gar; + if (size <= @divExact(2 * c.grlen, 8)) return .memory_gar_pair; + return .address; + } +}; diff --git a/src/codegen/mips/abi.zig b/src/codegen/mips/abi.zig index f512f1e6db98031dd581bc9cb19ef7be42b7ae29..e7c07582030cc16d73f07b0d56d56f09f0607a0f 100644 --- a/src/codegen/mips/abi.zig +++ b/src/codegen/mips/abi.zig @@ -38,7 +38,14 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { return .byval; }, .bool => return .byval, - .float => return .byval, + .float => return switch (ty.floatBits(target)) { + else => unreachable, + 16, 32, 64 => .byval, + 80, 128 => switch (max_direct_size) { + else => unreachable, + 64 => .memory, + }, + }, .int, .@"enum", .error_set => { return .byval; }, diff --git a/src/codegen/riscv64/CodeGen.zig b/src/codegen/riscv64/CodeGen.zig index 2b953f3bbef4ac4924b37ac4cb3d8f524b7bc9d9..1a6ae84190bf394992f5e30b305de583be9b5829 100644 --- a/src/codegen/riscv64/CodeGen.zig +++ b/src/codegen/riscv64/CodeGen.zig @@ -5036,7 +5036,7 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void { .register_pair, => { if (ret_ty.isVector(zcu)) { - const bit_size = ret_ty.totalVectorBits(zcu); + const bit_size = ret_ty.bitSize(zcu); // set the vtype to hold the entire vector's contents in a single element try func.setVl(.zero, 0, .{ @@ -6235,8 +6235,8 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void { next_op: for (&ops) |*op| { const op_str = while (!last_op) { const full_str = op_it.next() orelse break :next_op; - const code_str = if (mem.indexOfScalar(u8, full_str, '#') orelse - mem.indexOf(u8, full_str, "//")) |comment| + const code_str = if (mem.findScalar(u8, full_str, '#') orelse + mem.find(u8, full_str, "//")) |comment| code: { last_op = true; break :code full_str[0..comment]; @@ -6250,7 +6250,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void { } else if (std.fmt.parseInt(i12, op_str, 10)) |int| { op.* = .{ .imm = Immediate.s(int) }; } else |_| if (mem.startsWith(u8, op_str, "%[")) { - const mod_index = mem.indexOf(u8, op_str, "]@"); + const mod_index = mem.find(u8, op_str, "]@"); const modifier = if (mod_index) |index| op_str[index + "]@".len ..] else @@ -6871,7 +6871,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! // size to the total size of the vector, and vmv.x.s will work then if (src_reg.class() == .vector) { try func.setVl(.zero, 0, .{ - .vsew = switch (ty.totalVectorBits(zcu)) { + .vsew = switch (ty.bitSize(zcu)) { 8 => .@"8", 16 => .@"16", 32 => .@"32", @@ -8339,9 +8339,9 @@ fn resolveCallingConventionValues( fn wantSafety(func: *Func) bool { return switch (func.mod.optimize_mode) { .Debug => true, - .ReleaseSafe => true, - .ReleaseFast => false, - .ReleaseSmall => false, + .safe => true, + .fast => false, + .small => false, }; } diff --git a/src/codegen/riscv64/abi.zig b/src/codegen/riscv64/abi.zig index 5c89a35f7bd4e718e8e032093856f6068b751c9b..154118c50c98572fea63fcc00986c7cc338b3ca6 100644 --- a/src/codegen/riscv64/abi.zig +++ b/src/codegen/riscv64/abi.zig @@ -56,12 +56,20 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { return .integer; }, .bool => return .integer, - .float => return .byval, .int, .@"enum", .error_set => { const bit_size = ty.bitSize(zcu); if (bit_size > max_byval_size) return .memory; return .byval; }, + .float => return switch (ty.floatBits(target)) { + else => unreachable, + 16, 32, 64, 128 => .byval, + 80 => switch (max_byval_size) { + else => unreachable, + 64 => .memory, + 128 => .double_integer, + }, + }, .vector => { const bit_size = ty.bitSize(zcu); if (bit_size > max_byval_size) return .memory; @@ -190,7 +198,7 @@ pub fn classifySystem(ty: Type, zcu: *Zcu) [8]SystemClass { }, .vector => { // we pass vectors through integer registers if they are small enough to fit. - const vec_bits = ty.totalVectorBits(zcu); + const vec_bits = ty.bitSize(zcu); if (vec_bits <= 64) { result[0] = .integer; return result; diff --git a/src/codegen/riscv64/encoding.zig b/src/codegen/riscv64/encoding.zig index 40de9855cd342b35ea2ba540a20d589822c1b76f..5ca6a094d774fbaeb6a96c6c75ecd26a903da705 100644 --- a/src/codegen/riscv64/encoding.zig +++ b/src/codegen/riscv64/encoding.zig @@ -498,7 +498,7 @@ pub const Instruction = union(Lir.Format) { extra: u32, comptime { - for (std.meta.fieldTypes(Instruction)) |field_type| { + for (@typeInfo(Instruction).@"union".field_types) |field_type| { assert(@bitSizeOf(field_type) == 32); } } diff --git a/src/codegen/s390x/abi.zig b/src/codegen/s390x/abi.zig new file mode 100644 index 0000000000000000000000000000000000000000..2c3051ffc3139a314cedadf9ec98027d846a7dd3 --- /dev/null +++ b/src/codegen/s390x/abi.zig @@ -0,0 +1,85 @@ +const assert = std.debug.assert; +const std = @import("std"); +const InternPool = @import("../../InternPool.zig"); +const Type = @import("../../Type.zig"); +const Zcu = @import("../../Zcu.zig"); + +pub const Context = enum { ret, arg }; + +pub const Class = enum { + none, + double_or_float, + vector, + simple, + simple_aggregate, + pointer, +}; + +pub fn classifyType(ty: Type, context: Context, zcu: *Zcu) Class { + tag: switch (ty.zigTypeTag(zcu)) { + .type, + .comptime_float, + .comptime_int, + .undefined, + .null, + .error_union, + .error_set, + .@"fn", + .@"opaque", + .frame, + .@"anyframe", + .enum_literal, + .spirv, + => unreachable, + .void, .noreturn => return .none, + .bool => return .simple, + .int, .@"enum" => return switch (ty.intInfo(zcu).bits) { + 0 => .none, + 1...64 => .simple, + else => .pointer, + }, + .float => switch (ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16, 32, 64 => return .double_or_float, + 80 => {}, + 128 => return .pointer, + }, + .pointer, .optional => return .simple, + .array => {}, + .@"struct", .@"union" => |tag| switch (ty.containerLayout(zcu)) { + .auto => unreachable, + .@"extern" => switch (context) { + .ret => {}, + .arg => { + var class: Class = .none; + for (0..switch (tag) { + else => unreachable, + .@"struct" => ty.structFieldCount(zcu), + .@"union" => ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu), + }) |field_index| { + switch (tag) { + else => unreachable, + .@"struct" => if (ty.structFieldIsComptime(field_index, zcu)) continue, + .@"union" => {}, + } + const field_class = classifyType(ty.fieldType(field_index, zcu), context, zcu); + if (field_class == .none) continue; + if (class != .none) break :tag; + class = field_class; + } + return class; + }, + }, + .@"packed" => return classifyType(ty.backingIntType(zcu), context, zcu), + }, + .vector => return if (ty.abiSize(zcu) <= 16) .vector else .pointer, + } + return switch (ty.abiSize(zcu)) { + 0 => .none, + 1, 2, 4, 8 => switch (context) { + .ret => .pointer, + .arg => .simple_aggregate, + }, + else => .pointer, + }; +} diff --git a/src/codegen/sparc64/CodeGen.zig b/src/codegen/sparc64/CodeGen.zig index c5161485d377a68949901d6ed882346289a1c354..be9102f81ec684c11afe4cce59742823704b3175 100644 --- a/src/codegen/sparc64/CodeGen.zig +++ b/src/codegen/sparc64/CodeGen.zig @@ -4764,9 +4764,9 @@ fn truncRegister( fn wantSafety(self: *Self) bool { return switch (self.bin_file.comp.root_mod.optimize_mode) { .Debug => true, - .ReleaseSafe => true, - .ReleaseFast => false, - .ReleaseSmall => false, + .safe => true, + .fast => false, + .small => false, }; } diff --git a/src/codegen/spirv/Assembler.zig b/src/codegen/spirv/Assembler.zig index aa80b4257ecc0756a463b58a550155ba56f22d04..6a96b5e3a00445176a67e085a0ca27cbd2f88dd3 100644 --- a/src/codegen/spirv/Assembler.zig +++ b/src/codegen/spirv/Assembler.zig @@ -24,8 +24,9 @@ inst: struct { opcode: Opcode = undefined, operands: std.ArrayList(Operand) = .empty, string_bytes: std.ArrayList(u8) = .empty, + inst_offset: u32 = 0, - fn result(ass: @This()) ?AsmValue.Ref { + fn result(ass: *const @This()) ?AsmValue.Ref { for (ass.operands.items[0..@min(ass.operands.items.len, 2)]) |op| { switch (op) { .result_id => |index| return index, @@ -35,7 +36,7 @@ inst: struct { return null; } } = .{}, -value_map: std.array_hash_map.String(AsmValue) = .{}, +value_map: std.array_hash_map.String(AsmValue) = .empty, inst_map: std.array_hash_map.String(void) = .empty, const Operand = union(enum) { @@ -82,7 +83,7 @@ pub fn assemble(ass: *Assembler, src: []const u8) Error!void { if (ass.inst_map.count() == 0) { const instructions = spec.InstructionSet.core.instructions(); try ass.inst_map.ensureUnusedCapacity(gpa, @intCast(instructions.len)); - for (spec.InstructionSet.core.instructions(), 0..) |inst, i| { + for (instructions, 0..) |inst, i| { const entry = try ass.inst_map.getOrPut(gpa, inst.name); assert(entry.index == i); } @@ -114,12 +115,13 @@ fn addError(ass: *Assembler, offset: u32, comptime fmt: []const u8, args: anytyp } fn fail(ass: *Assembler, offset: u32, comptime fmt: []const u8, args: anytype) Error { + @branchHint(.cold); try ass.addError(offset, fmt, args); return error.AssembleFail; } fn todo(ass: *Assembler, comptime fmt: []const u8, args: anytype) Error { - return ass.fail(0, "todo: " ++ fmt, args); + return ass.fail(ass.inst.inst_offset, "todo: " ++ fmt, args); } const AsmValue = union(enum) { @@ -177,19 +179,19 @@ fn processInstruction(ass: *Assembler) !void { const cg = ass.cg; const result: AsmValue = switch (ass.inst.opcode) { .OpEntryPoint => { - return ass.fail(ass.currentToken().start, "cannot export entry points in assembly", .{}); + return ass.fail(ass.inst.inst_offset, "cannot export entry points in assembly", .{}); }, .OpExecutionMode, .OpExecutionModeId => { - return ass.fail(ass.currentToken().start, "cannot set execution mode in assembly", .{}); + return ass.fail(ass.inst.inst_offset, "cannot set execution mode in assembly", .{}); }, .OpCapability, .OpExtension => { - return ass.fail(ass.currentToken().start, "cannot declare capabilities or extensions in assembly; use -mcpu instead", .{}); + return ass.fail(ass.inst.inst_offset, "cannot declare capabilities or extensions in assembly; use -mcpu instead", .{}); }, .OpExtInstImport => blk: { const set_name_offset = ass.inst.operands.items[1].string; const set_name = std.mem.sliceTo(ass.inst.string_bytes.items[set_name_offset..], 0); const set_tag = std.meta.stringToEnum(spec.InstructionSet, set_name) orelse { - return ass.fail(set_name_offset, "unknown instruction set: {s}", .{set_name}); + return ass.fail(ass.inst.inst_offset, "unknown instruction set: {s}", .{set_name}); }; break :blk .{ .value = try cg.importInstructionSet(set_tag) }; }, @@ -209,9 +211,8 @@ fn processInstruction(ass: *Assembler) !void { switch (ass.value_map.values()[result_ref]) { .just_declared => ass.value_map.values()[result_ref] = result, else => { - // TODO: Improve source location. const name = ass.value_map.keys()[result_ref]; - return ass.fail(0, "duplicate definition of %{s}", .{name}); + return ass.fail(ass.inst.inst_offset, "duplicate definition of %{s}", .{name}); }, } } @@ -229,12 +230,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { 0 => .unsigned, 1 => .signed, else => { - // TODO: Improve source location. - return ass.fail(0, "{} is not a valid signedness (expected 0 or 1)", .{operands[2].literal32}); + return ass.fail(ass.inst.inst_offset, "{} is not a valid signedness (expected 0 or 1)", .{operands[2].literal32}); }, }; const width = std.math.cast(u16, operands[1].literal32) orelse { - return ass.fail(0, "int type of {} bits is too large", .{operands[1].literal32}); + return ass.fail(ass.inst.inst_offset, "int type of {} bits is too large", .{operands[1].literal32}); }; break :blk try cg.intType(signedness, width); }, @@ -243,7 +243,7 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { switch (bits) { 16, 32, 64 => {}, else => { - return ass.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits}); + return ass.fail(ass.inst.inst_offset, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits}); }, } break :blk try cg.floatType(@intCast(bits)); @@ -366,38 +366,40 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue { var maybe_result_id: ?Id = null; const first_word = section.instructions.items.len; - // At this point we're not quite sure how many operands this instruction is - // going to have, so insert 0 and patch up the actual opcode word later. - try section.ensureUnusedCapacity(cg.gpa, 1); + + // Pre-calculate exact instruction size to avoid per-operand capacity checks. + var total_words: usize = 1; // 1 word for the opcode itself + for (operands) |operand| { + total_words += switch (operand) { + .value, .literal32, .result_id, .ref_id => 1, + .literal64 => 2, + .string => |offset| blk: { + const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0); + break :blk @divCeil(text.len + 1, @sizeOf(Word)); + }, + }; + } + + try section.ensureUnusedCapacity(cg.gpa, total_words); section.writeWord(0); for (operands) |operand| { switch (operand) { - .value, .literal32 => |word| { - try section.ensureUnusedCapacity(cg.gpa, 1); - section.writeWord(word); - }, - .literal64 => |dword| { - try section.ensureUnusedCapacity(cg.gpa, 2); - section.writeDoubleWord(dword); - }, + .value, .literal32 => |word| section.writeWord(word), + .literal64 => |dword| section.writeDoubleWord(dword), .result_id => { maybe_result_id = if (maybe_spv_decl_index) |spv_decl_index| cg.declPtr(spv_decl_index).result_id else cg.allocId(); - try section.ensureUnusedCapacity(cg.gpa, 1); section.writeOperand(Id, maybe_result_id.?); }, .ref_id => |index| { const result = try ass.resolveRef(index); - try section.ensureUnusedCapacity(cg.gpa, 1); section.writeOperand(spec.Id, result.resultId()); }, .string => |offset| { const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0); - const size = @divCeil(text.len + 1, @sizeOf(Word)); - try section.ensureUnusedCapacity(cg.gpa, size); section.writeOperand(spec.LiteralString, text); }, } @@ -445,11 +447,11 @@ fn processSpecConstVector(ass: *Assembler) !?AsmValue { const gpa = cg.gpa; const ty_ref = switch (ass.inst.operands.items[0]) { .ref_id => |i| i, - else => return ass.fail(0, "missing result type", .{}), + else => return ass.fail(ass.inst.inst_offset, "missing result type", .{}), }; const composite_ty_id = switch (try ass.resolveRef(ty_ref)) { .ty => |id| id, - else => return ass.fail(0, "%ty must be a type", .{}), + else => return ass.fail(ass.inst.inst_offset, "%ty must be a type", .{}), }; const globals = &cg.sections.globals; @@ -483,7 +485,7 @@ fn processSpecConstVector(ass: *Assembler) !?AsmValue { } const spec_id_word = std.math.cast(u32, spec_id_base + i) orelse { - return ass.fail(0, "SpecId {} does not fit in 32 bits", .{spec_id_base + i}); + return ass.fail(ass.inst.inst_offset, "SpecId {} does not fit in 32 bits", .{spec_id_base + i}); }; try annotations.emitRaw(gpa, .OpDecorate, 3); annotations.writeOperand(Id, elem_id); @@ -505,8 +507,7 @@ fn resolveMaybeForwardRef(ass: *Assembler, ref: AsmValue.Ref) !AsmValue { switch (value) { .just_declared => { const name = ass.value_map.keys()[ref]; - // TODO: Improve source location. - return ass.fail(0, "ass-referential parameter %{s}", .{name}); + return ass.fail(ass.inst.inst_offset, "self-referential parameter %{s}", .{name}); }, else => return value, } @@ -518,8 +519,7 @@ fn resolveRef(ass: *Assembler, ref: AsmValue.Ref) !AsmValue { .just_declared => unreachable, .unresolved_forward_reference => { const name = ass.value_map.keys()[ref]; - // TODO: Improve source location. - return ass.fail(0, "reference to undeclared result-id %{s}", .{name}); + return ass.fail(ass.inst.inst_offset, "reference to undeclared result-id %{s}", .{name}); }, else => return value, } @@ -536,6 +536,7 @@ fn parseInstruction(ass: *Assembler) !void { ass.inst.opcode = undefined; ass.inst.operands.clearRetainingCapacity(); ass.inst.string_bytes.clearRetainingCapacity(); + ass.inst.inst_offset = ass.currentToken().start; const lhs_result_tok = ass.currentToken(); const maybe_lhs_result: ?AsmValue.Ref = if (ass.eatToken(.result_id_assign)) blk: { @@ -589,8 +590,8 @@ fn parseInstruction(ass: *Assembler) !void { .required => if (ass.isAtInstructionBoundary()) { return ass.fail( ass.currentToken().start, - "missing required operand", // TODO: Operand name? - .{}, + "missing required operand '{s}'", + .{@tagName(operand.kind)}, ); } else { try ass.parseOperand(operand.kind); diff --git a/src/codegen/spirv/CodeGen.zig b/src/codegen/spirv/CodeGen.zig index 7833c787e039be9d0002886293000ed5424203f6..1b46cfbbc1fcb105d85bdb6a0bf7b05a480cbcea 100644 --- a/src/codegen/spirv/CodeGen.zig +++ b/src/codegen/spirv/CodeGen.zig @@ -7280,7 +7280,7 @@ fn structuredBreak(cg: *CodeGen, target_block: Id) !void { if (cg.block_terminated) return; const gpa = cg.gpa; - const sblock = cg.block_stack.getLast().?; + const sblock = cg.block_stack.last().?; const merge_block = switch (sblock.*) { .selection => |*merge| blk: { const merge_label = cg.allocId(); @@ -7447,7 +7447,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) .operand_2 = this_block, }); - const sblock = cg.block_stack.getLast().?; + const sblock = cg.block_stack.last().?; if (ty.isNoReturn(zcu)) { // If this block is noreturn, this instruction is the last of a block, diff --git a/src/codegen/spirv/Section.zig b/src/codegen/spirv/Section.zig index 6207cc787cd0c187c8199fc54efd7c9aaf451efc..fcd7739c1dd3a6916a258e79ce36dae6fec3ba2c 100644 --- a/src/codegen/spirv/Section.zig +++ b/src/codegen/spirv/Section.zig @@ -49,8 +49,9 @@ pub fn emitRaw( operand_words: usize, ) !void { const word_count = 1 + operand_words; + if (word_count > std.math.maxInt(u16)) return error.OutOfMemory; try section.instructions.ensureUnusedCapacity(allocator, word_count); - section.writeWord((@as(Word, @intCast(word_count << 16))) | @backingInt(opcode)); + section.writeWord((@as(Word, @intCast(word_count)) << 16) | @backingInt(opcode)); } /// Write an entire instruction, including all operands @@ -70,7 +71,8 @@ pub fn emitAssumeCapacity( operands: opcode.Operands(), ) !void { const word_count = instructionSize(opcode, operands); - section.writeWord(@as(Word, @intCast(word_count << 16)) | @backingInt(opcode)); + if (word_count > std.math.maxInt(u16)) return error.OutOfMemory; + section.writeWord((@as(Word, @intCast(word_count)) << 16) | @backingInt(opcode)); section.writeOperands(opcode.Operands(), operands); } @@ -81,8 +83,9 @@ pub fn emit( operands: opcode.Operands(), ) !void { const word_count = instructionSize(opcode, operands); + if (word_count > std.math.maxInt(u16)) return error.OutOfMemory; try section.instructions.ensureUnusedCapacity(allocator, word_count); - section.writeWord(@as(Word, @intCast(word_count << 16)) | @backingInt(opcode)); + section.writeWord((@as(Word, @intCast(word_count)) << 16) | @backingInt(opcode)); section.writeOperands(opcode.Operands(), operands); } diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig index e0e73040cab9dedecaaca4c4f843e647e87edcd5..df15671e3379fabd3fbd3e2a75a015367b0e77a0 100644 --- a/src/codegen/wasm/CodeGen.zig +++ b/src/codegen/wasm/CodeGen.zig @@ -24,12 +24,6 @@ const Alignment = InternPool.Alignment; const errUnionPayloadOffset = codegen.errUnionPayloadOffset; const errUnionErrorOffset = codegen.errUnionErrorOffset; -const target_util = @import("../../target.zig"); -const libcFloatPrefix = target_util.libcFloatPrefix; -const libcFloatSuffix = target_util.libcFloatSuffix; -const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev; -const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev; - pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { return comptime &.initMany(&.{ .expand_bit_cast_safe, @@ -573,7 +567,7 @@ fn addCallIntrinsic(cg: *CodeGen, intrinsic: Mir.Intrinsic) error{OutOfMemory}!v /// Appends entries to `mir_extra` based on the type of `extra`. /// Returns the index into `mir_extra` fn addExtra(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 { - const field_count = std.meta.fieldNames(@TypeOf(extra)).len; + const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len; try cg.mir_extra.ensureUnusedCapacity(cg.gpa, field_count); return cg.addExtraAssumeCapacity(extra); } @@ -933,21 +927,26 @@ fn resolveCallingConventionValues( }, .wasm_mvp => { for (fn_info.param_types.get(ip)) |ty| { - if (!Type.fromInterned(ty).hasRuntimeBits(zcu)) { + const param_ty: Type = .fromInterned(ty); + if (!param_ty.hasRuntimeBits(zcu)) { continue; } - switch (abi.classifyType(.fromInterned(ty), zcu)) { - .direct => |scalar_ty| if (!abi.lowerAsDoubleI64(scalar_ty, zcu)) { + + switch (abi.classifyType(param_ty, zcu, target)) { + .direct, .indirect => { try args.append(.{ .local = .{ .value = result.local_index, .references = 1 } }); result.local_index += 1; - } else { + }, + .double_i64 => { try args.append(.{ .local = .{ .value = result.local_index, .references = 1 } }); try args.append(.{ .local = .{ .value = result.local_index + 1, .references = 1 } }); result.local_index += 2; }, - .indirect => { - try args.append(.{ .local = .{ .value = result.local_index, .references = 1 } }); - result.local_index += 1; + .unrolled => |vector| { + for (0..vector.len) |_| { + try args.append(.{ .local = .{ .value = result.local_index, .references = 1 } }); + result.local_index += 1; + } }, } } @@ -974,9 +973,10 @@ pub fn firstParamSRet( switch (cc) { .@"inline" => unreachable, .auto => return isByRef(return_type, zcu, target), - .wasm_mvp => switch (abi.classifyType(return_type, zcu)) { - .direct => |scalar_ty| return abi.lowerAsDoubleI64(scalar_ty, zcu), - .indirect => return true, + .wasm_mvp => switch (abi.classifyType(return_type, zcu, target)) { + .direct => return false, + .double_i64, .indirect => return true, + .unrolled => |vector| return vector.len > 1, }, else => return false, } @@ -991,18 +991,15 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu const zcu = cg.pt.zcu; - switch (abi.classifyType(ty, zcu)) { - .direct => |scalar_type| if (!abi.lowerAsDoubleI64(scalar_type, zcu)) { + switch (abi.classifyType(ty, zcu, cg.target)) { + .direct => |scalar_ty| { if (!isByRef(ty, zcu, cg.target)) { return cg.lowerToStack(value); } else { - switch (value) { - .nav_ref, .stack_offset => _ = try cg.load(value, scalar_type, 0), - .dead => unreachable, - else => try cg.emitWValue(value), - } + _ = try cg.load(value, scalar_ty, 0); } - } else { + }, + .double_i64 => { assert(ty.abiSize(zcu) == 16); // in this case we have an integer or float that must be lowered as 2 i64's. try cg.emitWValue(value); @@ -1010,7 +1007,17 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu try cg.emitWValue(value); try cg.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = 8 }); }, - .indirect => return cg.lowerToStack(value), + .indirect => { + const stack_copy = try cg.allocStack(ty); + try cg.store(stack_copy, value, ty, 0); + return cg.lowerToStack(stack_copy); + }, + .unrolled => |vector| { + const elem_size: u32 = @intCast(vector.elem_type.abiSize(zcu)); + for (0..vector.len) |index| { + _ = try cg.load(value, vector.elem_type, @intCast(index * elem_size)); + } + }, } } @@ -1953,16 +1960,19 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { if (cg.return_value != .none) { try cg.store(cg.return_value, operand, ret_ty, 0); } else if (fn_info.cc == .wasm_mvp and ret_ty.hasRuntimeBits(zcu)) { - switch (abi.classifyType(ret_ty, zcu)) { + switch (abi.classifyType(ret_ty, zcu, cg.target)) { .direct => |scalar_type| { - assert(!abi.lowerAsDoubleI64(scalar_type, zcu)); if (!isByRef(ret_ty, zcu, cg.target)) { try cg.emitWValue(operand); } else { _ = try cg.load(operand, scalar_type, 0); } }, - .indirect => unreachable, + .double_i64, .indirect => unreachable, + .unrolled => |vector| { + assert(vector.len == 1); + _ = try cg.load(operand, vector.elem_type, 0); + }, } } else { if (!ret_ty.hasRuntimeBits(zcu) and ret_ty.isError(zcu)) { @@ -2009,8 +2019,18 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.addImm32(0); } } else if (!firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), zcu, cg.target)) { - // leave on the stack - _ = try cg.load(operand, ret_ty, 0); + if (fn_info.cc == .wasm_mvp) { + switch (abi.classifyType(ret_ty, zcu, cg.target)) { + .direct => |scalar_type| _ = try cg.load(operand, scalar_type, 0), + .double_i64, .indirect => unreachable, + .unrolled => |vector| { + assert(vector.len == 1); + _ = try cg.load(operand, vector.elem_type, 0); + }, + } + } else { + _ = try cg.load(operand, ret_ty, 0); + } } try cg.restoreStackPointer(); @@ -2138,22 +2158,30 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) } else if (first_param_sret) { break :result_value sret; } else if (zcu.typeToFunc(fn_ty).?.cc == .wasm_mvp) { - switch (abi.classifyType(ret_ty, zcu)) { + switch (abi.classifyType(ret_ty, zcu, cg.target)) { .direct => |scalar_type| { - assert(!abi.lowerAsDoubleI64(scalar_type, zcu)); if (!isByRef(ret_ty, zcu, cg.target)) { const result_local = try cg.allocLocal(ret_ty); try cg.addLocal(.local_set, result_local.local.value); break :result_value result_local; } else { - const result_local = try cg.allocLocal(ret_ty); + const result_local = try cg.allocLocal(scalar_type); try cg.addLocal(.local_set, result_local.local.value); const result = try cg.allocStack(ret_ty); try cg.store(result, result_local, scalar_type, 0); break :result_value result; } }, - .indirect => unreachable, + .double_i64, .indirect => unreachable, + .unrolled => |vector| { + assert(vector.len == 1); + const result_local = try cg.allocLocal(vector.elem_type); + // save call result from operand stack + try cg.addLocal(.local_set, result_local.local.value); + const result = try cg.allocStack(ret_ty); + try cg.store(result, result_local, vector.elem_type, 0); + break :result_value result; + }, } } else { const result_local = try cg.allocLocal(ret_ty); @@ -2456,17 +2484,32 @@ fn airArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const cc = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?.cc; const arg_ty = cg.typeOfIndex(inst); if (cc == .wasm_mvp) { - switch (abi.classifyType(arg_ty, zcu)) { - .direct => |scalar_ty| if (!abi.lowerAsDoubleI64(scalar_ty, zcu)) { + switch (abi.classifyType(arg_ty, zcu, cg.target)) { + .direct => |scalar_type| { cg.arg_index += 1; - } else { + if (isByRef(arg_ty, zcu, cg.target)) { + const result = try cg.allocStack(arg_ty); + try cg.store(result, arg, scalar_type, 0); + return cg.finishAir(inst, result, &.{}); + } + }, + .indirect => cg.arg_index += 1, + .double_i64 => { cg.arg_index += 2; const result = try cg.allocStack(arg_ty); try cg.store(result, arg, Type.u64, 0); try cg.store(result, cg.args[arg_index + 1], Type.u64, 8); return cg.finishAir(inst, result, &.{}); }, - .indirect => cg.arg_index += 1, + .unrolled => |vector| { + const result = try cg.allocStack(arg_ty); + const elem_size: u32 = @intCast(vector.elem_type.abiSize(zcu)); + for (0..vector.len) |index| { + try cg.store(result, cg.args[cg.arg_index], vector.elem_type, @intCast(index * elem_size)); + cg.arg_index += 1; + } + return cg.finishAir(inst, result, &.{}); + }, } } else { cg.arg_index += 1; @@ -2515,15 +2558,15 @@ const IntType = struct { .anyerror, .adhoc_inferred_error_set => .{ .is_signed = false, .bits = zcu.errorSetBits() }, .isize => .{ .is_signed = true, .bits = cg.target.ptrBitWidth() }, .usize => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() }, - .c_char => .{ .is_signed = cg.target.cCharSignedness() == .signed, .bits = cg.target.cTypeBitSize(.char) }, - .c_short => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.short) }, - .c_ushort => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.short) }, - .c_int => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.int) }, - .c_uint => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.int) }, - .c_long => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.long) }, - .c_ulong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.long) }, - .c_longlong => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.longlong) }, - .c_ulonglong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.longlong) }, + .c_char => .{ .is_signed = cg.target.cCharSignedness().? == .signed, .bits = cg.target.cTypeBitSize(.char).? }, + .c_short => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.short).? }, + .c_ushort => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.short).? }, + .c_int => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.int).? }, + .c_uint => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.int).? }, + .c_long => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.long).? }, + .c_ulong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.long).? }, + .c_longlong => .{ .is_signed = true, .bits = cg.target.cTypeBitSize(.longlong).? }, + .c_ulonglong => .{ .is_signed = false, .bits = cg.target.cTypeBitSize(.longlong).? }, .f16, .f32, .f64, .f80, .f128, .c_longdouble => unreachable, .anyopaque, .void, .type, .comptime_int, .comptime_float, .noreturn, .null, .undefined, .enum_literal, .generic_poison => unreachable, }, @@ -4340,7 +4383,7 @@ fn floatRem(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerError!WV .f32 => return cg.callIntrinsic(.fmodf, &.{ .f32_type, .f32_type }, Type.f32, &.{ lhs, rhs }), .f64 => return cg.callIntrinsic(.fmod, &.{ .f64_type, .f64_type }, Type.f64, &.{ lhs, rhs }), .f80 => return cg.callIntrinsic(.__fmodx, &.{ .f80_type, .f80_type }, Type.f80, &.{ lhs, rhs }), - .f128 => return cg.callIntrinsic(.fmodq, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), + .f128 => return cg.callIntrinsic(.fmodf128, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), } } @@ -4376,7 +4419,7 @@ fn floatMax(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerError!WV .f32 => return cg.callIntrinsic(.fmaxf, &.{ .f32_type, .f32_type }, Type.f32, &.{ lhs, rhs }), .f64 => return cg.callIntrinsic(.fmax, &.{ .f64_type, .f64_type }, Type.f64, &.{ lhs, rhs }), .f80 => return cg.callIntrinsic(.__fmaxx, &.{ .f80_type, .f80_type }, Type.f80, &.{ lhs, rhs }), - .f128 => return cg.callIntrinsic(.fmaxq, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), + .f128 => return cg.callIntrinsic(.fmaxf128, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), } } @@ -4387,7 +4430,7 @@ fn floatMin(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerError!WV .f32 => return cg.callIntrinsic(.fminf, &.{ .f32_type, .f32_type }, Type.f32, &.{ lhs, rhs }), .f64 => return cg.callIntrinsic(.fmin, &.{ .f64_type, .f64_type }, Type.f64, &.{ lhs, rhs }), .f80 => return cg.callIntrinsic(.__fminx, &.{ .f80_type, .f80_type }, Type.f80, &.{ lhs, rhs }), - .f128 => return cg.callIntrinsic(.fminq, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), + .f128 => return cg.callIntrinsic(.fminf128, &.{ .f128_type, .f128_type }, Type.f128, &.{ lhs, rhs }), } } @@ -4405,7 +4448,7 @@ fn floatSqrt(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__sqrtx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.sqrtq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.sqrtf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4415,7 +4458,7 @@ fn floatSin(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.sinf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.sin, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__sinx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.sinq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.sinf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4425,7 +4468,7 @@ fn floatCos(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.cosf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.cos, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__cosx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.cosq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.cosf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4435,7 +4478,7 @@ fn floatTan(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.tanf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.tan, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__tanx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.tanq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.tanf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4445,7 +4488,7 @@ fn floatExp(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.expf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.exp, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__expx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.expq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.expf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4455,7 +4498,7 @@ fn floatExp2(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.exp2f, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.exp2, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__exp2x, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.exp2q, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.exp2f128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4465,7 +4508,7 @@ fn floatLog(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.logf, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.log, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__logx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.logq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.logf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4475,7 +4518,7 @@ fn floatLog2(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.log2f, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.log2, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__log2x, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.log2q, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.log2f128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4485,7 +4528,7 @@ fn floatLog10(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { .f32 => return cg.callIntrinsic(.log10f, &.{.f32_type}, Type.f32, &.{arg}), .f64 => return cg.callIntrinsic(.log10, &.{.f64_type}, Type.f64, &.{arg}), .f80 => return cg.callIntrinsic(.__log10x, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.log10q, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.log10f128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4503,7 +4546,7 @@ fn floatFloor(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__floorx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.floorq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.floorf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4521,7 +4564,7 @@ fn floatCeil(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__ceilx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.ceilq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.ceilf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4539,7 +4582,7 @@ fn floatRound(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__roundx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.roundq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.roundf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4557,7 +4600,7 @@ fn floatTrunc(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { return .stack; }, .f80 => return cg.callIntrinsic(.__truncx, &.{.f80_type}, Type.f80, &.{arg}), - .f128 => return cg.callIntrinsic(.truncq, &.{.f128_type}, Type.f128, &.{arg}), + .f128 => return cg.callIntrinsic(.truncf128, &.{.f128_type}, Type.f128, &.{arg}), } } @@ -4929,7 +4972,8 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr; const offset: u64 = prev_offset + ptr.byte_offset; return switch (ptr.base_addr) { - .nav => |nav| return if (Type.fromInterned(ip.getNav(nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu)) + .nav => |nav| return if (ip.getNav(nav).getExtern(ip) != null or + Type.fromInterned(ip.getNav(nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu)) .{ .nav_ref = .{ .nav_index = nav, .offset = @intCast(offset) } } else .{ .imm32 = @intCast(zcu.navAlignment(nav).forward(@as(u32, 0xaaaaaaaa))) }, @@ -5613,6 +5657,8 @@ fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass { } fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!?WValue { + if (dest_ty.eql(src_ty)) return null; + const zcu = cg.pt.zcu; const src_class = cg.bitcastClass(src_ty); const dest_class = cg.bitcastClass(dest_ty); diff --git a/src/codegen/wasm/Emit.zig b/src/codegen/wasm/Emit.zig index 81bf1e1315362d5b4dd4928b29f76dc5ab1f41f0..a83597dfc4fb3b0749a66fdf0c7e62c8995457c5 100644 --- a/src/codegen/wasm/Emit.zig +++ b/src/codegen/wasm/Emit.zig @@ -21,7 +21,7 @@ pub const Error = error{ OutOfMemory, }; -pub fn lowerToCode(emit: *Emit) Error!void { +pub fn lower(emit: *Emit) Error!void { const mir = &emit.mir; const code = emit.code; const wasm = emit.wasm; @@ -31,6 +31,47 @@ pub fn lowerToCode(emit: *Emit) Error!void { const target = &comp.root_mod.resolved_target.result; const is_wasm32 = target.cpu.arch == .wasm32; + // Write the locals in the prologue of the function body. + try code.ensureUnusedCapacity(gpa, 5 + mir.locals.len * 6 + 38); + + writeUleb128(code, @as(u32, @intCast(mir.locals.len))); + + for (mir.locals) |local| { + writeUleb128(code, @as(u32, 1)); + code.appendAssumeCapacity(@backingInt(local)); + } + + // Stack management section of function prologue. + const stack_alignment = mir.prologue.flags.stack_alignment; + if (stack_alignment.toByteUnits()) |align_bytes| { + // load stack pointer + code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.global_get)); + try appendStackPointerGlobalIndex(wasm, code, is_obj); + // store stack pointer so we can restore it when we return from the function + code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.local_tee)); + writeUleb128(code, mir.prologue.sp_local); + // get the total stack size + const aligned_stack: i32 = @intCast(stack_alignment.forward(mir.prologue.stack_size)); + code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_const)); + writeSleb128(code, aligned_stack); + // subtract it from the current stack pointer + code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_sub)); + // Get negative stack alignment + const neg_stack_align = @as(i32, @intCast(align_bytes)) * -1; + code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_const)); + writeSleb128(code, neg_stack_align); + // Bitwise-and the value to get the new stack pointer to ensure the + // pointers are aligned with the abi alignment. + code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_and)); + // The bottom will be used to calculate all stack pointer offsets. + code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.local_tee)); + writeUleb128(code, mir.prologue.bottom_stack_local); + // Store the current stack pointer value into the global stack pointer so other function calls will + // start from this value instead and not overwrite the current stack. + code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.global_set)); + try appendStackPointerGlobalIndex(wasm, code, is_obj); + } + const tags = mir.instructions.items(.tag); const datas = mir.instructions.items(.data); var inst: u32 = 0; @@ -78,14 +119,21 @@ pub fn lowerToCode(emit: *Emit) Error!void { continue :loop tags[inst]; }, .func_ref => { - const indirect_func_idx: Wasm.ZcuIndirectFunctionSetIndex = @fromBackingInt(@intCast( - wasm.zcu_indirect_function_set.getIndex(datas[inst].nav_index).?, - )); - code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_const)); + try code.ensureUnusedCapacity(gpa, 11); + const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; + code.appendAssumeCapacity(@backingInt(opcode)); if (is_obj) { - @panic("TODO"); + try wasm.zcu_relocations.append(gpa, .{ + .offset = @intCast(code.items.len), + .pointee = .{ .function_nav = datas[inst].nav_index }, + .tag = if (is_wasm32) .table_index_sleb else .table_index_sleb64, + .addend = 0, + }); + appendSlebRelocPlaceholder(code, is_wasm32); } else { - writeSleb128(code, 1 + @backingInt(indirect_func_idx)); + const function_index = Wasm.OutputFunctionIndex.fromIpNav(wasm, datas[inst].nav_index); + const table_index = wasm.flush_buffer.indirect_function_table.getIndex(function_index).? + 1; + writeSleb128(code, table_index); } inst += 1; continue :loop tags[inst]; @@ -105,18 +153,17 @@ pub fn lowerToCode(emit: *Emit) Error!void { continue :loop tags[inst]; }, .error_name_table_ref => { - wasm.error_name_table_ref_count += 1; try code.ensureUnusedCapacity(gpa, 11); const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; code.appendAssumeCapacity(@backingInt(opcode)); if (is_obj) { - try wasm.out_relocs.append(gpa, .{ + try wasm.zcu_relocations.append(gpa, .{ .offset = @intCast(code.items.len), - .pointee = .{ .symbol_index = try wasm.errorNameTableSymbolIndex() }, - .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64, + .pointee = .{ .data_resolution = .__zig_error_name_table }, + .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); + appendSlebRelocPlaceholder(code, is_wasm32); inst += 1; continue :loop tags[inst]; @@ -164,13 +211,13 @@ pub fn lowerToCode(emit: *Emit) Error!void { try code.ensureUnusedCapacity(gpa, 6); code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call)); if (is_obj) { - try wasm.out_relocs.append(gpa, .{ + try wasm.zcu_relocations.append(gpa, .{ .offset = @intCast(code.items.len), - .pointee = .{ .symbol_index = try wasm.navSymbolIndex(datas[inst].nav_index) }, + .pointee = .{ .function_nav = datas[inst].nav_index }, .tag = .function_index_leb, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, 5); + appendUlebRelocPlaceholder(code); } else { appendOutputFunctionIndex(code, .fromIpNav(wasm, datas[inst].nav_index)); } @@ -191,13 +238,13 @@ pub fn lowerToCode(emit: *Emit) Error!void { ).?; if (is_obj) { code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call_indirect)); - try wasm.out_relocs.append(gpa, .{ + try wasm.zcu_relocations.append(gpa, .{ .offset = @intCast(code.items.len), .pointee = .{ .type_index = func_ty_index }, .tag = .type_index_leb, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, 5); + appendUlebRelocPlaceholder(code); } else { const index: Wasm.Flush.FuncTypeIndex = @fromBackingInt(@intCast(wasm.flush_buffer.func_types.getIndex(func_ty_index) orelse { // In this case we tried to call a function pointer for @@ -224,13 +271,13 @@ pub fn lowerToCode(emit: *Emit) Error!void { try code.ensureUnusedCapacity(gpa, 6); code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call)); if (is_obj) { - try wasm.out_relocs.append(gpa, .{ + try wasm.zcu_relocations.append(gpa, .{ .offset = @intCast(code.items.len), - .pointee = .{ .symbol_index = try wasm.tagTableIndexSymbolIndex(datas[inst].ip_index) }, + .pointee = .{ .tag_function = datas[inst].ip_index }, .tag = .function_index_leb, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, 5); + appendUlebRelocPlaceholder(code); } else { appendOutputFunctionIndex(code, .fromTagIndexType(wasm, datas[inst].ip_index)); } @@ -244,14 +291,20 @@ pub fn lowerToCode(emit: *Emit) Error!void { const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; code.appendAssumeCapacity(@backingInt(opcode)); if (is_obj) { - @panic("TODO"); + try wasm.zcu_relocations.append(gpa, .{ + .offset = @intCast(code.items.len), + .pointee = .{ .data_resolution = .__zig_tag_name_table }, + .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64, + .addend = @intCast(wasm.tagIndexTableOffset(datas[inst].ip_index)), + }); + appendSlebRelocPlaceholder(code, is_wasm32); } else { const addr: u32 = wasm.tagIndexTableAddr(datas[inst].ip_index); writeSleb128(code, addr); - - inst += 1; - continue :loop tags[inst]; } + + inst += 1; + continue :loop tags[inst]; }, .call_intrinsic => { @@ -263,13 +316,13 @@ pub fn lowerToCode(emit: *Emit) Error!void { try code.ensureUnusedCapacity(gpa, 6); code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.call)); if (is_obj) { - try wasm.out_relocs.append(gpa, .{ + try wasm.zcu_relocations.append(gpa, .{ .offset = @intCast(code.items.len), - .pointee = .{ .symbol_index = try wasm.symbolNameIndex(symbol_name) }, + .pointee = .{ .function_name = symbol_name }, .tag = .function_index_leb, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, 5); + appendUlebRelocPlaceholder(code); } else { appendOutputFunctionIndex(code, .fromSymbolName(wasm, symbol_name)); } @@ -281,18 +334,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { .global_set_sp => { try code.ensureUnusedCapacity(gpa, 6); code.appendAssumeCapacity(@backingInt(std.wasm.Opcode.global_set)); - if (is_obj) { - try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), - .pointee = .{ .symbol_index = try wasm.stackPointerSymbolIndex() }, - .tag = .global_index_leb, - .addend = 0, - }); - code.appendNTimesAssumeCapacity(0, 5); - } else { - const sp_global: Wasm.GlobalIndex = .stack_pointer; - writeUleb128(code, @backingInt(sp_global)); - } + try appendStackPointerGlobalIndex(wasm, code, is_obj); inst += 1; continue :loop tags[inst]; @@ -960,13 +1002,13 @@ fn uavRefObj(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset: try code.ensureUnusedCapacity(gpa, 11); code.appendAssumeCapacity(@backingInt(opcode)); - try wasm.out_relocs.append(gpa, .{ + try wasm.zcu_relocations.append(gpa, .{ .offset = @intCast(code.items.len), - .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(value) }, - .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64, + .pointee = .{ .data_uav = value }, + .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64, .addend = offset, }); - code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); + appendSlebRelocPlaceholder(code, is_wasm32); } fn uavRefExe(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void { @@ -978,7 +1020,7 @@ fn uavRefExe(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset: code.appendAssumeCapacity(@backingInt(opcode)); const addr = wasm.uavAddr(value); - writeUleb128(code, @as(u32, @intCast(@as(i64, addr) + offset))); + writeSleb128(code, @as(u32, @intCast(@as(i64, addr) + offset))); } fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32: bool) !void { @@ -995,16 +1037,16 @@ fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32: const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; code.appendAssumeCapacity(@backingInt(opcode)); if (is_obj) { - try wasm.out_relocs.append(gpa, .{ + try wasm.zcu_relocations.append(gpa, .{ .offset = @intCast(code.items.len), - .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) }, - .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64, + .pointee = .{ .data_nav = data.nav_index }, + .tag = if (is_wasm32) .memory_addr_sleb else .memory_addr_sleb64, .addend = data.offset, }); - code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); + appendSlebRelocPlaceholder(code, is_wasm32); } else { const addr = wasm.navAddr(data.nav_index); - writeUleb128(code, @as(u32, @intCast(@as(i64, addr) + data.offset))); + writeSleb128(code, @as(u32, @intCast(@as(i64, addr) + data.offset))); } } @@ -1012,6 +1054,40 @@ fn appendOutputFunctionIndex(code: *ArrayList(u8), i: Wasm.OutputFunctionIndex) writeUleb128(code, @backingInt(i)); } +fn appendStackPointerGlobalIndex( + wasm: *Wasm, + code: *ArrayList(u8), + is_obj: bool, +) Error!void { + if (is_obj) { + try wasm.zcu_relocations.append(wasm.base.comp.gpa, .{ + .offset = @intCast(code.items.len), + .pointee = .stack_pointer, + .tag = .global_index_leb, + .addend = 0, + }); + appendUlebRelocPlaceholder(code); + } else { + const sp_global: Wasm.GlobalIndex = .stack_pointer; + writeUleb128(code, @backingInt(sp_global)); + } +} + +fn appendUlebRelocPlaceholder(code: *ArrayList(u8)) void { + code.appendSliceAssumeCapacity(&.{ 0x80, 0x80, 0x80, 0x80, 0x00 }); +} + +fn appendSlebRelocPlaceholder(code: *ArrayList(u8), is_wasm32: bool) void { + if (is_wasm32) { + code.appendSliceAssumeCapacity(&.{ 0x80, 0x80, 0x80, 0x80, 0x00 }); + } else { + code.appendSliceAssumeCapacity(&.{ + 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x00, + }); + } +} + fn writeUleb128(code: *ArrayList(u8), arg: anytype) void { var w: std.Io.Writer = .fixed(code.unusedCapacitySlice()); w.writeUleb128(arg) catch unreachable; diff --git a/src/codegen/wasm/Mir.zig b/src/codegen/wasm/Mir.zig index 454592c5d2198e14d895b2e19586775396ef5395..5f602496e901acc56864a8e45143fd7e14d193f7 100644 --- a/src/codegen/wasm/Mir.zig +++ b/src/codegen/wasm/Mir.zig @@ -114,7 +114,7 @@ pub const Inst = struct { /// /// Uses `payload` pointing to a `NavRefOff`. nav_ref_off, - /// Lowers to an i32_const which is the index of the function in the + /// Lowers to an iNN_const which is the index of the function in the /// table section. /// /// Uses `nav_index`. @@ -661,8 +661,8 @@ pub const Inst = struct { comptime { switch (builtin.mode) { - .Debug, .ReleaseSafe => {}, - .ReleaseFast, .ReleaseSmall => assert(@sizeOf(Data) == 4), + .debug, .safe => {}, + .fast, .small => assert(@sizeOf(Data) == 4), } } }; @@ -679,60 +679,12 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { } pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayList(u8)) std.mem.Allocator.Error!void { - const gpa = wasm.base.comp.gpa; - - // Write the locals in the prologue of the function body. - try code.ensureUnusedCapacity(gpa, 5 + mir.locals.len * 6 + 38); - - var w: std.Io.Writer = .fixed(code.unusedCapacitySlice()); - - w.writeLeb128(@as(u32, @intCast(mir.locals.len))) catch unreachable; - - for (mir.locals) |local| { - w.writeLeb128(@as(u32, 1)) catch unreachable; - w.writeByte(@backingInt(local)) catch unreachable; - } - - // Stack management section of function prologue. - const stack_alignment = mir.prologue.flags.stack_alignment; - if (stack_alignment.toByteUnits()) |align_bytes| { - const sp_global: Wasm.GlobalIndex = .stack_pointer; - // load stack pointer - w.writeByte(@backingInt(std.wasm.Opcode.global_get)) catch unreachable; - w.writeUleb128(@backingInt(sp_global)) catch unreachable; - // store stack pointer so we can restore it when we return from the function - w.writeByte(@backingInt(std.wasm.Opcode.local_tee)) catch unreachable; - w.writeUleb128(mir.prologue.sp_local) catch unreachable; - // get the total stack size - const aligned_stack: i32 = @intCast(stack_alignment.forward(mir.prologue.stack_size)); - w.writeByte(@backingInt(std.wasm.Opcode.i32_const)) catch unreachable; - w.writeSleb128(aligned_stack) catch unreachable; - // subtract it from the current stack pointer - w.writeByte(@backingInt(std.wasm.Opcode.i32_sub)) catch unreachable; - // Get negative stack alignment - const neg_stack_align = @as(i32, @intCast(align_bytes)) * -1; - w.writeByte(@backingInt(std.wasm.Opcode.i32_const)) catch unreachable; - w.writeSleb128(neg_stack_align) catch unreachable; - // Bitwise-and the value to get the new stack pointer to ensure the - // pointers are aligned with the abi alignment. - w.writeByte(@backingInt(std.wasm.Opcode.i32_and)) catch unreachable; - // The bottom will be used to calculate all stack pointer offsets. - w.writeByte(@backingInt(std.wasm.Opcode.local_tee)) catch unreachable; - w.writeUleb128(mir.prologue.bottom_stack_local) catch unreachable; - // Store the current stack pointer value into the global stack pointer so other function calls will - // start from this value instead and not overwrite the current stack. - w.writeByte(@backingInt(std.wasm.Opcode.global_set)) catch unreachable; - w.writeUleb128(@backingInt(sp_global)) catch unreachable; - } - - code.items.len += w.end; - var emit: Emit = .{ .mir = mir.*, .wasm = wasm, .code = code, }; - try emit.lowerToCode(); + try emit.lower(); } pub fn extraData(self: *const Mir, comptime T: type, index: usize) struct { data: T, end: usize } { @@ -991,48 +943,48 @@ pub const Intrinsic = enum(u32) { __udivti3, __umodei5, __umodti3, - ceilq, + ceilf128, cos, cosf, - cosq, + cosf128, exp, exp2, exp2f, - exp2q, + exp2f128, expf, - expq, - fabsq, - floorq, + expf128, + fabsf128, + floorf128, fma, fmaf, - fmaq, + fmaf128, fmax, fmaxf, - fmaxq, + fmaxf128, fmin, fminf, - fminq, + fminf128, fmod, fmodf, - fmodq, + fmodf128, log, log10, log10f, - log10q, + log10f128, log2, log2f, - log2q, + log2f128, logf, - logq, - roundq, + logf128, + roundf128, sin, sinf, - sinq, - sqrtq, + sinf128, + sqrtf128, tan, tanf, - tanq, - truncq, + tanf128, + truncf128, memcpy, memmove, memset, diff --git a/src/codegen/wasm/abi.zig b/src/codegen/wasm/abi.zig index 7a643e8dc7a755937f096f9826e5d770c2394b42..1952c65227e8d57b0c164a62286814265bae0e3c 100644 --- a/src/codegen/wasm/abi.zig +++ b/src/codegen/wasm/abi.zig @@ -11,21 +11,53 @@ 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. +/// Describes how the Wasm backend represents a C ABI value. pub const Class = union(enum) { direct: Type, + double_i64, indirect, + unrolled: struct { + elem_type: Type, + len: u32, + }, }; -/// 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 { +pub const LlvmClass = union(enum) { + direct: Type, + indirect, +}; + +pub fn classifyType(ty: Type, zcu: *const Zcu, target: *const Target) Class { + if (ty.zigTypeTag(zcu) == .vector) { + if (!(ty.bitSize(zcu) == 128 and target.cpu.has(.wasm, .simd128))) { + const elem_type = ty.childType(zcu); + return .{ .unrolled = .{ + .elem_type = elem_type, + .len = ty.vectorLen(zcu), + } }; + } + return .{ .direct = ty }; + } + + return switch (classifyTypeForLlvm(ty, zcu)) { + .direct => |scalar_ty| if (scalar_ty.bitSize(zcu) > 64) + .double_i64 + else + .{ .direct = scalar_ty }, + .indirect => .indirect, + }; +} + +pub fn classifyTypeForLlvm(ty: Type, zcu: *const Zcu) LlvmClass { const ip = &zcu.intern_pool; assert(ty.hasRuntimeBits(zcu)); switch (ty.zigTypeTag(zcu)) { .int, .@"enum", .error_set => return .{ .direct = ty }, - .float => return .{ .direct = ty }, + .float => return switch (ty.floatBits(zcu.getTarget())) { + else => unreachable, + 16, 32, 64, 128 => .{ .direct = ty }, + 80 => .indirect, + }, .bool => return .{ .direct = ty }, .vector => return .{ .direct = ty }, .array => return .indirect, @@ -39,20 +71,35 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class { }, .@"struct" => { const struct_type = zcu.typeToStruct(ty).?; - if (struct_type.layout == .@"packed") { - return .{ .direct = ty }; + switch (struct_type.layout) { + .auto => unreachable, + .@"packed" => return .{ .direct = ty }, + .@"extern" => {}, } - 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.field_aligns.getOrNone(ip, 0); - if (explicit_align != .none) { - if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(zcu))) + var opt_single_field_ty: ?Type = null; + for (struct_type.field_types.get(ip), 0..) |field_ty_index, field_index| { + const field_ty: Type = .fromInterned(field_ty_index); + if (!field_ty.hasRuntimeBits(zcu)) continue; + + if (opt_single_field_ty != null) { + return .indirect; + } + + const field_align = struct_type.field_aligns.getOrNone(ip, field_index); + if (field_align != .none and field_align.compareStrict(.gt, field_ty.abiAlignment(zcu))) { return .indirect; + } + opt_single_field_ty = field_ty; + } + const single_field_ty = opt_single_field_ty.?; + if (single_field_ty.zigTypeTag(zcu) == .array) { + switch (single_field_ty.arrayLenIncludingSentinel(zcu)) { + 0 => unreachable, + 1 => return classifyTypeForLlvm(single_field_ty.childType(zcu), zcu), + else => {}, + } } - return classifyType(field_ty, zcu); + return classifyTypeForLlvm(single_field_ty, zcu); }, .@"union" => { const union_obj = zcu.typeToUnion(ty).?; @@ -63,7 +110,14 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class { 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); + if (first_field_ty.zigTypeTag(zcu) == .array) { + switch (first_field_ty.arrayLenIncludingSentinel(zcu)) { + 0 => unreachable, + 1 => return classifyTypeForLlvm(first_field_ty.childType(zcu), zcu), + else => {}, + } + } + return classifyTypeForLlvm(first_field_ty, zcu); }, .error_union, .frame, @@ -82,7 +136,3 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class { => unreachable, } } - -pub fn lowerAsDoubleI64(scalar_ty: Type, zcu: *const Zcu) bool { - return scalar_ty.bitSize(zcu) > 64; -} diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index 1b29b50549173fe0d0855f541238971f8fcba181..063a8c158f3ff592ded65497dc14640098588e31 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -1301,7 +1301,7 @@ fn addInst(self: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { } fn addExtra(self: *CodeGen, extra: anytype) Allocator.Error!u32 { - const field_count = std.meta.fieldNames(@TypeOf(extra)).len; + const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len; try self.mir_extra.ensureUnusedCapacity(self.gpa, field_count); return self.addExtraAssumeCapacity(extra); } @@ -2152,7 +2152,7 @@ fn gen( const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: { var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1); - while (self.epilogue_relocs.getLast() == last_inst) { + while (self.epilogue_relocs.last() == last_inst) { self.epilogue_relocs.items.len -= 1; self.mir_instructions.set(last_inst, .{ .tag = .pseudo, @@ -34436,7 +34436,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34470,7 +34470,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34505,7 +34505,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34540,7 +34540,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34575,7 +34575,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34612,7 +34612,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34649,7 +34649,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34688,7 +34688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34727,7 +34727,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -34766,7 +34766,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf128" } }, .unused, .unused, .unused, @@ -35960,8 +35960,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -35998,8 +35998,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .mem }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36037,8 +36037,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .mem }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36076,8 +36076,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .mem }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36115,8 +36115,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36156,8 +36156,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36197,8 +36197,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36240,8 +36240,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36283,8 +36283,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -36326,8 +36326,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .zero => "truncq", - .down => "floorq", + .zero => "truncf128", + .down => "floorf128", } } }, .unused, .unused, @@ -37691,7 +37691,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37725,7 +37725,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37760,7 +37760,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37795,7 +37795,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37830,7 +37830,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37867,7 +37867,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37904,7 +37904,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37943,7 +37943,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -37982,7 +37982,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -38021,7 +38021,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf128" } }, .unused, .unused, .unused, @@ -39558,7 +39558,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39590,7 +39590,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39623,7 +39623,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39659,7 +39659,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39695,7 +39695,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .unused, .unused, .unused, @@ -39731,7 +39731,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -39767,7 +39767,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -39803,7 +39803,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -42803,7 +42803,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .u64, .kind = .{ .reg = .rcx } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -42849,7 +42849,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .u64, .kind = .{ .reg = .rcx } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -42895,7 +42895,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .u64, .kind = .{ .reg = .rcx } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -42942,7 +42942,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .mem }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -42984,7 +42984,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -43029,7 +43029,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -43074,7 +43074,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, @@ -43120,7 +43120,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .mem }, .{ .type = .usize, .kind = .{ .reg = .rax } }, .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, @@ -43164,7 +43164,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, @@ -43211,7 +43211,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, @@ -43258,7 +43258,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, @@ -43306,7 +43306,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf128" } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .rax } }, @@ -47623,7 +47623,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47655,7 +47655,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47688,7 +47688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47724,7 +47724,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47760,7 +47760,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -47796,7 +47796,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -47832,7 +47832,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -47868,7 +47868,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -51926,7 +51926,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -51958,7 +51958,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -51991,7 +51991,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -52027,7 +52027,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -52063,7 +52063,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -52099,7 +52099,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -52135,7 +52135,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -52171,7 +52171,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -76457,7 +76457,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76484,7 +76484,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76512,7 +76512,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76543,7 +76543,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76574,7 +76574,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .unused, .unused, .unused, @@ -76605,7 +76605,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -76636,7 +76636,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -76667,7 +76667,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -77306,7 +77306,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77333,7 +77333,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77361,7 +77361,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77392,7 +77392,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77423,7 +77423,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .unused, .unused, .unused, @@ -77454,7 +77454,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -77485,7 +77485,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -77516,7 +77516,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -80155,9 +80155,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80187,9 +80187,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80220,9 +80220,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80256,9 +80256,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80292,9 +80292,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .unused, .unused, @@ -80328,9 +80328,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, @@ -80364,9 +80364,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, @@ -80400,9 +80400,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, - .down => "floorq", - .up => "ceilq", - .zero => "truncq", + .down => "floorf128", + .up => "ceilf128", + .zero => "truncf128", } } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, @@ -125531,7 +125531,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .call, .tmp1d, ._, ._, ._ }, } }, }, .{ - .required_cc_abi = .sysv64, .required_features = .{ .sse, null, null, null }, .src_constraints = .{ .{ .unsigned_int = .xword }, .any, .any }, .dst_constraints = .{ .{ .float = .xword }, .any }, @@ -125557,34 +125556,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .each = .{ .once = &.{ .{ ._, ._, .call, .tmp0d, ._, ._, ._ }, } }, - }, .{ - .required_cc_abi = .win64, - .required_features = .{ .sse, null, null, null }, - .src_constraints = .{ .{ .unsigned_int = .xword }, .any, .any }, - .dst_constraints = .{ .{ .float = .xword }, .any }, - .patterns = &.{ - .{ .src = .{ .to_mem, .none, .none } }, - }, - .call_frame = .{ .alignment = .@"16" }, - .extra_temps = .{ - .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - }, - .dst_temps = .{ .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } }, .unused }, - .clobbers = .{ .eflags = true, .caller_preserved = .ccc }, - .each = .{ .once = &.{ - .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ }, - .{ ._, ._, .call, .tmp1d, ._, ._, ._ }, - } }, }, .{ .required_features = .{ .@"64bit", .sse, null, null }, .src_constraints = .{ .{ .remainder_signed_int = .{ .of = .dword, .is = .dword } }, .any, .any }, @@ -126791,7 +126762,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, }, .{ - .required_cc_abi = .sysv64, .required_features = .{ .avx, null, null, null }, .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, @@ -126824,39 +126794,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, }, .{ - .required_cc_abi = .win64, - .required_features = .{ .avx, null, null, null }, - .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, - .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, - .patterns = &.{ - .{ .src = .{ .to_mem, .none, .none } }, - }, - .call_frame = .{ .alignment = .@"16" }, - .extra_temps = .{ - .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, - .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - }, - .dst_temps = .{ .mem, .unused }, - .clobbers = .{ .eflags = true, .caller_preserved = .ccc }, - .each = .{ .once = &.{ - .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_unaligned_size), ._, ._ }, - .{ .@"0:", ._, .lea, .tmp1p, .memi(.src0, .tmp0), ._, ._ }, - .{ ._, ._, .call, .tmp2d, ._, ._, ._ }, - .{ ._, .v_dqa, .mov, .memi(.dst0x, .tmp0), .tmp3x, ._, ._ }, - .{ ._, ._, .sub, .tmp0d, .si(16), ._, ._ }, - .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, - } }, - }, .{ - .required_cc_abi = .sysv64, .required_features = .{ .sse2, null, null, null }, .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, @@ -126889,39 +126826,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, }, .{ - .required_cc_abi = .win64, - .required_features = .{ .sse2, null, null, null }, - .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, - .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, - .patterns = &.{ - .{ .src = .{ .to_mem, .none, .none } }, - }, - .call_frame = .{ .alignment = .@"16" }, - .extra_temps = .{ - .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, - .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - }, - .dst_temps = .{ .mem, .unused }, - .clobbers = .{ .eflags = true, .caller_preserved = .ccc }, - .each = .{ .once = &.{ - .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_unaligned_size), ._, ._ }, - .{ .@"0:", ._, .lea, .tmp1p, .memi(.src0, .tmp0), ._, ._ }, - .{ ._, ._, .call, .tmp2d, ._, ._, ._ }, - .{ ._, ._dqa, .mov, .memi(.dst0x, .tmp0), .tmp3x, ._, ._ }, - .{ ._, ._, .sub, .tmp0d, .si(16), ._, ._ }, - .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, - } }, - }, .{ - .required_cc_abi = .sysv64, .required_features = .{ .sse, null, null, null }, .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, @@ -126953,38 +126857,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .sub, .tmp0d, .si(16), ._, ._ }, .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, - }, .{ - .required_cc_abi = .win64, - .required_features = .{ .sse, null, null, null }, - .src_constraints = .{ .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .xword } }, .any, .any }, - .dst_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } }, .any }, - .patterns = &.{ - .{ .src = .{ .to_mem, .none, .none } }, - }, - .call_frame = .{ .alignment = .@"16" }, - .extra_temps = .{ - .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, - .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - .unused, - }, - .dst_temps = .{ .mem, .unused }, - .clobbers = .{ .eflags = true, .caller_preserved = .ccc }, - .each = .{ .once = &.{ - .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_unaligned_size), ._, ._ }, - .{ .@"0:", ._, .lea, .tmp1p, .memi(.src0, .tmp0), ._, ._ }, - .{ ._, ._, .call, .tmp2d, ._, ._, ._ }, - .{ ._, ._ps, .mova, .memi(.dst0x, .tmp0), .tmp3x, ._, ._ }, - .{ ._, ._, .sub, .tmp0d, .si(16), ._, ._ }, - .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, - } }, }, .{ .required_features = .{ .@"64bit", .avx, null, null }, .src_constraints = .{ .{ .scalar_remainder_signed_int = .{ .of = .dword, .is = .dword } }, .any, .any }, @@ -142552,7 +142424,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -142584,7 +142456,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -142616,7 +142488,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -142649,7 +142521,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -142683,7 +142555,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -142717,7 +142589,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -152785,7 +152657,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -152817,7 +152689,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -152849,7 +152721,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -152882,7 +152754,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -152916,7 +152788,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -152950,7 +152822,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -163019,7 +162891,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -163051,7 +162923,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -163083,7 +162955,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .unused, .unused, .unused, @@ -163116,7 +162988,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -163150,7 +163022,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -163184,7 +163056,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -164816,7 +164688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -164848,7 +164720,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -164880,7 +164752,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .unused, .unused, .unused, @@ -164913,7 +164785,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -164947,7 +164819,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -164981,7 +164853,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxf128" } }, .{ .type = .f128, .kind = .mem }, .unused, .unused, @@ -172785,7 +172657,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172818,7 +172690,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172852,7 +172724,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172889,7 +172761,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172926,7 +172798,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .f128, .kind = .{ .param_sse = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .unused, .unused, .unused, @@ -172963,7 +172835,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -173000,7 +172872,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -173037,7 +172909,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 1, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .after = 2, .at = 2 } } }, - .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf128" } }, .{ .type = .f128, .kind = .{ .ret_sse = .{ .cc = .ccc, .after = 0, .at = 0 } } }, .unused, .unused, @@ -176621,10 +176493,20 @@ fn genCall(cg: *CodeGen, info: union(enum) { for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, frame_index| switch (dst_arg) { .none, .load_frame, .indirect_load_frame => {}, - .register => |dst_reg| try cg.genSetReg(registerAlias( - dst_reg, - @intCast(cg.unalignedSize(arg_ty)), - ), arg_ty, src_arg, opts), + .register => |dst_reg| switch (fn_info.cc) { + else => try cg.genSetReg(registerAlias( + dst_reg, + @intCast(cg.unalignedSize(arg_ty)), + ), arg_ty, src_arg, opts), + .x86_64_sysv, .x86_64_win => { + const promoted_ty = cg.promoteInt(arg_ty); + const promoted_unaligned_size: u32 = @intCast(cg.unalignedSize(promoted_ty)); + const dst_alias = registerAlias(dst_reg, promoted_unaligned_size); + try cg.genSetReg(dst_alias, promoted_ty, src_arg, opts); + if (promoted_ty.toIntern() != arg_ty.toIntern()) + try cg.truncateRegister(arg_ty, dst_alias); + }, + }, .register_pair, .register_triple, .register_quadruple, @@ -177096,7 +176978,7 @@ fn lowerBlock(self: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index defer block_data.value.deinit(self.gpa); if (block_data.value.relocs.items.len > 0) { var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1); - while (block_data.value.relocs.getLast() == last_inst) { + while (block_data.value.relocs.last() == last_inst) { block_data.value.relocs.items.len -= 1; self.mir_instructions.set(last_inst, .{ .tag = .pseudo, @@ -178017,7 +177899,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { else if (std.mem.endsWith(u8, mnem_str, "l")) .dword else if (std.mem.endsWith(u8, mnem_str, "q") and - (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or + (std.mem.findScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq"))) .qword else if (std.mem.endsWith(u8, mnem_str, "t")) @@ -178084,8 +177966,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { }) + 1, } }; - const untrimmed_op_str = if (std.mem.indexOfScalar(u8, full_op_str, '#') orelse - std.mem.indexOf(u8, full_op_str, "//")) |comment| + const untrimmed_op_str = if (std.mem.findScalar(u8, full_op_str, '#') orelse + std.mem.find(u8, full_op_str, "//")) |comment| untrimmed_op_str: { ops_index = ops_str.len; break :untrimmed_op_str full_op_str[0..comment]; @@ -178094,7 +177976,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { if (trimmed_op_str.len > 0) break trimmed_op_str; }; if (std.mem.startsWith(u8, op_str, "%%")) { - const colon = std.mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); + const colon = std.mem.findScalarPos(u8, op_str, "%%".len + 2, ':'); const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse return self.fail("invalid register: '{s}'", .{op_str}); if (colon) |colon_pos| { @@ -178115,7 +177997,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { op.* = .{ .reg = reg }; } } else if (std.mem.startsWith(u8, op_str, "%[") and std.mem.endsWith(u8, op_str, "]")) { - const colon = std.mem.indexOfScalarPos(u8, op_str, "%[".len, ':'); + const colon = std.mem.findScalarPos(u8, op_str, "%[".len, ':'); const modifier = if (colon) |colon_pos| op_str[colon_pos + ":".len .. op_str.len - "]".len] else @@ -178198,7 +178080,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { else |_| return self.fail("invalid immediate: '{s}'", .{op_str}); } else if (std.mem.endsWith(u8, op_str, ")")) { - const open = std.mem.indexOfScalar(u8, op_str, '(') orelse + const open = std.mem.findScalar(u8, op_str, '(') orelse return self.fail("invalid operand: '{s}'", .{op_str}); var sib_it = std.mem.splitScalar(u8, op_str[open + "(".len .. op_str.len - ")".len], ','); @@ -178259,7 +178141,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { .disp = if (std.mem.startsWith(u8, op_str[0..open], "%[") and std.mem.endsWith(u8, op_str[0..open], "]")) disp: { - const colon = std.mem.indexOfScalarPos(u8, op_str[0..open], "%[".len, ':'); + const colon = std.mem.findScalarPos(u8, op_str[0..open], "%[".len, ':'); const modifier = if (colon) |colon_pos| op_str[colon_pos + ":".len .. open - "]".len] else @@ -178328,14 +178210,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { .{ ._, .pseudo } else for (std.enums.values(Mir.Inst.Fixes)) |fixes| { const fixes_name = @tagName(fixes); - const space_index = std.mem.indexOfScalar(u8, fixes_name, ' '); + const space_index = std.mem.findScalar(u8, fixes_name, ' '); const fixes_prefix = if (space_index) |index| std.meta.stringToEnum(encoder.Instruction.Prefix, fixes_name[0..index]).? else .none; if (fixes_prefix != prefix) continue; const pattern = fixes_name[if (space_index) |index| index + " ".len else 0..]; - const wildcard_index = std.mem.indexOfScalar(u8, pattern, '_').?; + const wildcard_index = std.mem.findScalar(u8, pattern, '_').?; const mnem_prefix = pattern[0..wildcard_index]; const mnem_suffix = pattern[wildcard_index + "_".len ..]; if (!std.mem.startsWith(u8, mnem_name, mnem_prefix)) continue; @@ -178581,11 +178463,11 @@ fn moveStrategy(cg: *CodeGen, ty: Type, class: Register.Class, aligned: bool) !M .sse => switch (ty.zigTypeTag(zcu)) { else => { const classes = std.mem.sliceTo(&abi.classifySystemV(ty, zcu, cg.target, .other), .none); - assert(std.mem.indexOfNone(abi.Class, classes, &.{ + assert(std.mem.findNone(abi.Class, classes, &.{ .integer, .sse, .sseup, .memory, .float, .float_combine, }) == null); const abi_size = ty.abiSize(zcu); - if (abi_size < 4 or std.mem.indexOfScalar(abi.Class, classes, .integer) != null) switch (abi_size) { + if (abi_size < 4 or std.mem.findScalar(abi.Class, classes, .integer) != null) switch (abi_size) { 1 => return if (cg.hasFeature(.avx)) .{ .vex_insert_extract = .{ .insert = .{ .vp_b, .insr }, .extract = .{ .vp_b, .extr }, @@ -181994,7 +181876,7 @@ fn resolveCallingConventionValues( } const save_param_gpr_index = param_gpr_index; - const save_param_sse_index = param_gpr_index; + const save_param_sse_index = param_sse_index; var arg_mcv: [4]MCValue = undefined; var arg_mcv_len: u32 = 0; @@ -182502,8 +182384,8 @@ fn hasFeature(cg: *CodeGen, feature: std.Target.x86.Feature) bool { .slow_unaligned_mem_16, .slow_unaligned_mem_32, => switch (cg.mod.optimize_mode) { - .Debug, .ReleaseSafe, .ReleaseFast => null, - .ReleaseSmall => false, + .debug, .safe, .fast => null, + .small => false, }, .fast_11bytenop, .fast_15bytenop, @@ -182523,8 +182405,8 @@ fn hasFeature(cg: *CodeGen, feature: std.Target.x86.Feature) bool { .fast_vector_fsqrt, .fast_vector_shift_masks, => switch (cg.mod.optimize_mode) { - .Debug, .ReleaseSafe, .ReleaseFast => null, - .ReleaseSmall => true, + .debug, .safe, .fast => null, + .small => true, }, .mmx => false, .sahf => switch (cg.target.cpu.arch) { @@ -182626,15 +182508,15 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.lang.Type.Int { .anyerror => .{ .signedness = .unsigned, .bits = zcu.errorSetBits() }, .isize => .{ .signedness = .signed, .bits = cg.target.ptrBitWidth() }, .usize => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() }, - .c_char => .{ .signedness = cg.target.cCharSignedness(), .bits = cg.target.cTypeBitSize(.char) }, - .c_short => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.short) }, - .c_ushort => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.short) }, - .c_int => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.int) }, - .c_uint => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.int) }, - .c_long => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.long) }, - .c_ulong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.long) }, - .c_longlong => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.longlong) }, - .c_ulonglong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.longlong) }, + .c_char => .{ .signedness = cg.target.cCharSignedness().?, .bits = cg.target.cTypeBitSize(.char).? }, + .c_short => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.short).? }, + .c_ushort => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.short).? }, + .c_int => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.int).? }, + .c_uint => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.int).? }, + .c_long => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.long).? }, + .c_ulong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.long).? }, + .c_longlong => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.longlong).? }, + .c_ulonglong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.longlong).? }, .f16, .f32, .f64, .f80, .f128, .c_longdouble => null, .anyopaque, .void, @@ -183696,8 +183578,8 @@ const Temp = struct { const class = classes[class_index]; next_class_index = @intCast(switch (class) { .integer, .memory, .float, .float_combine => class_index + 1, - .sse => std.mem.indexOfNonePos(abi.Class, classes, class_index + 1, &.{.sseup}) orelse classes.len, - .x87 => std.mem.indexOfNonePos(abi.Class, classes, class_index + 1, &.{.x87up}) orelse classes.len, + .sse => std.mem.findNonePos(abi.Class, classes, class_index + 1, &.{.sseup}) orelse classes.len, + .x87 => std.mem.findNonePos(abi.Class, classes, class_index + 1, &.{.x87up}) orelse classes.len, .sseup, .x87up, .none, @@ -189943,7 +189825,7 @@ const Select = struct { s.cg.asmOps(mir_tag, mir_ops) catch |err| switch (err) { error.InvalidInstruction => { const fixes = @tagName(mir_tag[0]); - const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?; + const fixes_blank = std.mem.findScalar(u8, fixes, '_').?; return s.cg.fail("invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'", .{ fixes[0..fixes_blank], @tagName(mir_tag[1]), @@ -190023,7 +189905,7 @@ const Select = struct { .add, .com, .comi, .div, .divr, .mul, .st, .sub, .subr, .ucom, .ucomi => s.top +%= 1, else => { const fixes = @tagName(mir_tag[0]); - const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?; + const fixes_blank = std.mem.findScalar(u8, fixes, '_').?; std.debug.panic("{s}: {s}{s}{s}\n", .{ @src().fn_name, fixes[0..fixes_blank], diff --git a/src/codegen/x86_64/Lower.zig b/src/codegen/x86_64/Lower.zig index f471d990d1f19bd10d120d2d69f53266ab5538d3..389d57f62d6540f7f5dc096d65c59402f72ab06b 100644 --- a/src/codegen/x86_64/Lower.zig +++ b/src/codegen/x86_64/Lower.zig @@ -435,11 +435,11 @@ const mnemonic_table: [inst_tags_len * inst_fixes_len]?Mnemonic = table: { for (0..inst_fixes_len) |fixes_i| { const fixes: Mir.Inst.Fixes = @fromBackingInt(@intCast(fixes_i)); const prefix, const suffix = affix: { - const pattern = if (std.mem.indexOfScalar(u8, @tagName(fixes), ' ')) |i| + const pattern = if (std.mem.findScalar(u8, @tagName(fixes), ' ')) |i| @tagName(fixes)[i + 1 ..] else @tagName(fixes); - const wildcard_idx = std.mem.indexOfScalar(u8, pattern, '_').?; + const wildcard_idx = std.mem.findScalar(u8, pattern, '_').?; break :affix .{ pattern[0..wildcard_idx], pattern[wildcard_idx + 1 ..] }; }; for (0..inst_tags_len) |inst_tag_i| { @@ -477,7 +477,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}), }; try lower.encode(switch (fixes) { - inline else => |tag| comptime if (std.mem.indexOfScalar(u8, @tagName(tag), ' ')) |space| + inline else => |tag| comptime if (std.mem.findScalar(u8, @tagName(tag), ' ')) |space| @field(Prefix, @tagName(tag)[0..space]) else .none, @@ -487,8 +487,8 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { } // This combination is invalid; make the theoretical mnemonic name and emit an error with it. const fixes_name = @tagName(fixes); - const pattern = fixes_name[if (std.mem.indexOfScalar(u8, fixes_name, ' ')) |i| i + " ".len else 0..]; - const wildcard_index = std.mem.indexOfScalar(u8, pattern, '_').?; + const pattern = fixes_name[if (std.mem.findScalar(u8, fixes_name, ' ')) |i| i + " ".len else 0..]; + const wildcard_index = std.mem.findScalar(u8, pattern, '_').?; return lower.fail("unsupported mnemonic: '{s}{s}{s}'", .{ pattern[0..wildcard_index], @tagName(inst.tag), diff --git a/src/codegen/x86_64/Mir.zig b/src/codegen/x86_64/Mir.zig index 90fbbdf3125b2e449dc9723a0b98ce26a6b228c2..274437d54ccf55ce4fb47470e7a82b607c4bf0d2 100644 --- a/src/codegen/x86_64/Mir.zig +++ b/src/codegen/x86_64/Mir.zig @@ -1745,8 +1745,8 @@ pub const Inst = struct { for (@typeInfo(Mnemonic).@"enum".field_names) |mnemonic_name| { if (mnemonic_name[0] == '.') continue; for (@typeInfo(Fixes).@"enum".field_names) |fixes_name| { - const pattern = fixes_name[if (std.mem.indexOfScalar(u8, fixes_name, ' ')) |index| index + " ".len else 0..]; - const wildcard_index = std.mem.indexOfScalar(u8, pattern, '_').?; + const pattern = fixes_name[if (std.mem.findScalar(u8, fixes_name, ' ')) |index| index + " ".len else 0..]; + const wildcard_index = std.mem.findScalar(u8, pattern, '_').?; const mnem_prefix = pattern[0..wildcard_index]; const mnem_suffix = pattern[wildcard_index + "_".len ..]; if (!std.mem.startsWith(u8, mnemonic_name, mnem_prefix)) continue; @@ -1823,7 +1823,7 @@ pub const NullTerminatedString = enum(u32) { pub fn toSlice(nts: NullTerminatedString, mir: *const Mir) ?[:0]const u8 { if (nts == .none) return null; const string_bytes = mir.string_bytes[@backingInt(nts)..]; - return string_bytes[0..std.mem.indexOfScalar(u8, string_bytes, 0).? :0]; + return string_bytes[0..std.mem.findScalar(u8, string_bytes, 0).? :0]; } }; diff --git a/src/codegen/x86_64/abi.zig b/src/codegen/x86_64/abi.zig index 3e7a9a548d54baee16d64a54de9a42c4650f7ea5..471c09974d6bd29a29fb0fd37bd1b7e7612088b7 100644 --- a/src/codegen/x86_64/abi.zig +++ b/src/codegen/x86_64/abi.zig @@ -133,7 +133,7 @@ pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx: .float => switch (ty.floatBits(target)) { 16, 32, 64 => .sse, 80 => .memory, - 128 => if (ctx == .arg) .memory else .sse, + 128 => .win_i128, else => unreachable, }, .vector => { @@ -238,16 +238,18 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont }; const unaligned_size = elem_ty.abiSize(zcu) * len; if (unaligned_size <= 4) return Class.one_integer; - if (ctx == .arg and unaligned_size == 8 * 1 * 1 and len == 1 and - elem_ty.isRuntimeFloat()) return Class.stack; // what + if (unaligned_size == 8 * 1 * 1 and len == 1) { + if (ctx == .arg and elem_ty.isRuntimeFloat()) return Class.stack; // what? + if (ctx != .other and !elem_ty.isRuntimeFloat() and target.os.tag == .freebsd) return Class.one_integer; // who? + } if (unaligned_size <= 8 * 1) return .{ .sse, .none, .none, .none, .none, .none, .none, .none }; if (unaligned_size <= 8 * 2) return .{ .sse, .sseup, .none, .none, .none, .none, .none, .none }; if (!target.cpu.has(.x86, .avx)) { if (ctx == .ret) switch (unaligned_size) { else => {}, 8 * 3 => if (len == 3) return if (elem_ty.isRuntimeFloat()) .{ - .sse_sse_x87_per_qword, .none, .none, .none, .none, .none, .none, .none, // how - } else Class.len_integers, // why + .sse_sse_x87_per_qword, .none, .none, .none, .none, .none, .none, .none, // how? + } else Class.len_integers, // why? 8 * 2 * 2, 8 * 2 * 4 => return .{ .sse_per_xword, .none, .none, .none, .none, .none, .none, .none }, }; return Class.stack; @@ -316,7 +318,7 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont // byte isn't SSE or any other eightbyte isn't SSEUP, the whole argument // is passed in memory." if (ty_size > 16 and (result[0] != .sse or - std.mem.indexOfNone(Class, result[1..], &.{ .sseup, .none }) != null)) return Class.stack; + std.mem.findNone(Class, result[1..], &.{ .sseup, .none }) != null)) return Class.stack; // "If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE." for (&result, 0..) |*class, i| switch (class.*) { @@ -356,11 +358,10 @@ fn classifySystemVStruct( while (field_it.next()) |field_index| { const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); const field_align = loaded_struct.field_aligns.getOrNone(ip, field_index); - byte_offset = std.mem.alignForward( - u64, - byte_offset, - field_align.toByteUnits() orelse field_ty.abiAlignment(zcu).toByteUnits().?, - ); + byte_offset = switch (field_align) { + .none => field_ty.abiAlignment(zcu), + else => field_align, + }.forward(byte_offset); if (zcu.typeToStruct(field_ty)) |field_loaded_struct| { switch (field_loaded_struct.layout) { .auto => unreachable, @@ -379,6 +380,9 @@ fn classifySystemVStruct( }, .@"packed" => {}, } + } else if (field_ty.zigTypeTag(zcu) == .array) { + byte_offset = classifySystemVArray(result, byte_offset, field_ty, zcu, target); + continue; } const field_classes = std.mem.sliceTo(&classifySystemV(field_ty, zcu, target, .other), .none); for (result[@intCast(byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| @@ -386,11 +390,7 @@ fn classifySystemVStruct( byte_offset += field_ty.abiSize(zcu); } const final_byte_offset = starting_byte_offset + loaded_struct.size; - std.debug.assert(final_byte_offset == std.mem.alignForward( - u64, - byte_offset, - loaded_struct.alignment.toByteUnits().?, - )); + std.debug.assert(final_byte_offset == loaded_struct.alignment.forward(byte_offset)); return final_byte_offset; } @@ -422,6 +422,9 @@ fn classifySystemVUnion( }, .@"packed" => {}, } + } else if (field_ty.zigTypeTag(zcu) == .array) { + _ = classifySystemVArray(result, starting_byte_offset, field_ty, zcu, target); + continue; } const field_classes = std.mem.sliceTo(&classifySystemV(field_ty, zcu, target, .other), .none); for (result[@intCast(starting_byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| @@ -430,6 +433,26 @@ fn classifySystemVUnion( return starting_byte_offset + loaded_union.size; } +fn classifySystemVArray( + result: *[8]Class, + starting_byte_offset: u64, + array_ty: Type, + zcu: *Zcu, + target: *const std.Target, +) u64 { + const field_classes = std.mem.sliceTo(&classifySystemV(array_ty.childType(zcu), zcu, target, .other), .none); + var byte_offset = starting_byte_offset; + const elem_size = array_ty.childType(zcu).abiSize(zcu); + for (0..@intCast(array_ty.arrayLenIncludingSentinel(zcu))) |_| { + for (result[@intCast(byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| + result_class.* = result_class.combineSystemV(field_class); + byte_offset += elem_size; + } + const final_byte_offset = starting_byte_offset + array_ty.abiSize(zcu); + assert(final_byte_offset == byte_offset); + return final_byte_offset; +} + pub const zigcc = struct { pub const stack_align: ?InternPool.Alignment = null; pub const return_in_regs = true; diff --git a/src/codegen/x86_64/encoder.zig b/src/codegen/x86_64/encoder.zig index d18497cf08b640064083c4322feaab825f0bb849..a3c8a34714bdc033c5105ddf65e20f5b30e198eb 100644 --- a/src/codegen/x86_64/encoder.zig +++ b/src/codegen/x86_64/encoder.zig @@ -1171,7 +1171,7 @@ fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []co defer testing.allocator.free(expected_fmt); const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{given}); defer testing.allocator.free(given_fmt); - const idx = std.mem.indexOfDiff(u8, expected_fmt, given_fmt).?; + const idx = std.mem.findDiff(u8, expected_fmt, given_fmt).?; const padding = try testing.allocator.alloc(u8, idx + 5); defer testing.allocator.free(padding); @memset(padding, ' '); diff --git a/src/libs/freebsd.zig b/src/libs/freebsd.zig index fd8e80a78f6931227bd5e1ed7a21366c0cbc775b..0895ef4280ed25592fbcfda9fa54960675d28271 100644 --- a/src/libs/freebsd.zig +++ b/src/libs/freebsd.zig @@ -1077,7 +1077,6 @@ fn buildSharedLib( .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, }, .global = config, .cc_argv = &.{}, diff --git a/src/libs/glibc.zig b/src/libs/glibc.zig index a23757c2f6107cf8b2f48b732d5505563127a9d5..fce076dba86d74c52756d72419ed8859633992b5 100644 --- a/src/libs/glibc.zig +++ b/src/libs/glibc.zig @@ -398,7 +398,7 @@ fn start_asm_path(comp: *Compilation, arena: Allocator, basename: []const u8) ![ try result.appendSlice("powerpc" ++ s ++ "powerpc32"); } } else if (arch == .s390x) { - try result.appendSlice("s390" ++ s ++ "s390-64"); + try result.appendSlice("s390"); } else if (arch.isLoongArch()) { try result.appendSlice("loongarch"); } else if (arch == .m68k) { @@ -607,8 +607,6 @@ fn add_include_dirs_arch( try args.append("-I"); try args.append(try path.join(arena, &[_][]const u8{ dir, "s390", nptl })); } else { - try args.append("-I"); - try args.append(try path.join(arena, &[_][]const u8{ dir, "s390" ++ s ++ "s390-64" })); try args.append("-I"); try args.append(try path.join(arena, &[_][]const u8{ dir, "s390" })); } @@ -1223,7 +1221,6 @@ fn buildSharedLib( .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, }, .global = config, .cc_argv = &.{}, diff --git a/src/libs/libcxx.zig b/src/libs/libcxx.zig index 502199a58fbee46259a18257192e97d79cab3678..88a92274188ff5294bf7c868027f49d3c9e5d40c 100644 --- a/src/libs/libcxx.zig +++ b/src/libs/libcxx.zig @@ -172,7 +172,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError! .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, .pic = if (target_util.supports_fpic(target)) true else null, .code_model = comp.root_mod.code_model, }, @@ -366,7 +365,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, .unwind_tables = unwind_tables, .pic = if (target_util.supports_fpic(target)) true else null, .code_model = comp.root_mod.code_model, @@ -539,15 +537,15 @@ pub fn addCxxArgs( // is simple and works everywhere. try cflags.append("-D_LIBCPP_PSTL_BACKEND_SERIAL"); switch (optimize_mode) { - .Debug => { + .debug => { try cflags.append("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG"); try cflags.append("-D_LIBCPP_ASSERTION_SEMANTIC_DEFAULT=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE"); }, - .ReleaseFast, .ReleaseSmall => { + .fast, .small => { try cflags.append("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE"); try cflags.append("-D_LIBCPP_ASSERTION_SEMANTIC_DEFAULT=_LIBCPP_ASSERTION_SEMANTIC_IGNORE"); }, - .ReleaseSafe => { + .safe => { try cflags.append("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST"); try cflags.append("-D_LIBCPP_ASSERTION_SEMANTIC_DEFAULT=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE"); }, diff --git a/src/libs/libtsan.zig b/src/libs/libtsan.zig index cb15557c5b57c441217568e67caae602ddfa37a9..2621391c769f63c678ab419c0bc8db7c95f2326e 100644 --- a/src/libs/libtsan.zig +++ b/src/libs/libtsan.zig @@ -100,7 +100,6 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .valgrind = false, .unwind_tables = unwind_tables, .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, .pic = true, .no_builtin = true, .code_model = comp.root_mod.code_model, diff --git a/src/libs/libunwind.zig b/src/libs/libunwind.zig index 82ef9c34bc3d76b5cdbf2306ff8faf2526f54cbb..46c4b0332aad75d110ab172ccc3209a8257c66b4 100644 --- a/src/libs/libunwind.zig +++ b/src/libs/libunwind.zig @@ -118,7 +118,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr // defines will be correct. try cflags.append("-D_LIBUNWIND_IS_NATIVE_ONLY"); - if (comp.root_mod.optimize_mode == .Debug) { + if (comp.root_mod.optimize_mode == .debug) { try cflags.append("-D_DEBUG"); } if (!comp.config.any_non_single_threaded) { diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 99257442052cea392327370ca91879be1371cb3c..224b5ec27b4c0e8dac994ec4a54f85a689a11449 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -135,8 +135,8 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre }); switch (comp.compilerRtOptMode()) { - .Debug, .ReleaseSafe => try winpthreads_args.append("-DWINPTHREAD_DBG"), - .ReleaseFast, .ReleaseSmall => {}, + .debug, .safe => try winpthreads_args.append("-DWINPTHREAD_DBG"), + .fast, .small => {}, } for (mingw32_winpthreads_src) |dep| { diff --git a/src/libs/mingw/Preprocessor.zig b/src/libs/mingw/Preprocessor.zig index dcf8e01d043dbc6790aeff839718fd65b5e621cd..f6606eb54cd0f2ea46a85194dd79674115256499 100644 --- a/src/libs/mingw/Preprocessor.zig +++ b/src/libs/mingw/Preprocessor.zig @@ -15,7 +15,7 @@ const RawTokenList = std.ArrayList(Token); const ExpandBuf = std.ArrayList(Token); const Preprocessor = @This(); -const DefineMap = std.StringArrayHashMapUnmanaged(Macro); +const DefineMap = std.array_hash_map.String(Macro); const GeneratedTokens = std.ArrayList(u8); @@ -29,7 +29,7 @@ pub const Source = struct { buf: []const u8, }; -sources: std.StringArrayHashMapUnmanaged(Source) = .empty, +sources: std.array_hash_map.String(Source) = .empty, arena: Allocator, io: std.Io, @@ -91,9 +91,9 @@ fn addTokenAssumeCapacity(pp: *Preprocessor, tok: Token) void { fn defineBuiltins(pp: *Preprocessor) !void { var buf: [5]u8 = undefined; - var val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeBitSize(.longdouble)}) catch unreachable; + var val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeByteSize(.longdouble).?}) catch unreachable; try pp.defineBuiltinValue("__SIZEOF_LONG_DOUBLE__", val, .pp_num); - val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeBitSize(.double)}) catch unreachable; + val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeByteSize(.double).?}) catch unreachable; try pp.defineBuiltinValue("__SIZEOF_DOUBLE__", val, .pp_num); if (pp.target.abi.isGnu()) { diff --git a/src/libs/mingw/def.zig b/src/libs/mingw/def.zig index f1c112d16e0e49249faeaaf159f7e2b79e277861..0d67f4fe33539c9a7a25b648a6306f1251187333 100644 --- a/src/libs/mingw/def.zig +++ b/src/libs/mingw/def.zig @@ -61,7 +61,7 @@ pub const ModuleDefinition = struct { // or ? for C++ functions). Vectorcall functions won't have any // fixed prefix, but the function base name will still be at least // one char. - const name_len_without_at_suffix = std.mem.indexOfScalarPos(u8, e.name, 1, '@') orelse e.name.len; + const name_len_without_at_suffix = std.mem.findScalarPos(u8, e.name, 1, '@') orelse e.name.len; e.name = e.name[0..name_len_without_at_suffix]; } } @@ -452,7 +452,7 @@ pub const Parser = struct { var ext_name_needs_underscore = false; if (self.machine_type == .I386) { const is_decorated = isDecorated(name_tok.slice(self.tokenizer.source), self.module_definition_type); - const is_forward_target = ext_name_tok != null and std.mem.indexOfScalar(u8, name_tok.slice(self.tokenizer.source), '.') != null; + const is_forward_target = ext_name_tok != null and std.mem.findScalar(u8, name_tok.slice(self.tokenizer.source), '.') != null; name_needs_underscore = !is_decorated and !is_forward_target; if (ext_name_tok) |ext_name| { @@ -578,9 +578,9 @@ pub const Parser = struct { // themselves can start with an underscore, while a second one still needs // to be added. if (std.mem.startsWith(u8, symbol, "@")) return true; - if (std.mem.indexOf(u8, symbol, "@@") != null) return true; + if (std.mem.find(u8, symbol, "@@") != null) return true; if (std.mem.startsWith(u8, symbol, "?")) return true; - if (module_definition_type != .mingw and std.mem.indexOfScalar(u8, symbol, '@') != null) return true; + if (module_definition_type != .mingw and std.mem.findScalar(u8, symbol, '@') != null) return true; return false; } diff --git a/src/libs/mingw/implib.zig b/src/libs/mingw/implib.zig index f8ee4858e66d84de84c337c92f04e7c5363442e1..0a4deb7aeb87ac62939fc7a8fd1f6e3d6a1a7966 100644 --- a/src/libs/mingw/implib.zig +++ b/src/libs/mingw/implib.zig @@ -351,7 +351,7 @@ fn getNameType( // the leading underscore. In MinGW on the other hand, a decorated // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX). if (std.mem.startsWith(u8, ext_name, "_") and - std.mem.indexOfScalar(u8, ext_name, '@') != null and + std.mem.findScalar(u8, ext_name, '@') != null and module_definition_type != .mingw) return .NAME; if (!std.mem.eql(u8, symbol, ext_name)) diff --git a/src/libs/musl.zig b/src/libs/musl.zig index 3d32cc98b722252c029489076ea1ef7c9132cc6c..eca461940ce84ad1aa8d26dd406b6c4c3100dbb3 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -225,7 +225,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, }, .global = config, .cc_argv = cc_argv, diff --git a/src/libs/netbsd.zig b/src/libs/netbsd.zig index 3b7162363f148c5332dd721923ef8ff046faa46d..fb811df536ed7fa55f2ec630534e1c995ef978f7 100644 --- a/src/libs/netbsd.zig +++ b/src/libs/netbsd.zig @@ -727,7 +727,6 @@ fn buildSharedLib( .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, }, .global = config, .cc_argv = &.{}, diff --git a/src/libs/openbsd.zig b/src/libs/openbsd.zig index 7f6dc2db817ff630366f463a9405821714a12c95..e38183ab75db6a29eae22695f52550f69b35858c 100644 --- a/src/libs/openbsd.zig +++ b/src/libs/openbsd.zig @@ -647,7 +647,6 @@ fn buildSharedLib( .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, }, .global = config, .cc_argv = &.{}, diff --git a/src/link.zig b/src/link.zig index 075924712c1d71b2dc0eaa133591247b34a2de3c..58534f63f8b6e2e2840201eebbe4fd69af07ac33 100644 --- a/src/link.zig +++ b/src/link.zig @@ -1238,11 +1238,11 @@ pub const File = struct { } switch (base.tag) { - inline .elf2, .coff2, .wasm => |tag| { + inline .elf2, .coff2, .wasm, .c => |tag| { dev.check(tag.devFeature()); try @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node); }, - else => {}, + else => base.comp.link_prog_node.completeOne(), } base.post_prelink = true; @@ -2127,7 +2127,7 @@ pub fn resolveInputs( continue; }, } - @compileError("unreachable"); + comptime unreachable; } if (failed_libs.items.len > 0) { @@ -2239,6 +2239,60 @@ fn resolveLibInput( return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query); } + // In the case of OpenBSD, dynamic libraries are always versioned, without + // unversioned symlinks. OpenBSD patches LLD to select the highest-versioned + // shared library, and this code is intended to match that upstream behavior. + if (target.isOpenBSDLibC() and link_mode == .dynamic) versioned: { + const prefix = try std.fmt.allocPrint(arena, "lib{s}.so.", .{lib_name}); + + var dir = lib_directory.handle.openDir(io, ".", .{ .iterate = true }) catch |err| switch (err) { + error.NotDir, error.FileNotFound => break :versioned, + else => |e| fatal("unable to search for shared library '{s}.*': {s}", .{ prefix, @errorName(e) }), + }; + defer dir.close(io); + + var best_match_major: u32 = 0; + var best_match_minor: u32 = 0; + var best_match: ?[]const u8 = null; + + var iter = dir.iterate(); + while (iter.next(io) catch |err| { + fatal("unable to scan library directory '{s}'", .{@errorName(err)}); + }) |entry| { + if (entry.kind != .file) continue; + if (!std.mem.startsWith(u8, entry.name, prefix)) continue; + + const rest = entry.name[prefix.len..]; + var sit = std.mem.splitScalar(u8, rest, '.'); + const major_str = sit.next() orelse continue; + const minor_str = sit.next() orelse continue; + if (sit.next() != null) continue; + const major = std.fmt.parseInt(u32, major_str, 10) catch continue; + const minor = std.fmt.parseInt(u32, minor_str, 10) catch continue; + + if (major > best_match_major or (major == best_match_major and minor >= best_match_minor)) { + best_match_major = major; + best_match_minor = minor; + best_match = try arena.dupe(u8, entry.name); + } + } + + if (best_match) |found| { + const test_path: Path = .{ + .root_dir = lib_directory, + .sub_path = found, + }; + try checked_paths.print(gpa, "\n {f}", .{test_path}); + switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{ + .path = test_path, + .query = name_query.query, + }, link_mode, color)) { + .no_match => {}, + .ok => return .ok, + } + } + } + return .no_match; } diff --git a/src/link/C.zig b/src/link/C.zig index ae8526aafefb5adbcff87d1a90f789653e9faa8a..cf82ed146fa853cc449074721eb294834cde6d1b 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -43,6 +43,8 @@ type_dependencies: std.ArrayList(link.ConstPool.Index), /// one array. align_dependency_masks: std.ArrayList(u64), +/// Emitted at the top of the file. This can be cached since it only depends on the target. +header: String, /// All NAVs, regardless of whether they are functions or simple constants, are put in this map. navs: std.array_hash_map.Auto(InternPool.Nav.Index, RenderedDecl), /// All UAVs which may be referenced are in this map. The UAV alignment is not included in the @@ -404,9 +406,8 @@ pub fn createEmpty( emit: Path, options: link.File.OpenOptions, ) !*C { + assert(comp.root_mod.resolved_target.result.ofmt == .c); const io = comp.io; - const target = &comp.root_mod.resolved_target.result; - assert(target.ofmt == .c); const optimize_mode = comp.root_mod.optimize_mode; const use_lld = build_options.have_llvm and comp.config.use_lld; const use_llvm = comp.config.use_llvm; @@ -422,14 +423,13 @@ pub fn createEmpty( }); errdefer file.close(io); - const c_file = try arena.create(C); - - c_file.* = .{ + const c = try arena.create(C); + c.* = .{ .base = .{ .tag = .c, .comp = comp, .emit = emit, - .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), + .gc_sections = options.gc_sections orelse (optimize_mode != .debug and output_mode != .Obj), .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -439,6 +439,7 @@ pub fn createEmpty( .string_bytes = .empty, .type_dependencies = .empty, .align_dependency_masks = .empty, + .header = .empty, .navs = .empty, .uavs = .empty, .type_pool = .empty, @@ -447,8 +448,7 @@ pub fn createEmpty( .exported_navs = .empty, .exported_uavs = .empty, }; - - return c_file; + return c; } pub fn deinit(c: *C) void { @@ -469,6 +469,21 @@ pub fn deinit(c: *C) void { c.exported_uavs.deinit(gpa); } +pub fn prelink(c: *C, prog_node: std.Progress.Node) !void { + const comp = c.base.comp; + + const sub_prog_node = prog_node.start("Generate Header", 0); + defer sub_prog_node.end(); + + var header_aw: std.Io.Writer.Allocating = .init(comp.gpa); + defer header_aw.deinit(); + codegen.genHeader(comp.zcu.?, &header_aw.writer) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + else => |e| return e, + }; + c.header = try c.addString(&.{header_aw.written()}); +} + pub fn updateContainerType( c: *C, pt: Zcu.PerThread, @@ -727,7 +742,6 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog const io = comp.io; const zcu = c.base.comp.zcu.?; const ip = &zcu.intern_pool; - const target = zcu.getTarget(); const active = zcu.activate(tid); defer active.deactivate(); const pt = active.pt; @@ -943,7 +957,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog // We have discovered the full set of NAVs, UAVs, and types we need to emit, and will now begin // to build the output buffer. Our strategy is to emit the C source in this order: // - // * ABI defines and `#include "zig.h"` + // * Header // * Big-int type definitions // * Other CType definitions (traversing the dependency graph to sort topologically) // * Global assembly @@ -968,7 +982,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog // We know exactly what we'll be emitting, so can reserve capacity for all of our buffers! - try f.all_buffers.ensureUnusedCapacity(gpa, 3 + // ABI defines and `#include "zig.h"` + try f.all_buffers.ensureUnusedCapacity(gpa, 1 + // Header 1 + // Big-int type definitions need_types.count() + // `RenderedType.fwd_decl` (worst-case) need_types.count() + // `RenderedType.definition` @@ -984,20 +998,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog need_uavs.count() * 3 + // UAV definitions ("static ", "zig_align(4)", "") need_navs.count() * 2); // NAV definitions ("static ", "") - // ABI defines and `#include "zig.h"` - switch (target.abi) { - .msvc, .itanium => f.appendBufAssumeCapacity("#define ZIG_TARGET_ABI_MSVC\n"), - else => {}, - } - f.appendBufAssumeCapacity(try std.fmt.allocPrint( - arena, - "#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", - .{target.cMaxIntAlignment()}, - )); - f.appendBufAssumeCapacity( - \\#include "zig.h" - \\ - ); + f.appendBufAssumeCapacity(c.header.get(c)); // Big-int type definitions var bigint_aw: std.Io.Writer.Allocating = .init(gpa); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 136c1184f64554dfcee7d60c7e044d662a778d82..78195f75241f3808610760eedb7d4b83eba681d5 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -621,7 +621,7 @@ pub const LongNamesTable = struct { } pub fn hash(_: Adapter, key: []const u8) u32 { - assert(std.mem.indexOfScalar(u8, key, 0) == null); + assert(std.mem.findScalar(u8, key, 0) == null); return std.array_hash_map.hashString(key); } }; @@ -711,7 +711,7 @@ pub const ExportTable = struct { } pub fn hash(_: Adapter, key: []const u8) u32 { - assert(std.mem.indexOfScalar(u8, key, 0) == null); + assert(std.mem.findScalar(u8, key, 0) == null); return std.array_hash_map.hashString(key); } }; @@ -759,7 +759,7 @@ pub const ImportTable = struct { } pub fn hash(_: Adapter, key: []const u8) u32 { - assert(std.mem.indexOfScalar(u8, key, 0) == null); + assert(std.mem.findScalar(u8, key, 0) == null); return std.array_hash_map.hashString(key); } }; @@ -822,7 +822,7 @@ pub const String = enum(u32) { pub fn toSlice(s: String, coff: *Coff) [:0]const u8 { const slice = coff.string_bytes.items[@backingInt(s)..]; - return slice[0..std.mem.indexOfScalar(u8, slice, 0).? :0]; + return slice[0..std.mem.findScalar(u8, slice, 0).? :0]; } pub fn toOptional(s: String) String.Optional { @@ -3535,7 +3535,7 @@ fn objectSectionParentName(coff: *Coff, name: []const u8) []const u8 { // Otherwise, we want to keep the full name so that this sort can occur correctly when // the object is finally linked into an image. return if (coff.isImage()) - name[0 .. std.mem.indexOfScalar(u8, name, '$') orelse name.len] + name[0 .. std.mem.findScalar(u8, name, '$') orelse name.len] else name; } @@ -3654,7 +3654,7 @@ fn verifyParentSectionAttributes( parent.name(coff).toSlice(coff), }); - inline for (comptime std.meta.fieldNames(ObjectSectionAttributes)) |field| { + inline for (@typeInfo(ObjectSectionAttributes).@"struct".field_names) |field| { if (@field(child_attrs, field) != @field(parent_attrs, field)) { err.addNote("flags.{s} was {d} in {s}, but {d} in {s}", .{ field, @@ -5370,7 +5370,9 @@ fn loadDll(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) LoadInp } pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { - _ = prog_node; + const sub_prog_node = prog_node.start("COFF Prelink", 0); + defer sub_prog_node.end(); + const base = coff.base; const comp = base.comp; @@ -5598,11 +5600,11 @@ fn updateFuncInner( const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ .alignment = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { - .Debug, - .ReleaseSafe, - .ReleaseFast, + .debug, + .safe, + .fast, => target_util.defaultFunctionAlignment(target), - .ReleaseSmall => target_util.minFunctionAlignment(target), + .small => target_util.minFunctionAlignment(target), }, else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), }.toStdMem(), @@ -5735,7 +5737,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { const gpa = comp.gpa; const max_notes = 4; - var undef_indices: std.ArrayListUnmanaged(u32) = .empty; + var undef_indices: std.ArrayList(u32) = .empty; for (coff.relocs.items, 0..) |reloc, reloc_i| { if (reloc.flags.free) continue; const target_sym = reloc.target.get(coff); @@ -5886,7 +5888,9 @@ pub fn flush( prog_node: std.Progress.Node, ) link.Error!void { _ = arena; - _ = prog_node; + const sub_prog_node = prog_node.start("COFF Flush", 0); + defer sub_prog_node.end(); + const comp = coff.base.comp; // TODO: When https://github.com/ziglang/zig/issues/23617 is in, @@ -6649,11 +6653,11 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { const target = &comp.root_mod.resolved_target.result; const alignment = switch (comp.root_mod.optimize_mode) { - .Debug, - .ReleaseSafe, - .ReleaseFast, + .debug, + .safe, + .fast, => target_util.defaultFunctionAlignment(target), - .ReleaseSmall => target_util.minFunctionAlignment(target), + .small => target_util.minFunctionAlignment(target), }.toStdMem(); const parent_si = (try coff.pseudoSectionMapIndex( .@".thunks", @@ -6983,7 +6987,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { continue; import_hint_name_index = @intCast(import_hint_name_align.forward( - std.mem.indexOfScalarPos( + std.mem.findScalarPos( u8, import_hint_name_slice, import_hint_name_index, diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 1b2aa830d23ee24903085a36db49ce1a42c91c72..c8eef4c8651367edbc1abffcd3cf24d76b847603 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -4151,8 +4151,8 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co .x86_64_regcall_v3_sysv => .LLVM_X86RegCall, .x86_64_regcall_v4_win => .LLVM_X86RegCall, .x86_64_vectorcall => .LLVM_vectorcall, - .x86_sysv => .normal, - .x86_win => .normal, + .x86_sysv, .x86_win, .x86_mingw => .normal, + .x86_64_preserve_none => .LLVM_PreserveNone, .x86_stdcall => .BORLAND_stdcall, .x86_fastcall => .BORLAND_msfastcall, .x86_thiscall => .BORLAND_thiscall, @@ -4166,6 +4166,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co .aarch64_aapcs_win => .normal, .aarch64_vfabi => .LLVM_AAPCS, .aarch64_vfabi_sve => .LLVM_AAPCS, + .aarch64_preserve_none => .LLVM_PreserveNone, .arm_aapcs => .LLVM_AAPCS, .arm_aapcs_vfp => .LLVM_AAPCS_VFP, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index d0448f575793e6af830d9ae3b37cf3ca827a89bb..80844d3d8832b7b326411038a286cc2391b4d097 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -127,7 +127,7 @@ const SectionIndexes = struct { symtab: ?u32 = null, }; -const ProgramHeaderList = std.ArrayList(elf.Elf64_Phdr); +const ProgramHeaderList = std.ArrayList(elf.Elf64.Phdr); const OptionalProgramHeaderIndex = enum(u16) { none = std.math.maxInt(u16), @@ -159,21 +159,21 @@ const ProgramHeaderIndex = enum(u16) { }; const ProgramHeaderIndexes = struct { - /// PT_PHDR + /// PT.PHDR table: OptionalProgramHeaderIndex = .none, - /// PT_LOAD for PHDR table + /// PT.LOAD for PHDR table /// We add this special load segment to ensure the EHDR and PHDR table are always /// loaded into memory. table_load: OptionalProgramHeaderIndex = .none, - /// PT_INTERP + /// PT.INTERP interp: OptionalProgramHeaderIndex = .none, - /// PT_DYNAMIC + /// PT.DYNAMIC dynamic: OptionalProgramHeaderIndex = .none, - /// PT_GNU_EH_FRAME + /// PT.GNU_EH_FRAME gnu_eh_frame: OptionalProgramHeaderIndex = .none, - /// PT_GNU_STACK + /// PT.GNU_STACK gnu_stack: OptionalProgramHeaderIndex = .none, - /// PT_TLS + /// PT.TLS /// TODO I think ELF permits multiple TLS segments but for now, assume one per file. tls: OptionalProgramHeaderIndex = .none, }; @@ -260,7 +260,7 @@ pub fn createEmpty( .tag = .elf, .comp = comp, .emit = emit, - .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), + .gc_sections = options.gc_sections orelse (optimize_mode != .debug and output_mode != .Obj), .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse !is_native_os, @@ -334,23 +334,23 @@ pub fn createEmpty( if (!is_obj_or_ar) { try self.dynstrtab.append(gpa, 0); - // Initialize PT_PHDR program header + // Initialize PT.PHDR program header const p_align: u16 = switch (self.ptr_width) { - .p32 => @alignOf(elf.Elf32_Phdr), - .p64 => @alignOf(elf.Elf64_Phdr), + .p32 => @alignOf(elf.Elf32.Phdr), + .p64 => @alignOf(elf.Elf64.Phdr), }; const ehsize: u64 = switch (self.ptr_width) { .p32 => @sizeOf(elf.Elf32_Ehdr), .p64 => @sizeOf(elf.Elf64_Ehdr), }; const phsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Phdr), - .p64 => @sizeOf(elf.Elf64_Phdr), + .p32 => @sizeOf(elf.Elf32.Phdr), + .p64 => @sizeOf(elf.Elf64.Phdr), }; const max_nphdrs = comptime getMaxNumberOfPhdrs(); const reserved: u64 = mem.alignForward(u64, padToIdeal(max_nphdrs * phsize), self.page_size); self.phdr_indexes.table = (try self.addPhdr(.{ - .type = elf.PT_PHDR, + .type = @backingInt(elf.PT.PHDR), .flags = elf.PF_R, .@"align" = p_align, .addr = self.image_base + ehsize, @@ -359,7 +359,7 @@ pub fn createEmpty( .memsz = reserved, })).toOptional(); self.phdr_indexes.table_load = (try self.addPhdr(.{ - .type = elf.PT_LOAD, + .type = @backingInt(elf.PT.LOAD), .flags = elf.PF_R, .@"align" = self.page_size, .addr = self.image_base, @@ -514,11 +514,11 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 { } for (self.phdrs.items) |phdr| { - if (phdr.p_type != elf.PT_LOAD) continue; - const increased_size = padToIdeal(phdr.p_filesz); - const test_end = phdr.p_offset +| increased_size; + if (phdr.type != .LOAD) continue; + const increased_size = padToIdeal(phdr.filesz); + const test_end = phdr.offset +| increased_size; if (start < test_end) { - if (end > phdr.p_offset) return test_end; + if (end > phdr.offset) return test_end; if (test_end < std.math.maxInt(u64)) at_end = false; } } @@ -538,8 +538,8 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 { if (section.sh_offset < min_pos) min_pos = section.sh_offset; } for (self.phdrs.items) |phdr| { - if (phdr.p_offset <= start) continue; - if (phdr.p_offset < min_pos) min_pos = phdr.p_offset; + if (phdr.offset <= start) continue; + if (phdr.offset < min_pos) min_pos = phdr.offset; } return min_pos - start; } @@ -714,7 +714,6 @@ pub fn loadInput(self: *Elf, input: link.Input) !void { const target = self.getTarget(); const debug_fmt_strip = comp.config.debug_format == .strip; const default_sym_version = self.default_sym_version; - const is_static_lib = self.base.isStaticLib(); if (comp.verbose_link) { comp.mutex.lockUncancelable(io); // protect comp.arena @@ -733,7 +732,11 @@ pub fn loadInput(self: *Elf, input: link.Input) !void { .res => unreachable, .dso_exact => @panic("TODO"), .object => |obj| try parseObject(self, obj), - .archive => |obj| try parseArchive(gpa, io, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj, is_static_lib), + .archive => |obj| if (self.base.isStaticLib()) { + // Ignore static library inputs when generating a static library. + } else { + try parseArchive(gpa, io, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj); + }, .dso => |dso| try parseDso(gpa, io, diags, dso, &self.shared_objects, &self.files, target), } } @@ -1083,7 +1086,6 @@ fn parseArchive( default_sym_version: elf.Versym, objects: *std.ArrayList(File.Index), obj: link.Input.Object, - is_static_lib: bool, ) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1092,17 +1094,14 @@ fn parseArchive( var archive = try Archive.parse(gpa, io, diags, file_handles, obj.path, fh); defer archive.deinit(gpa); - const init_alive = if (is_static_lib) true else obj.must_link; - for (archive.objects) |extracted| { const index: File.Index = @intCast(try files.addOne(gpa)); files.set(index, .{ .object = extracted }); const object = &files.items(.data)[index].object; object.index = index; - object.alive = init_alive; + object.alive = obj.must_link; try object.parseCommon(gpa, io, diags, obj.path, obj.file, target); - if (!is_static_lib) - try object.parse(gpa, io, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version); + try object.parse(gpa, io, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version); try objects.append(gpa, index); } } @@ -1471,34 +1470,34 @@ fn writePhdrTable(self: *Elf) !void { const phdr_table = &self.phdrs.items[self.phdr_indexes.table.int().?]; log.debug("writing program headers from 0x{x} to 0x{x}", .{ - phdr_table.p_offset, - phdr_table.p_offset + phdr_table.p_filesz, + phdr_table.offset, + phdr_table.offset + phdr_table.filesz, }); switch (self.ptr_width) { .p32 => { - const buf = try gpa.alloc(elf.Elf32_Phdr, self.phdrs.items.len); + const buf = try gpa.alloc(elf.Elf32.Phdr, self.phdrs.items.len); defer gpa.free(buf); for (buf, 0..) |*phdr, i| { phdr.* = phdrTo32(self.phdrs.items[i]); if (foreign_endian) { - mem.byteSwapAllFields(elf.Elf32_Phdr, phdr); + mem.byteSwapAllFields(elf.Elf32.Phdr, phdr); } } - try self.pwriteAll(@ptrCast(buf), phdr_table.p_offset); + try self.pwriteAll(@ptrCast(buf), phdr_table.offset); }, .p64 => { - const buf = try gpa.alloc(elf.Elf64_Phdr, self.phdrs.items.len); + const buf = try gpa.alloc(elf.Elf64.Phdr, self.phdrs.items.len); defer gpa.free(buf); for (buf, 0..) |*phdr, i| { phdr.* = self.phdrs.items[i]; if (foreign_endian) { - mem.byteSwapAllFields(elf.Elf64_Phdr, phdr); + mem.byteSwapAllFields(elf.Elf64.Phdr, phdr); } } - try self.pwriteAll(@ptrCast(buf), phdr_table.p_offset); + try self.pwriteAll(@ptrCast(buf), phdr_table.offset); }, } } @@ -1581,7 +1580,7 @@ pub fn writeElfHeader(self: *Elf) !void { const entry_sym = obj.entrySymbol(self) orelse break :blk 0; break :blk @intCast(entry_sym.address(.{}, self)); } else 0; - const phdr_table_offset = if (self.phdr_indexes.table.int()) |phndx| self.phdrs.items[phndx].p_offset else 0; + const phdr_table_offset = if (self.phdr_indexes.table.int()) |phndx| self.phdrs.items[phndx].offset else 0; switch (self.ptr_width) { .p32 => { mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(e_entry), endian); @@ -1622,8 +1621,8 @@ pub fn writeElfHeader(self: *Elf) !void { index += 2; const e_phentsize: u16 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Phdr), - .p64 => @sizeOf(elf.Elf64_Phdr), + .p32 => @sizeOf(elf.Elf32.Phdr), + .p64 => @sizeOf(elf.Elf64.Phdr), }; mem.writeInt(u16, hdr_buf[index..][0..2], e_phentsize, endian); index += 2; @@ -2091,26 +2090,26 @@ fn initSpecialPhdrs(self: *Elf) !void { if (self.section_indexes.interp != null and self.phdr_indexes.interp == .none) { self.phdr_indexes.interp = (try self.addPhdr(.{ - .type = elf.PT_INTERP, + .type = @backingInt(elf.PT.INTERP), .flags = elf.PF_R, .@"align" = 1, })).toOptional(); } if (self.section_indexes.dynamic != null and self.phdr_indexes.dynamic == .none) { self.phdr_indexes.dynamic = (try self.addPhdr(.{ - .type = elf.PT_DYNAMIC, + .type = @backingInt(elf.PT.DYNAMIC), .flags = elf.PF_R | elf.PF_W, })).toOptional(); } if (self.section_indexes.eh_frame_hdr != null and self.phdr_indexes.gnu_eh_frame == .none) { self.phdr_indexes.gnu_eh_frame = (try self.addPhdr(.{ - .type = elf.PT_GNU_EH_FRAME, + .type = @backingInt(elf.PT.GNU_EH_FRAME), .flags = elf.PF_R, })).toOptional(); } if (self.phdr_indexes.gnu_stack == .none) { self.phdr_indexes.gnu_stack = (try self.addPhdr(.{ - .type = elf.PT_GNU_STACK, + .type = @backingInt(elf.PT.GNU_STACK), .flags = elf.PF_W | elf.PF_R, .memsz = self.base.stack_size, .@"align" = 1, @@ -2122,7 +2121,7 @@ fn initSpecialPhdrs(self: *Elf) !void { } else false; if (has_tls and self.phdr_indexes.tls == .none) { self.phdr_indexes.tls = (try self.addPhdr(.{ - .type = elf.PT_TLS, + .type = @backingInt(elf.PT.TLS), .flags = elf.PF_R, .@"align" = 1, })).toOptional(); @@ -2173,7 +2172,7 @@ fn sortInitFini(self: *Elf) !void { => is_init_fini = true, else => { const name = self.getShString(shdr.sh_name); - is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null; + is_ctor_dtor = mem.find(u8, name, ".ctors") != null or mem.find(u8, name, ".dtors") != null; }, } if (!is_init_fini and !is_ctor_dtor) continue; @@ -2260,15 +2259,15 @@ fn setHashSections(self: *Elf) !void { } } -fn phdrRank(phdr: elf.Elf64_Phdr) u8 { - return switch (phdr.p_type) { - elf.PT_NULL => 0, - elf.PT_PHDR => 1, - elf.PT_INTERP => 2, - elf.PT_LOAD => 3, - elf.PT_DYNAMIC, elf.PT_TLS => 4, - elf.PT_GNU_EH_FRAME => 5, - elf.PT_GNU_STACK => 6, +fn phdrRank(phdr: elf.Elf64.Phdr) u8 { + return switch (phdr.type) { + .NULL => 0, + .PHDR => 1, + .INTERP => 2, + .LOAD => 3, + .DYNAMIC, .TLS => 4, + .GNU_EH_FRAME => 5, + .GNU_STACK => 6, else => 7, }; } @@ -2282,12 +2281,12 @@ fn sortPhdrs( const Entry = struct { phndx: u16, - pub fn lessThan(program_headers: []const elf.Elf64_Phdr, lhs: @This(), rhs: @This()) bool { + pub fn lessThan(program_headers: []const elf.Elf64.Phdr, lhs: @This(), rhs: @This()) bool { const lhs_phdr = program_headers[lhs.phndx]; const rhs_phdr = program_headers[rhs.phndx]; const lhs_rank = phdrRank(lhs_phdr); const rhs_rank = phdrRank(rhs_phdr); - if (lhs_rank == rhs_rank) return lhs_phdr.p_vaddr < rhs_phdr.p_vaddr; + if (lhs_rank == rhs_rank) return lhs_phdr.vaddr < rhs_phdr.vaddr; return lhs_rank < rhs_rank; } }; @@ -2299,7 +2298,7 @@ fn sortPhdrs( } // The `@as` here works around a bug in the C backend. - mem.sort(Entry, entries, @as([]const elf.Elf64_Phdr, phdrs.items), Entry.lessThan); + mem.sort(Entry, entries, @as([]const elf.Elf64.Phdr, phdrs.items), Entry.lessThan); const backlinks = try gpa.alloc(u16, entries.len); defer gpa.free(backlinks); @@ -2655,8 +2654,8 @@ fn addLoadPhdrs(self: *Elf) error{OutOfMemory}!void { if (shdr.sh_type == elf.SHT_NULL) continue; if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; const flags = shdrToPhdrFlags(shdr.sh_flags); - if (self.getPhdr(.{ .flags = flags, .type = elf.PT_LOAD }) == .none) { - _ = try self.addPhdr(.{ .flags = flags, .type = elf.PT_LOAD }); + if (self.getPhdr(.{ .flags = flags, .type = @backingInt(elf.PT.LOAD) }) == .none) { + _ = try self.addPhdr(.{ .flags = flags, .type = @backingInt(elf.PT.LOAD) }); } } } @@ -2672,11 +2671,11 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void { .p64 => @sizeOf(elf.Elf64_Ehdr), }; const phsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Phdr), - .p64 => @sizeOf(elf.Elf64_Phdr), + .p32 => @sizeOf(elf.Elf32.Phdr), + .p64 => @sizeOf(elf.Elf64.Phdr), }; const needed_size = self.phdrs.items.len * phsize; - const available_space = self.allocatedSize(phdr_table.p_offset); + const available_space = self.allocatedSize(phdr_table.offset); if (needed_size > available_space) { // In this case, we have two options: @@ -2689,10 +2688,10 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void { err.addNote("required 0x{x}, available 0x{x}", .{ needed_size, available_space }); } - phdr_table_load.p_filesz = needed_size + ehsize; - phdr_table_load.p_memsz = needed_size + ehsize; - phdr_table.p_filesz = needed_size; - phdr_table.p_memsz = needed_size; + phdr_table_load.filesz = needed_size + ehsize; + phdr_table_load.memsz = needed_size + ehsize; + phdr_table.filesz = needed_size; + phdr_table.memsz = needed_size; } /// Allocates alloc sections and creates load segments for sections @@ -2758,7 +2757,7 @@ pub fn allocateAllocSections(self: *Elf) !void { // of any section that is contained in a cover and use it to align // the start address of the segement (and first section). const phdr_table = &self.phdrs.items[self.phdr_indexes.table_load.int().?]; - var addr = phdr_table.p_vaddr + phdr_table.p_memsz; + var addr = phdr_table.vaddr + phdr_table.memsz; for (covers) |cover| { if (cover.items.len == 0) continue; @@ -2817,14 +2816,14 @@ pub fn allocateAllocSections(self: *Elf) !void { } const first = slice.items(.shdr)[cover.items[0]]; - const phndx = self.getPhdr(.{ .type = elf.PT_LOAD, .flags = shdrToPhdrFlags(first.sh_flags) }).unwrap().?; + const phndx = self.getPhdr(.{ .type = @backingInt(elf.PT.LOAD), .flags = shdrToPhdrFlags(first.sh_flags) }).unwrap().?; const phdr = &self.phdrs.items[phndx.int()]; - const allocated_size = self.allocatedSize(phdr.p_offset); + const allocated_size = self.allocatedSize(phdr.offset); if (filesz > allocated_size) { - const old_offset = phdr.p_offset; - phdr.p_offset = 0; + const old_offset = phdr.offset; + phdr.offset = 0; var new_offset = try self.findFreeSpace(filesz, @"align"); - phdr.p_offset = new_offset; + phdr.offset = new_offset; log.debug("moving phdr({d}) from 0x{x} to 0x{x}", .{ phndx, old_offset, new_offset }); @@ -2854,11 +2853,11 @@ pub fn allocateAllocSections(self: *Elf) !void { } } - phdr.p_vaddr = first.sh_addr; - phdr.p_paddr = first.sh_addr; - phdr.p_memsz = memsz; - phdr.p_filesz = filesz; - phdr.p_align = @"align"; + phdr.vaddr = first.sh_addr; + phdr.paddr = first.sh_addr; + phdr.memsz = memsz; + phdr.filesz = filesz; + phdr.@"align" = @"align"; addr = mem.alignForward(u64, addr, self.page_size); } @@ -2902,12 +2901,12 @@ fn allocateSpecialPhdrs(self: *Elf) void { if (pair[0].int()) |index| { const shdr = slice.items(.shdr)[pair[1].?]; const phdr = &self.phdrs.items[index]; - phdr.p_align = shdr.sh_addralign; - phdr.p_offset = shdr.sh_offset; - phdr.p_vaddr = shdr.sh_addr; - phdr.p_paddr = shdr.sh_addr; - phdr.p_filesz = shdr.sh_size; - phdr.p_memsz = shdr.sh_size; + phdr.@"align" = shdr.sh_addralign; + phdr.offset = shdr.sh_offset; + phdr.vaddr = shdr.sh_addr; + phdr.paddr = shdr.sh_addr; + phdr.filesz = shdr.sh_size; + phdr.memsz = shdr.sh_size; } } @@ -2924,25 +2923,25 @@ fn allocateSpecialPhdrs(self: *Elf) void { shndx += 1; continue; } - phdr.p_offset = shdr.sh_offset; - phdr.p_vaddr = shdr.sh_addr; - phdr.p_paddr = shdr.sh_addr; - phdr.p_align = shdr.sh_addralign; + phdr.offset = shdr.sh_offset; + phdr.vaddr = shdr.sh_addr; + phdr.paddr = shdr.sh_addr; + phdr.@"align" = shdr.sh_addralign; shndx += 1; - phdr.p_align = @max(phdr.p_align, shdr.sh_addralign); + phdr.@"align" = @max(phdr.@"align", shdr.sh_addralign); if (shdr.sh_type != elf.SHT_NOBITS) { - phdr.p_filesz = shdr.sh_offset + shdr.sh_size - phdr.p_offset; + phdr.filesz = shdr.sh_offset + shdr.sh_size - phdr.offset; } - phdr.p_memsz = shdr.sh_addr + shdr.sh_size - phdr.p_vaddr; + phdr.memsz = shdr.sh_addr + shdr.sh_size - phdr.vaddr; while (shndx < shdrs.len) : (shndx += 1) { const next = shdrs[shndx]; if (next.sh_flags & elf.SHF_TLS == 0) break; - phdr.p_align = @max(phdr.p_align, next.sh_addralign); + phdr.@"align" = @max(phdr.@"align", next.sh_addralign); if (next.sh_type != elf.SHT_NOBITS) { - phdr.p_filesz = next.sh_offset + next.sh_size - phdr.p_offset; + phdr.filesz = next.sh_offset + next.sh_size - phdr.offset; } - phdr.p_memsz = next.sh_addr + next.sh_size - phdr.p_vaddr; + phdr.memsz = next.sh_addr + next.sh_size - phdr.vaddr; } } } @@ -3347,16 +3346,16 @@ pub fn archPtrWidthBytes(self: Elf) u8 { return @intCast(@divExact(self.getTarget().ptrBitWidth(), 8)); } -fn phdrTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr { +fn phdrTo32(phdr: elf.Elf64.Phdr) elf.Elf32.Phdr { return .{ - .p_type = phdr.p_type, - .p_flags = phdr.p_flags, - .p_offset = @as(u32, @intCast(phdr.p_offset)), - .p_vaddr = @as(u32, @intCast(phdr.p_vaddr)), - .p_paddr = @as(u32, @intCast(phdr.p_paddr)), - .p_filesz = @as(u32, @intCast(phdr.p_filesz)), - .p_memsz = @as(u32, @intCast(phdr.p_memsz)), - .p_align = @as(u32, @intCast(phdr.p_align)), + .type = phdr.type, + .flags = phdr.flags, + .offset = @intCast(phdr.offset), + .vaddr = @intCast(phdr.vaddr), + .paddr = @intCast(phdr.paddr), + .filesz = @intCast(phdr.filesz), + .memsz = @intCast(phdr.memsz), + .@"align" = @intCast(phdr.@"align"), }; } @@ -3397,7 +3396,7 @@ fn getPhdr(self: *Elf, opts: struct { if (self.phdr_indexes.table_load.int()) |index| { if (phndx == index) continue; } - if (phdr.p_type == opts.type and phdr.p_flags == opts.flags) + if (@backingInt(phdr.type) == opts.type and @backingInt(phdr.flags) == opts.flags) return @fromBackingInt(@intCast(phndx)); } return .none; @@ -3415,14 +3414,14 @@ fn addPhdr(self: *Elf, opts: struct { const gpa = self.base.comp.gpa; const index: ProgramHeaderIndex = @fromBackingInt(@intCast(self.phdrs.items.len)); try self.phdrs.append(gpa, .{ - .p_type = opts.type, - .p_flags = opts.flags, - .p_offset = opts.offset, - .p_vaddr = opts.addr, - .p_paddr = opts.addr, - .p_filesz = opts.filesz, - .p_memsz = opts.memsz, - .p_align = opts.@"align", + .type = @fromBackingInt(opts.type), + .flags = @fromBackingInt(opts.flags), + .offset = opts.offset, + .vaddr = opts.addr, + .paddr = opts.addr, + .filesz = opts.filesz, + .memsz = opts.memsz, + .@"align" = opts.@"align", }); return index; } @@ -3673,9 +3672,9 @@ pub fn tpAddress(self: *Elf) i64 { const index = self.phdr_indexes.tls.int() orelse return 0; const phdr = self.phdrs.items[index]; const addr = switch (self.getTarget().cpu.arch) { - .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align), - .aarch64, .aarch64_be => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align), - .riscv64, .riscv64be => phdr.p_vaddr, + .x86_64 => mem.alignForward(u64, phdr.vaddr + phdr.memsz, phdr.@"align"), + .aarch64, .aarch64_be => mem.alignBackward(u64, phdr.vaddr - 16, phdr.@"align"), + .riscv64, .riscv64be => phdr.vaddr, else => |arch| std.debug.panic("TODO implement getTpAddress for {s}", .{@tagName(arch)}), }; return @intCast(addr); @@ -3684,13 +3683,13 @@ pub fn tpAddress(self: *Elf) i64 { pub fn dtpAddress(self: *Elf) i64 { const index = self.phdr_indexes.tls.int() orelse return 0; const phdr = self.phdrs.items[index]; - return @intCast(phdr.p_vaddr); + return @intCast(phdr.vaddr); } pub fn tlsAddress(self: *Elf) i64 { const index = self.phdr_indexes.tls.int() orelse return 0; const phdr = self.phdrs.items[index]; - return @intCast(phdr.p_vaddr); + return @intCast(phdr.vaddr); } pub fn getShString(self: Elf, off: u32) [:0]const u8 { @@ -3702,7 +3701,7 @@ fn shString( off: u32, ) [:0]const u8 { const slice = shstrtab[off..]; - return slice[0..mem.indexOfScalar(u8, slice, 0).? :0]; + return slice[0..mem.findScalar(u8, slice, 0).? :0]; } pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 { @@ -3886,10 +3885,10 @@ fn formatShdrFlags(sh_flags: u64, writer: *std.Io.Writer) std.Io.Writer.Error!vo const FormatPhdr = struct { elf_file: *Elf, - phdr: elf.Elf64_Phdr, + phdr: elf.Elf64.Phdr, }; -fn fmtPhdr(self: *Elf, phdr: elf.Elf64_Phdr) std.fmt.Alt(FormatPhdr, formatPhdr) { +fn fmtPhdr(self: *Elf, phdr: elf.Elf64.Phdr) std.fmt.Alt(FormatPhdr, formatPhdr) { return .{ .data = .{ .phdr = phdr, .elf_file = self, @@ -3898,28 +3897,28 @@ fn fmtPhdr(self: *Elf, phdr: elf.Elf64_Phdr) std.fmt.Alt(FormatPhdr, formatPhdr) fn formatPhdr(ctx: FormatPhdr, writer: *std.Io.Writer) std.Io.Writer.Error!void { const phdr = ctx.phdr; - const write = phdr.p_flags & elf.PF_W != 0; - const read = phdr.p_flags & elf.PF_R != 0; - const exec = phdr.p_flags & elf.PF_X != 0; + const write = phdr.flags.W; + const read = phdr.flags.R; + const exec = phdr.flags.X; var flags: [3]u8 = @splat('_'); if (exec) flags[0] = 'X'; if (write) flags[1] = 'W'; if (read) flags[2] = 'R'; - const p_type = switch (phdr.p_type) { - elf.PT_LOAD => "LOAD", - elf.PT_TLS => "TLS", - elf.PT_GNU_EH_FRAME => "GNU_EH_FRAME", - elf.PT_GNU_STACK => "GNU_STACK", - elf.PT_DYNAMIC => "DYNAMIC", - elf.PT_INTERP => "INTERP", - elf.PT_NULL => "NULL", - elf.PT_PHDR => "PHDR", - elf.PT_NOTE => "NOTE", + const p_type = switch (phdr.type) { + .LOAD => "LOAD", + .TLS => "TLS", + .GNU_EH_FRAME => "GNU_EH_FRAME", + .GNU_STACK => "GNU_STACK", + .DYNAMIC => "DYNAMIC", + .INTERP => "INTERP", + .NULL => "NULL", + .PHDR => "PHDR", + .NOTE => "NOTE", else => "UNKNOWN", }; try writer.print("{s} : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})", .{ - p_type, flags, phdr.p_offset, phdr.p_vaddr, - phdr.p_align, phdr.p_filesz, phdr.p_memsz, + p_type, flags, phdr.offset, phdr.vaddr, + phdr.@"align", phdr.filesz, phdr.memsz, }); } @@ -4376,7 +4375,7 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void { pub fn stringTableLookup(strtab: []const u8, off: u32) [:0]const u8 { const slice = strtab[off..]; - return slice[0..mem.indexOfScalar(u8, slice, 0).? :0]; + return slice[0..mem.findScalar(u8, slice, 0).? :0]; } pub fn pwriteAll(elf_file: *Elf, bytes: []const u8, offset: u64) error{AlreadyReported}!void { diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig index ae997c5b9bc16e806ca86d0889ff95df094dafdf..7be90fc558f72eaabeec930aa83f6e7f5e71b975 100644 --- a/src/link/Elf/Archive.zig +++ b/src/link/Elf/Archive.zig @@ -118,7 +118,7 @@ pub fn parse( pub fn stringTableLookup(strtab: []const u8, off: u32) [:'\n']const u8 { const slice = strtab[off..]; - return slice[0..mem.indexOfScalar(u8, slice, '\n').? :'\n']; + return slice[0..mem.findScalar(u8, slice, '\n').? :'\n']; } pub fn setArHdr(opts: struct { diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 9c0d1202776faa558015eec68b86fe3d3bbbe407..cd3378c8d69f457bb45e028def978067a219196d 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1299,7 +1299,7 @@ fn getNavShdrIndex( } if (nav_val.isUndef(zcu)) return switch (zcu.navFileScope(nav_index).mod.?.optimize_mode) { - .Debug, .ReleaseSafe => { + .debug, .safe => { if (self.data_index) |symbol_index| return self.symbol(symbol_index).outputShndx(elf_file).?; const osec = try elf_file.addSection(.{ @@ -1311,7 +1311,7 @@ fn getNavShdrIndex( self.data_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data"), osec); return osec; }, - .ReleaseFast, .ReleaseSmall => { + .fast, .small => { if (self.bss_index) |symbol_index| return self.symbol(symbol_index).outputShndx(elf_file).?; const osec = try elf_file.addSection(.{ @@ -1374,8 +1374,8 @@ fn updateNavCode( const target = &mod.resolved_target.result; const required_alignment = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { - .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), - .ReleaseSmall => target_util.minFunctionAlignment(target), + .debug, .safe, .fast => target_util.defaultFunctionAlignment(target), + .small => target_util.minFunctionAlignment(target), }.maxStrict(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)), else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), }; diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index a3ef197aba481bfb355d2d913efffbede87c55ae..b0085f18a404a767553ffbf99ccc63bea7672e2a 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -126,8 +126,14 @@ needed: std.array_hash_map.Auto(String(.dynstr), void), inputs: std.ArrayList(struct { path: std.Build.Cache.Path, member: ?[]const u8, - file_symbol: Symbol.LocalIndex, + extra: union { + /// Active for static libraries. + node: MappedFile.Node.Index, + /// Active otherwise. + file_symbol: Symbol.LocalIndex, + }, }), +input_pending_index: u32, input_sections: std.ArrayList(InputSection), input_section_pending_index: u32, navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct { @@ -181,7 +187,10 @@ input_prog_node: std.Progress.Node, const Error = link.Error || error{MappedFileIo}; const Node = union(enum) { - file, + archive, + /// This includes the archive magic and long file member. + archive_header, + elf, ehdr, shdr, segment: u32, @@ -189,6 +198,8 @@ const Node = union(enum) { /// /// The section '.dynamic' may contain relocations via `elf.dynamic_first_symbol_reloc`. section: Section.Index, + /// Only valid for static libraries, represents one non-zcu archive member. + input_member: InputIndex, /// May contain relocations. input_section: InputSection.Index, /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for @@ -219,19 +230,23 @@ const Node = union(enum) { return elf.inputs.items[@backingInt(ii)].member; } + pub fn node(ii: InputIndex, elf: *const Elf) MappedFile.Node.Index { + return elf.inputs.items[@backingInt(ii)].extra.node; + } + pub fn fileSymbol(ii: InputIndex, elf: *const Elf) Symbol.LocalIndex { - return elf.inputs.items[@backingInt(ii)].file_symbol; + return elf.inputs.items[@backingInt(ii)].extra.file_symbol; } pub fn localSymbolRange(ii: InputIndex, elf: *Elf) [2]Symbol.LocalIndex { if (@backingInt(ii) + 1 < elf.inputs.items.len) { - const next_ii: InputIndex = @fromBackingInt(@intCast(@backingInt(ii) + 1)); + const next_ii: InputIndex = @fromBackingInt(@backingInt(ii) + 1); return .{ ii.fileSymbol(elf), next_ii.fileSymbol(elf) }; } else { const local_symbols_len = switch (elf.shdrPtr(.symtab)) { inline else => |shdr| elf.targetLoad(&shdr.info), }; - return .{ ii.fileSymbol(elf), @fromBackingInt(@intCast(local_symbols_len)) }; + return .{ ii.fileSymbol(elf), @fromBackingInt(local_symbols_len) }; } } }; @@ -315,15 +330,16 @@ const Node = union(enum) { }; pub const Known = struct { - comptime file: MappedFile.Node.Index = .root, - comptime ehdr: MappedFile.Node.Index = @fromBackingInt(@intCast(1)), - comptime shdr: MappedFile.Node.Index = @fromBackingInt(@intCast(2)), - comptime rodata: MappedFile.Node.Index = @fromBackingInt(@intCast(3)), - comptime phdr: MappedFile.Node.Index = @fromBackingInt(@intCast(4)), - comptime text: MappedFile.Node.Index = @fromBackingInt(@intCast(5)), - comptime data: MappedFile.Node.Index = @fromBackingInt(@intCast(6)), - comptime data_rel_ro: MappedFile.Node.Index = @fromBackingInt(@intCast(7)), - + archive: MappedFile.Node.Index, + archive_header: MappedFile.Node.Index, + elf: MappedFile.Node.Index, + ehdr: MappedFile.Node.Index, + shdr: MappedFile.Node.Index, + rodata: MappedFile.Node.Index, + phdr: MappedFile.Node.Index, + text: MappedFile.Node.Index, + data: MappedFile.Node.Index, + data_rel_ro: MappedFile.Node.Index, tls: MappedFile.Node.Index, }; @@ -333,11 +349,11 @@ const Node = union(enum) { /// In this linker implementation, `link.File.AtomId` is a type-erased `MappedFile.Node.Index`. fn toAtom(ni: MappedFile.Node.Index) link.File.AtomId { - return @fromBackingInt(@intCast(@backingInt(ni))); + return @fromBackingInt(@backingInt(ni)); } /// In this linker implementation, `link.File.AtomId` is a type-erased `MappedFile.Node.Index`. fn fromAtom(atom: link.File.AtomId) MappedFile.Node.Index { - return @fromBackingInt(@intCast(@backingInt(atom))); + return @fromBackingInt(@backingInt(atom)); } }; @@ -424,13 +440,13 @@ const Section = struct { fn unwrap(opt: RelaIndex.Optional) ?RelaIndex { return switch (opt) { .none => null, - _ => @fromBackingInt(@intCast(@backingInt(opt))), + _ => @fromBackingInt(@backingInt(opt)), }; } }; fn toOptional(i: RelaIndex) RelaIndex.Optional { - return @fromBackingInt(@intCast(@backingInt(i))); + return @fromBackingInt(@backingInt(i)); } }; @@ -465,8 +481,8 @@ const Section = struct { pub fn fromSection(sec: std.elf.Section) Index { return switch (sec) { - std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @fromBackingInt(@intCast(sec)), - std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @fromBackingInt(@intCast(reserve(sec))), + std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @fromBackingInt(sec), + std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @fromBackingInt(reserve(sec)), }; } pub fn toSection(s: Index) ?std.elf.Section { @@ -485,7 +501,7 @@ const Section = struct { fn name(s: Index, elf: *Elf) String(.shstrtab) { return switch (elf.shdrPtr(s)) { - inline else => |shdr| @fromBackingInt(@intCast(elf.targetLoad(&shdr.name))), + inline else => |shdr| @fromBackingInt(elf.targetLoad(&shdr.name)), }; } @@ -928,21 +944,7 @@ const GotReloc = struct { } } fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { - const node_vaddr: u64 = switch (elf.getNode(reloc.node)) { - .file => unreachable, - .ehdr => unreachable, - .shdr => unreachable, - .segment => unreachable, - .copied_global => unreachable, - .section => |shndx| shndx.vaddr(elf), - .input_section => |isi| isi.ptrConst(elf).vaddr, - inline .nav, - .uav, - .lazy_code, - .lazy_const_data, - => |i| Symbol.Id.local(i.symbol(elf)).value(elf), - }; - const dest_vaddr = node_vaddr + reloc.offset; + const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset; const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..]; const got_vaddr = elf.shndx.got.vaddr(elf); @@ -1131,12 +1133,12 @@ pub const MachineRelocType = union { pub fn wrap(int: u32, elf: *const Elf) MachineRelocType { return switch (elf.ehdrMachine()) { - .AARCH64 => .{ .AARCH64 = @fromBackingInt(@intCast(int)) }, - .LOONGARCH => .{ .LARCH = @fromBackingInt(@intCast(int)) }, - .PPC64 => .{ .PPC64 = @fromBackingInt(@intCast(int)) }, - .RISCV => .{ .RISCV = @fromBackingInt(@intCast(int)) }, - .SPARCV9 => .{ .SPARC = @fromBackingInt(@intCast(int)) }, - .X86_64 => .{ .X86_64 = @fromBackingInt(@intCast(int)) }, + .AARCH64 => .{ .AARCH64 = @fromBackingInt(int) }, + .LOONGARCH => .{ .LARCH = @fromBackingInt(int) }, + .PPC64 => .{ .PPC64 = @fromBackingInt(int) }, + .RISCV => .{ .RISCV = @fromBackingInt(int) }, + .SPARCV9 => .{ .SPARC = @fromBackingInt(int) }, + .X86_64 => .{ .X86_64 = @fromBackingInt(int) }, }; } pub fn unwrap(rt: MachineRelocType, elf: *const Elf) u32 { @@ -1646,21 +1648,7 @@ const SymbolReloc = struct { } } fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { - const node_vaddr: u64 = switch (elf.getNode(reloc.node)) { - .file => unreachable, - .ehdr => unreachable, - .shdr => unreachable, - .segment => unreachable, - .copied_global => unreachable, - .section => |shndx| shndx.vaddr(elf), - .input_section => |isi| isi.ptrConst(elf).vaddr, - inline .nav, - .uav, - .lazy_code, - .lazy_const_data, - => |i| Symbol.Id.local(i.symbol(elf)).value(elf), - }; - const dest_vaddr = node_vaddr + reloc.offset; + const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset; const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..]; const addend: u64 = @bitCast(reloc.addend); @@ -1875,7 +1863,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L // `shdr.info` stores the index of the first global symbol. We will replace it with our // new local symbol, and move the global symbol to a new index at the end of the symtab. - const target_index: Symbol.Index = @fromBackingInt(@intCast(elf.targetLoad(&shdr.info))); + const target_index: Symbol.Index = @fromBackingInt(elf.targetLoad(&shdr.info)); const old_size = elf.targetLoad(&shdr.size); const new_size = old_size + ent_size; @@ -1897,7 +1885,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L // ...then the `elf.symtab` metadata... new_index.ptr(elf).* = target_index.ptr(elf).*; // ...then update the `elf.globals` tracking. - const global_name: String(.strtab) = @fromBackingInt(@intCast(elf.targetLoad(&new_sym.name))); + const global_name: String(.strtab) = @fromBackingInt(elf.targetLoad(&new_sym.name)); elf.globalByName(global_name).?.symtab_index = new_index; if (elf.ehdrType() == .REL and target_index.ptr(elf).first_target_reloc != .none) { @@ -1923,7 +1911,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym); } - return @fromBackingInt(@intCast(@backingInt(target_index))); + return @fromBackingInt(@backingInt(target_index)); }, } } @@ -2371,7 +2359,7 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { inline else => |shdr, class| { // `shdr.info` stores the index of the first global symbol. We are going to swap the // demoted symbol with that first global symbol, then increment that start index. - const dest_index: Symbol.Index = @fromBackingInt(@intCast(elf.targetLoad(&shdr.info))); + const dest_index: Symbol.Index = @fromBackingInt(elf.targetLoad(&shdr.info)); const src_index = global_ptr.symtab_index; // This global should currently be in the "global symbols" part of the symtab, since our @@ -2387,10 +2375,10 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { const src_sym_ptr = @field(elf.symPtr(src_index), @tagName(class)); const dest_sym_ptr = @field(elf.symPtr(dest_index), @tagName(class)); - const this_name: String(.strtab) = @fromBackingInt(@intCast(elf.targetLoad(&src_sym_ptr.name))); + const this_name: String(.strtab) = @fromBackingInt(elf.targetLoad(&src_sym_ptr.name)); assert(elf.globalByName(this_name).? == global_ptr); - const other_name: String(.strtab) = @fromBackingInt(@intCast(elf.targetLoad(&dest_sym_ptr.name))); + const other_name: String(.strtab) = @fromBackingInt(elf.targetLoad(&dest_sym_ptr.name)); const other_global_ptr = elf.globalByName(other_name).?; assert(other_global_ptr.symtab_index == dest_index); @@ -2426,7 +2414,7 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { const src_dynsym_ptr = @field(elf.dynsymPtr(remove_dynsym_index), @tagName(class)); const dest_dynsym_ptr = @field(elf.dynsymPtr(free_dynsym_index), @tagName(class)); - const moved_name_dynstr: String(.dynstr) = @fromBackingInt(@intCast(elf.targetLoad(&src_dynsym_ptr.name))); + const moved_name_dynstr: String(.dynstr) = @fromBackingInt(elf.targetLoad(&src_dynsym_ptr.name)); const moved_name = elf.stringExisting(.strtab, moved_name_dynstr.slice(elf)); const moved_global_ptr = elf.globalByName(moved_name).?; @@ -2505,7 +2493,7 @@ const Symbol = struct { _, fn index(li: LocalIndex) Index { - return @fromBackingInt(@intCast(@backingInt(li))); + return @fromBackingInt(@backingInt(li)); } }; @@ -2527,16 +2515,16 @@ const Symbol = struct { global: String(.strtab), } { return switch (s.kind) { - .local => .{ .local = @fromBackingInt(@intCast(s.raw)) }, - .global => .{ .global = @fromBackingInt(@intCast(s.raw)) }, + .local => .{ .local = @fromBackingInt(s.raw) }, + .global => .{ .global = @fromBackingInt(s.raw) }, }; } fn toTypeErased(s: Symbol.Id) link.File.SymbolId { - return @fromBackingInt(@intCast(@as(u32, @bitCast(s)))); + return @bitCast(s); } fn fromTypeErased(s: link.File.SymbolId) Symbol.Id { - return @bitCast(@backingInt(s)); + return @bitCast(s); } fn index(s: Symbol.Id, elf: *const Elf) Symbol.Index { @@ -2648,24 +2636,10 @@ const Symbol = struct { .yes_textrel => elf.textrel_count += 1, .yes => {}, } - const node_vaddr: u64 = switch (elf.getNode(reloc.node)) { - .file => unreachable, - .ehdr => unreachable, - .shdr => unreachable, - .segment => unreachable, - .copied_global => unreachable, - .section => |shndx| shndx.vaddr(elf), - .input_section => |isi| isi.ptrConst(elf).vaddr, - inline .nav, - .uav, - .lazy_code, - .lazy_const_data, - => |i| Symbol.Id.local(i.symbol(elf)).value(elf), - }; // There is capacity for a relocation because we just deleted one earlier. reloc.rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{ .type = .relative(elf), - .offset = node_vaddr + reloc.offset, + .offset = elf.getNodeVAddr(reloc.node) + reloc.offset, .raw_sym_index = 0, .addend = 0, }).toOptional(); @@ -2771,11 +2745,14 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum { pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) { - .file, + .archive, + .archive_header, + .elf, .ehdr, .shdr, .segment, .section, + .input_member, .input_section, .copied_global, => unreachable, @@ -3001,12 +2978,12 @@ fn String(section: StringSection) type { } fn string(elf: *Elf, comptime section: StringSection, key: []const u8) Error!String(section) { const st: *StringTable = &@field(elf, @tagName(section)); - return @fromBackingInt(@intCast(try st.get(elf, section.shndx(elf), key))); + return @fromBackingInt(try st.get(elf, section.shndx(elf), key)); } /// Like `string`, but asserts that the string is already in `section`. fn stringExisting(elf: *Elf, comptime section: StringSection, key: []const u8) String(section) { const st: *StringTable = &@field(elf, @tagName(section)); - return @fromBackingInt(@intCast(st.getExisting(elf, section.shndx(elf), key))); + return @fromBackingInt(st.getExisting(elf, section.shndx(elf), key)); } const StringTable = struct { @@ -3033,7 +3010,7 @@ const StringTable = struct { } pub fn hash(_: Adapter, key: []const u8) u64 { - assert(std.mem.indexOfScalar(u8, key, 0) == null); + assert(std.mem.findScalar(u8, key, 0) == null); return std.hash_map.hashString(key); } }; @@ -3172,6 +3149,16 @@ fn create( .options = options, .mf = try .init(file, comp.gpa, io), .ni = .{ + .archive = .root, + .archive_header = .none, + .elf = .root, + .ehdr = .none, + .shdr = .none, + .rodata = .none, + .phdr = .none, + .text = .none, + .data = .none, + .data_rel_ro = .none, .tls = .none, }, .nodes = .empty, @@ -3218,6 +3205,7 @@ fn create( .dynamic_first_symbol_reloc = .none, .needed = .empty, .inputs = .empty, + .input_pending_index = 0, .input_sections = .empty, .input_section_pending_index = 0, .navs = .empty, @@ -3293,6 +3281,7 @@ fn initHeaders( const comp = elf.base.comp; const gpa = comp.gpa; + const is_archive = comp.config.output_mode == .Lib and comp.config.link_mode == .static; const have_dynamic_section = switch (@"type") { .REL => false, .EXEC => comp.config.link_mode == .dynamic, @@ -3389,7 +3378,8 @@ fn initHeaders( }, phnum }; }; - const expected_nodes_len = 3 + // `.file`, `.ehdr`, and `.shdr` nodes + const expected_nodes_len = @as(usize, if (is_archive) 2 else 0) + // .archive, .archive_header + 3 + // `.file`, `.ehdr`, and `.shdr` nodes (shnum - 1) + // -1 because the null shdr does not have a `.section` node (phnum -| 1); // -1 because the GNU_STACK phdr does not have a `.segment` node @@ -3398,17 +3388,49 @@ fn initHeaders( try elf.section_by_name.ensureUnusedCapacity(gpa, shnum); try elf.phdrs.resize(gpa, phnum); try elf.symtab.ensureTotalCapacity(gpa, 1); - elf.nodes.appendAssumeCapacity(.file); + + if (is_archive) { + elf.nodes.appendAssumeCapacity(.archive); + elf.ni.archive_header = try elf.mf.addOnlyChildNode(gpa, elf.ni.archive, .{ + .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr) * 2, + .alignment = .@"2", + .fixed = true, + .next_moved = true, + .bubbles_moved = false, + .enable_next_moved = true, + }); + const archive_header_slice = elf.ni.archive_header.slice(&elf.mf); + @memcpy(archive_header_slice[0..std.elf.ARMAG.len], std.elf.ARMAG); + const strtab_ar_hdr: *std.elf.ar_hdr = @ptrCast(archive_header_slice[std.elf.ARMAG.len..]); + strtab_ar_hdr.* = .{ + .ar_name = std.elf.STRNAME.*, + .ar_date = @splat(' '), + .ar_uid = @splat(' '), + .ar_gid = @splat(' '), + .ar_mode = @splat(' '), + .ar_size = @splat(' '), + .ar_fmag = std.elf.ARFMAG.*, + }; + + elf.nodes.appendAssumeCapacity(.archive_header); + elf.ni.elf = try elf.mf.addLastChildNode(gpa, elf.ni.archive, .{ + .alignment = elf.mf.flags.block_size.max(.@"2"), + .next_moved = true, + .bubbles_moved = false, + .enable_next_moved = true, + }); + } + elf.nodes.appendAssumeCapacity(.elf); const entsize: struct { ph: u32, sh: u32 } = switch (class) { .NONE, _ => unreachable, inline else => |ct_class| entsize: { const ElfN = ct_class.ElfN(); - assert(elf.ni.ehdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.file, .{ + elf.ni.ehdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ .size = @sizeOf(ElfN.Ehdr), .alignment = addr_align, .fixed = true, - })); + }); elf.nodes.appendAssumeCapacity(.ehdr); const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf))); @@ -3461,12 +3483,12 @@ fn initHeaders( }, }; - assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ + elf.ni.shdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ .size = 1 * entsize.sh, // as above, only the null shdr initially .alignment = elf.mf.flags.block_size, .moved = true, .resized = true, - })); + }); elf.nodes.appendAssumeCapacity(.shdr); const page_align: std.mem.Alignment = .fromByteUnits(switch (machine) { @@ -3491,45 +3513,45 @@ fn initHeaders( }); var ph_vaddr: u32 = if (@"type" != .REL) ph_vaddr: { - assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ + elf.ni.rodata = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ .alignment = elf.mf.flags.block_size, .moved = true, .bubbles_moved = false, - })); + }); elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata }); elf.phdrs.items[phndx.rodata] = elf.ni.rodata; - assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ + elf.ni.phdr = try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ .size = @as(u64, phnum) * entsize.ph, .alignment = addr_align, .moved = true, .resized = true, .bubbles_moved = false, - })); + }); elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr }); elf.phdrs.items[phndx.phdr] = elf.ni.phdr; - assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ + elf.ni.text = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ .alignment = elf.mf.flags.block_size, .moved = true, .bubbles_moved = false, - })); + }); elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text }); elf.phdrs.items[phndx.text] = elf.ni.text; - assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ + elf.ni.data = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ .alignment = elf.mf.flags.block_size, .moved = true, .bubbles_moved = false, - })); + }); elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data }); elf.phdrs.items[phndx.data] = elf.ni.data; - assert(elf.ni.data_rel_ro == try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{ + elf.ni.data_rel_ro = try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{ .alignment = elf.mf.flags.block_size, .moved = true, .bubbles_moved = false, - })); + }); elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro }); elf.phdrs.items[phndx.relro] = elf.ni.data_rel_ro; @@ -3706,7 +3728,7 @@ fn initHeaders( .node = .none, .first_target_reloc = .none, }; - assert(.symtab == try elf.addSection(elf.ni.file, .{ + assert(.symtab == try elf.addSection(elf.ni.elf, .{ .type = .SYMTAB, .size = @sizeOf(ElfN.Sym) * 1, .addralign = addr_align, @@ -3729,7 +3751,7 @@ fn initHeaders( ehdr.shstrndx = ehdr.shnum; }, } - assert(.shstrtab == try elf.addSection(elf.ni.file, .{ + assert(.shstrtab == try elf.addSection(elf.ni.elf, .{ .type = .STRTAB, .size = 1, .entsize = 1, @@ -3740,7 +3762,7 @@ fn initHeaders( try Section.Index.symtab.rename(elf, ".symtab"); try Section.Index.shstrtab.rename(elf, ".shstrtab"); - assert(.strtab == try elf.addSection(elf.ni.file, .{ + assert(.strtab == try elf.addSection(elf.ni.elf, .{ .name = ".strtab", .type = .STRTAB, .size = 1, @@ -4210,6 +4232,8 @@ fn initHeaders( break :str try elf.string(.dynstr, slice); }, }; + + try elf.ensureElfNodeSize(); } pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { @@ -4221,10 +4245,8 @@ pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { break :count count; }); elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len); - elf.input_prog_node = prog_node.start( - "Inputs", - elf.input_sections.items.len - elf.input_section_pending_index, - ); + elf.input_prog_node = prog_node.start("Inputs", (elf.inputs.items.len - elf.input_pending_index) + + (elf.input_sections.items.len - elf.input_section_pending_index)); } pub fn endProgress(elf: *Elf) void { @@ -4244,13 +4266,15 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { /// Asserts that `ni` is a section, input section, copied global, NAV, UAV, or lazy code/data. fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { return switch (elf.getNode(ni)) { - .file => unreachable, - .ehdr => unreachable, - .shdr => unreachable, - .segment => unreachable, - + .archive, + .archive_header, + .elf, + .ehdr, + .shdr, + .segment, + .input_member, + => unreachable, .section => |shndx| shndx, - .input_section, .copied_global, .nav, @@ -4260,21 +4284,44 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { => elf.getNode(ni.parent(&elf.mf)).section, }; } +fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { + return switch (elf.getNode(ni)) { + .archive, + .archive_header, + .elf, + .ehdr, + .shdr, + .segment, + .input_member, + .copied_global, + => unreachable, + .section => |shndx| shndx.vaddr(elf), + .input_section => |isi| isi.ptrConst(elf).vaddr, + inline .nav, + .uav, + .lazy_code, + .lazy_const_data, + => |i| Symbol.Id.local(i.symbol(elf)).value(elf), + }; +} fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf))) { - .file => return 0, + .archive, .archive_header => unreachable, + .elf => return 0, .ehdr, .shdr => unreachable, .segment => |phndx| switch (elf.phdrSlice()) { inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr), }, .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf), - .input_section => unreachable, - .copied_global => unreachable, + .input_member, .input_section, .copied_global => unreachable, inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf), }; const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); return parent_vaddr + offset; } +fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 { + return ni.fileLocation(&elf.mf, false).offset - elf.ni.elf.fileLocation(&elf.mf, false).offset; +} /// Deletes any existing relocations in the given node, and marks the start of the node's contiguous /// sequence of relocations, so that the caller may append the node's updated relocations. @@ -4283,12 +4330,16 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { /// the special-case sections '.plt' and '.dynamic'. fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { const symbol_relocs: *SymbolReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) { - .file => unreachable, // cannot contain relocs - .ehdr => unreachable, // cannot contain relocs - .shdr => unreachable, // cannot contain relocs - .segment => unreachable, // cannot contain relocs + .archive, + .archive_header, + .elf, + .ehdr, + .shdr, + .segment, + .input_member, + .copied_global, + => unreachable, // cannot contain relocs .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported) - .copied_global => unreachable, // cannot contain relocs .input_section => |isi| .{ &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc, &elf.input_sections.items[@backingInt(isi)].first_got_reloc, @@ -4359,7 +4410,7 @@ fn flushMovedNodeRelocs( } fn identClass(elf: *const Elf) std.elf.CLASS { - return @fromBackingInt(@intCast(elf.mf.memory_map.memory[std.elf.EI.CLASS])); + return @fromBackingInt(elf.ni.elf.sliceConst(&elf.mf)[std.elf.EI.CLASS]); } /// Like `std.elf.ET`, but only includes the ELF machine architectures we support, so that we can @@ -4415,7 +4466,7 @@ fn targetPtrSize(elf: *const Elf) u8 { return elf.identClass().size(); } fn targetEndian(elf: *const Elf) std.lang.Endian { - const ident_data: std.elf.DATA = @fromBackingInt(@intCast(elf.mf.memory_map.memory[std.elf.EI.DATA])); + const ident_data: std.elf.DATA = @fromBackingInt(elf.ni.elf.sliceConst(&elf.mf)[std.elf.EI.DATA]); return ident_data.endian(); } fn targetTlsVariant(elf: *const Elf) union(enum) { @@ -4487,7 +4538,7 @@ fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.chi return switch (@typeInfo(Child)) { else => @compileError(@typeName(Child)), .int => std.mem.toNative(Child, ptr.*, elf.targetEndian()), - .@"enum" => |@"enum"| @fromBackingInt(@intCast(elf.targetLoad(@as(*align(alignment) const @"enum".tag_type, @ptrCast(ptr))))), + .@"enum" => |@"enum"| @fromBackingInt(elf.targetLoad(@as(*align(alignment) const @"enum".tag_type, @ptrCast(ptr)))), .@"struct" => |@"struct"| @bitCast( elf.targetLoad(@as(*align(alignment) @"struct".backing_integer.?, @ptrCast(ptr))), ), @@ -4563,6 +4614,16 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr { } } +fn arHdrPtr(elf: *Elf, ni: MappedFile.Node.Index) *align(2) std.elf.ar_hdr { + assert(elf.ni.elf != MappedFile.Node.Index.root); + const file_offset = ni.fileLocation(&elf.mf, false).offset; + return @ptrCast(@alignCast(elf.mf.memory_map.memory[@intCast(switch (elf.getNode(ni)) { + else => unreachable, + .archive_header => file_offset + std.elf.ARMAG.len, + .elf, .input_member => file_offset - @sizeOf(std.elf.ar_hdr), + })..][0..@sizeOf(std.elf.ar_hdr)])); +} + const SymPtr = union(std.elf.CLASS) { NONE: noreturn, @"32": *std.elf.Elf32.Sym, @@ -4657,7 +4718,7 @@ fn mapInputSection(elf: *Elf, opts: struct { } errdefer assert(elf.section_by_name.pop().?.key == name_shstrtab); const parent_node: MappedFile.Node.Index = parent: { - if (!opts.flags.ALLOC) break :parent elf.ni.file; + if (!opts.flags.ALLOC) break :parent elf.ni.elf; if (opts.flags.EXECINSTR) break :parent elf.ni.text; if (opts.flags.TLS) break :parent elf.ni.tls; if (opts.flags.WRITE) break :parent elf.ni.data; @@ -4782,11 +4843,11 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node break :a switch (nav.resolved.?.@"align") { else => |a| a.maxStrict(min), .none => switch (mod.optimize_mode) { - .Debug, - .ReleaseSafe, - .ReleaseFast, + .debug, + .safe, + .fast, => target_util.defaultFunctionAlignment(target), - .ReleaseSmall => min, + .small => min, }.maxStrict(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)), }; }, @@ -4878,7 +4939,7 @@ const LoadParseInputError = Error || Io.File.SeekError || Io.Reader.Error; /// indicates to the frontend that the input could be a GNU ld script instead. pub fn loadInput(elf: *Elf, input: link.Input) (link.Error || error{BadMagic})!void { const diags = &elf.base.comp.link_diags; - return elf.loadInputInner(input) catch |err| switch (err) { + elf.loadInputInner(input) catch |err| switch (err) { else => |e| return e, error.MappedFileIo => return diags.fail( "failed to write output file: {t}", @@ -4986,6 +5047,9 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load const r = &fr.interface; log.debug("loadArchive({f})", .{path.fmtEscapeString()}); + + if (elf.ehdrType() == .REL) return; // this input does not affect the output artifact + { const magic = r.take(std.elf.ARMAG.len) catch |err| switch (err) { error.ReadFailed => |e| return e, @@ -5071,21 +5135,40 @@ fn loadObject( .{}, ), }; + + const input = try elf.inputs.addOne(gpa); + input.* = .{ + .path = path, + .member = if (member) |m| try gpa.dupe(u8, m) else null, + .extra = undefined, + }; + if (elf.ni.elf != MappedFile.Node.Index.root) { + try elf.nodes.ensureUnusedCapacity(gpa, 1); + input.extra = .{ .node = try elf.mf.addLastChildNode(gpa, .root, .{ + .size = fl.size + @sizeOf(std.elf.ar_hdr), + .alignment = .@"2", + .next_moved = true, + .bubbles_moved = false, + .enable_next_moved = true, + }) }; + elf.nodes.appendAssumeCapacity(.{ .input_member = input_index }); + elf.input_prog_node.increaseEstimatedTotalItems(1); + + // Since we are not emitting the archive symbol table (yet?) we do not need to parse + // the symbols in this input. + return; + } + + elf.input_pending_index += 1; try elf.ensureUnusedSymbolCapacity(1, .all_local); - try elf.inputs.ensureUnusedCapacity(gpa, 1); - const file_symbol = elf.addLocalSymbolAssumeCapacity(.{ + input.extra = .{ .file_symbol = elf.addLocalSymbolAssumeCapacity(.{ .node = .none, .name = try elf.string(.strtab, std.fs.path.stem(member orelse path.sub_path)), .value = 0, .size = 0, .type = .FILE, .shndx = .ABS, - }); - elf.inputs.addOneAssumeCapacity().* = .{ - .path = path, - .member = if (member) |m| try gpa.dupe(u8, m) else null, - .file_symbol = file_symbol, - }; + }) }; const target_endian = elf.targetEndian(); switch (elf.identClass()) { .NONE, _ => unreachable, @@ -5267,7 +5350,7 @@ fn loadObject( .first_symbol_reloc = .none, .first_got_reloc = .none, }; - elf.synth_prog_node.increaseEstimatedTotalItems(1); + elf.input_prog_node.increaseEstimatedTotalItems(1); } var symmap: std.ArrayList(Symbol.Id) = .empty; defer symmap.deinit(gpa); @@ -5479,6 +5562,9 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars log.debug("loadDso({f})", .{path.fmtEscapeString()}); try elf.checkInputIdent(path, r); + + if (elf.ehdrType() == .REL) return; // this input does not affect the output artifact + const target_endian = elf.targetEndian(); switch (elf.identClass()) { .NONE, _ => unreachable, @@ -5709,7 +5795,8 @@ fn checkInputIdent( } const ident = try r.peekStructPointer(std.elf.Ident); - const target: *const std.elf.Ident = @ptrCast(elf.mf.memory_map.memory[0..@sizeOf(std.elf.Ident)]); + const target: *const std.elf.Ident = + @ptrCast(elf.ni.elf.sliceConst(&elf.mf)[0..@sizeOf(std.elf.Ident)]); if (ident.class != target.class) return diags.failParse( path, @@ -5812,7 +5899,9 @@ fn updateInitFiniArraySectionSize( } pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) link.Error!void { - _ = prog_node; + const sub_prog_node = prog_node.start("ELF Prelink", 0); + defer sub_prog_node.end(); + const diags = &elf.base.comp.link_diags; elf.prelinkInner() catch |err| switch (err) { error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), @@ -5823,13 +5912,11 @@ fn prelinkInner(elf: *Elf) Error!void { const comp = elf.base.comp; const gpa = comp.gpa; - if (comp.zcu != null and !comp.config.use_llvm) { - // We're use self-hosted codegen---add an input representing the Zig "object". + if (comp.zcu != null and !comp.config.use_llvm and elf.ni.elf == MappedFile.Node.Index.root) { + // We're using self-hosted codegen---add an input representing the Zig "object". try elf.ensureUnusedSymbolCapacity(1, .all_local); try elf.inputs.ensureUnusedCapacity(gpa, 1); - const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{ - std.fs.path.stem(elf.base.emit.sub_path), - }); + const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{comp.root_name}); defer gpa.free(zcu_name); const zcu_file_symbol = elf.addLocalSymbolAssumeCapacity(.{ .node = .none, @@ -5842,9 +5929,12 @@ fn prelinkInner(elf: *Elf) Error!void { elf.inputs.addOneAssumeCapacity().* = .{ .path = elf.base.emit, .member = null, - .file_symbol = zcu_file_symbol, + .extra = .{ .file_symbol = zcu_file_symbol }, }; + elf.input_pending_index += 1; } + + try elf.ensureElfNodeSize(); } fn prepareDynamic(elf: *Elf) Error!void { @@ -6034,12 +6124,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { }, }; assert(shndx < @backingInt(Section.Index.LORESERVE)); - break :shndx .{ @fromBackingInt(@intCast(shndx)), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) }; + break :shndx .{ @fromBackingInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) }; }, }; try elf.ensureNodeSize(elf.ni.shdr, new_shdr_size); const ni = try elf.mf.addLastChildNode(gpa, switch (elf.ehdrType()) { - .REL => elf.ni.file, + .REL => elf.ni.elf, .EXEC, .DYN => segment_ni, }, .{ .size = opts.size, @@ -6062,7 +6152,6 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { else => .{ .shndx = .UNDEF }, } }); elf.nodes.appendAssumeCapacity(.{ .section = shndx }); - const offset = ni.fileLocation(&elf.mf, false).offset; switch (elf.shdrPtr(shndx)) { inline else => |shdr, class| { shdr.* = .{ @@ -6070,7 +6159,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { .type = opts.type, .flags = .{ .shf = opts.flags }, .addr = @intCast(addr), - .offset = @intCast(offset), + .offset = @intCast(elf.getNodeElfOffset(ni)), .size = @intCast(opts.size), .link = opts.link, .info = opts.info, @@ -6504,20 +6593,7 @@ fn addSymbolRelocAssumeCapacity( // If we emit a runtime relocation entry, its `offset` is a virtual address, so we need to // determine the vaddr of `node`. - const node_vaddr: u64 = switch (elf.getNode(node)) { - .file => unreachable, - .ehdr => unreachable, - .shdr => unreachable, - .segment => unreachable, - .copied_global => unreachable, - .section => |shndx| shndx.vaddr(elf), - .input_section => |isi| isi.ptrConst(elf).vaddr, - inline .nav, - .uav, - .lazy_code, - .lazy_const_data, - => |i| Symbol.Id.local(i.symbol(elf)).value(elf), - }; + const node_vaddr = elf.getNodeVAddr(node); // If this is `true`, we will try to create a copy relocation for the target symbol if it is // not locally defined. If the relocation value is always computed from the target symbol's @@ -6656,20 +6732,23 @@ fn addGotRelocAssumeCapacity( ) void { assert(elf.ehdrType() != .REL); switch (elf.getNode(node)) { + .archive, + .archive_header, + .elf, + .ehdr, + .shdr, + .segment, + .input_member, + .copied_global, + => unreachable, // cannot contain relocs, + .section, + .uav, + => unreachable, // cannot contain GOT relocs .input_section, .nav, .lazy_code, .lazy_const_data, => {}, - - .section => unreachable, // cannot contain GOT relocs - .uav => unreachable, // cannot contain GOT relocs - - .file => unreachable, // cannot contain relocs - .ehdr => unreachable, // cannot contain relocs - .shdr => unreachable, // cannot contain relocs - .segment => unreachable, // cannot contain relocs - .copied_global => unreachable, // cannot contain relocs } const gop = elf.got.getOrPutAssumeCapacity(target); @@ -7053,11 +7132,24 @@ pub fn flush( tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, ) link.Error!void { + elf.flushInner(arena, tid, prog_node) catch |err| switch (err) { + error.MappedFileIo => return elf.base.comp.link_diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), + else => |e| return e, + }; +} +fn flushInner( + elf: *Elf, + arena: std.mem.Allocator, + tid: Zcu.PerThread.Id, + prog_node: std.Progress.Node, +) Error!void { const comp = elf.base.comp; const diags = &comp.link_diags; - _ = prog_node; _ = arena; + const sub_prog_node = prog_node.start("ELF Flush", 0); + defer sub_prog_node.end(); + if (comp.config.output_mode == .Exe) { var any_undef = false; for (elf.globals.strong_undef.keys()) |name| { @@ -7068,11 +7160,9 @@ pub fn flush( if (any_undef) return error.AlreadyReported; } - elf.prepareDynamic() catch |err| switch (err) { - error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), - else => |e| return e, - }; + try elf.prepareDynamic(); + try elf.ensureElfNodeSize(); while (try elf.idle(tid)) {} // We've done the final `idle` loop, so everything is at its final place in the file. We have a @@ -7097,10 +7187,7 @@ pub fn flush( .enabled => "_start", .named => |named| named, }; - const sym_name_strtab = elf.string(.strtab, sym_name_slice) catch |err| switch (err) { - error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), - else => |e| return e, - }; + const sym_name_strtab = try elf.string(.strtab, sym_name_slice); if (elf.globalByName(sym_name_strtab) == null) break :entry 0; break :entry Symbol.Id.global(sym_name_strtab).value(elf); }; @@ -7108,10 +7195,11 @@ pub fn flush( inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(entry_addr)), } - elf.mf.flush() catch |err| switch (err) { - error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), - else => |e| return e, - }; + try elf.mf.flush(); + + if (elf.options.enable_link_snapshots) + elf.dumpStderr(tid) catch |err| + return comp.link_diags.fail("dumping link snapshot failed: {t}", .{err}); } pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { @@ -7124,8 +7212,19 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { } task: { + if (elf.input_pending_index < elf.inputs.items.len) { + const ii: Node.InputIndex = @fromBackingInt(elf.input_pending_index); + elf.input_pending_index += 1; + const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(ii.node(elf))); + defer sub_prog_node.end(); + elf.flushInput(ii) catch |err| switch (err) { + error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), + else => |e| return e, + }; + break :task; + } if (elf.input_section_pending_index < elf.input_sections.items.len) { - const isi: InputSection.Index = @fromBackingInt(@intCast(elf.input_section_pending_index)); + const isi: InputSection.Index = @fromBackingInt(elf.input_section_pending_index); elf.input_section_pending_index += 1; const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf))); defer sub_prog_node.end(); @@ -7213,11 +7312,13 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { while (elf.mf.updates.pop()) |ni| { const clean_moved = ni.cleanMoved(&elf.mf); const clean_resized = ni.cleanResized(&elf.mf); - if (clean_moved or clean_resized) { + const clean_next_moved = ni.cleanNextMoved(&elf.mf); + if (clean_moved or clean_resized or clean_next_moved) { const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni)); defer sub_prog_node.end(); if (clean_moved) try elf.flushMoved(ni); if (clean_resized) try elf.flushResized(ni); + if (clean_next_moved) try elf.flushNextMoved(ni); break :task; } else elf.mf.update_prog_node.completeOne(); } @@ -7238,6 +7339,10 @@ fn idleProgNode( return prog_node.start(name: switch (node) { else => |tag| @tagName(tag), .section => |shndx| shndx.name(elf).slice(elf), + .input_member => |ii| std.fmt.bufPrint(&name, "{f}{f}", .{ + ii.path(elf).fmtEscapeString(), + fmtMemberString(ii.member(elf)), + }) catch &name, .input_section => |isi| { const ii = isi.input(elf); break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{ @@ -7290,6 +7395,8 @@ fn genPending(elf: *Elf, pt: Zcu.PerThread) Error!void { }; break; } + + try elf.ensureElfNodeSize(); } fn genUav( @@ -7358,6 +7465,36 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void { } } +fn flushInput(elf: *Elf, ii: Node.InputIndex) Error!void { + const comp = elf.base.comp; + const io = comp.io; + const gpa = comp.gpa; + const diags = &comp.link_diags; + const path = ii.path(elf); + const file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| return diags.fail("failed to open input file \"{f}\": {t}", .{ path.fmtEscapeString(), e }), + }; + defer file.close(io); + var fr = file.reader(io, &.{}); + var nw: MappedFile.Node.Writer = undefined; + ii.node(elf).writer(&elf.mf, gpa, &nw); + defer nw.deinit(); + const size = nw.interface.buffer.len - @sizeOf(std.elf.ar_hdr); + const n_bytes = nw.interface.sendFileAll(&fr, .limited(size)) catch |err| switch (err) { + error.ReadFailed => return diags.fail("failed to read input \"{f}{f}\": {t}", .{ + path.fmtEscapeString(), + fmtMemberString(ii.member(elf)), + fr.err orelse (fr.seek_err orelse fr.size_err.?), + }), + error.WriteFailed => return nw.err.?, + }; + if (n_bytes + 1 < size) return diags.fail("failed to read input \"{f}{f}\": unexpected eof", .{ + path.fmtEscapeString(), + fmtMemberString(ii.member(elf)), + }); +} + fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void { const file_loc = isi.fileLocation(elf); if (file_loc.size == 0) return; @@ -7404,33 +7541,29 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void { assert(isi.node(elf).hasMoved(&elf.mf)); } -fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) void { +fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void { + const elf_offset = elf.getNodeElfOffset(ni); switch (elf.getNode(ni)) { else => unreachable, - .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0), + .ehdr => assert(elf_offset == 0), .shdr => switch (elf.ehdrPtr()) { - inline else => |ehdr| elf.targetStore( - &ehdr.shoff, - @intCast(ni.fileLocation(&elf.mf, false).offset), - ), + inline else => |ehdr| elf.targetStore(&ehdr.shoff, @intCast(elf_offset)), }, .segment => |phndx| { switch (elf.phdrSlice()) { inline else => |phdr, class| { const ph = &phdr[phndx]; - elf.targetStore(&ph.offset, @intCast(ni.fileLocation(&elf.mf, false).offset)); + elf.targetStore(&ph.offset, @intCast(elf_offset)); if (elf.targetLoad(&ph.type) == .PHDR) { @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset; } }, } var child_it = ni.children(&elf.mf); - while (child_it.next()) |child_ni| elf.flushFileOffset(child_ni); + while (child_it.next()) |child_ni| elf.flushElfOffset(child_ni); }, .section => |shndx| switch (elf.shdrPtr(shndx)) { - inline else => |shdr| elf.targetStore(&shdr.offset, @intCast( - ni.fileLocation(&elf.mf, false).offset, - )), + inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)), }, } } @@ -7443,10 +7576,11 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void defer elf.mf.nodes_lock.unlock(); switch (elf.getNode(ni)) { - .file => unreachable, - .ehdr, .shdr => elf.flushFileOffset(ni), + .archive, .archive_header => unreachable, + .elf => {}, + .ehdr, .shdr => elf.flushElfOffset(ni), .segment => |phndx| { - elf.flushFileOffset(ni); + elf.flushElfOffset(ni); switch (elf.phdrSlice()) { inline else => |phdr| { const ph = &phdr[phndx]; @@ -7467,7 +7601,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void } }, .section => |shndx| { - elf.flushFileOffset(ni); + elf.flushElfOffset(ni); const addr = elf.computeNodeVAddr(ni); const old_addr: u64, const flags: std.elf.SHF = switch (elf.shdrPtr(shndx)) { inline else => |shdr| .{ @@ -7518,6 +7652,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void elf.flushMovedNodeRelocs(ni, addr, elf.dynamic_first_symbol_reloc, .none); } }, + .input_member => {}, .input_section => |isi| { const old_section_addr = isi.ptr(elf).vaddr; const new_section_addr = elf.computeNodeVAddr(ni); @@ -7526,7 +7661,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void // Update local symbols const ii = isi.input(elf); var lsi, const end_lsi = ii.localSymbolRange(elf); - while (lsi != end_lsi) : (lsi = @fromBackingInt(@intCast(@backingInt(lsi) + 1))) { + while (lsi != end_lsi) : (lsi = @fromBackingInt(@backingInt(lsi) + 1)) { if (lsi.index().ptr(elf).node != ni) continue; const visibility: std.elf.STV = switch (elf.symPtr(lsi.index())) { inline else => |sym| elf.targetLoad(&sym.other).visibility, @@ -7613,7 +7748,17 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo _, const size = ni.location(&elf.mf).resolve(&elf.mf); switch (elf.getNode(ni)) { - .file => {}, + .archive => { + var child_it = ni.reverseChildren(&elf.mf); + if (child_it.next()) |last_ni| { + if (child_it.next()) |prev_ni| if (prev_ni.hasNextMoved(&elf.mf)) return; + const offset, _ = last_ni.location(&elf.mf).resolve(&elf.mf); + _ = std.mem.print(&elf.arHdrPtr(last_ni).ar_size, "{d:<10}", .{ + size - offset, + }) catch @panic("archive member too large"); + } + }, + .archive_header, .elf => {}, .ehdr => unreachable, .shdr => {}, .segment => |phndx| switch (elf.phdrSlice()) { @@ -7713,9 +7858,88 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo } }, }, - .copied_global, .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {}, + .input_member, .input_section, .copied_global, .nav, .uav, .lazy_code, .lazy_const_data => {}, } } + +fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { + const trace = tracy.trace(@src()); + defer trace.end(); + + elf.mf.nodes_lock.lock(); + defer elf.mf.nodes_lock.unlock(); + + switch (elf.getNode(ni)) { + .archive, + .ehdr, + .shdr, + .segment, + .section, + .input_section, + .copied_global, + .nav, + .uav, + .lazy_code, + .lazy_const_data, + => unreachable, + .archive_header, .elf, .input_member => |_, tag| { + const member_offset, const update_size = member_offset: { + const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); + break :member_offset switch (tag) { + else => unreachable, + .archive_header => .{ offset + std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr), true }, + .elf, .input_member => .{ offset, switch (ni.prev(&elf.mf)) { + .none => unreachable, + else => |prev_ni| !prev_ni.hasNextMoved(&elf.mf), + } }, + }; + }; + const member_size = member_end: switch (ni.next(&elf.mf)) { + else => |next_ni| { + const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf); + const next_member_size = next_member_end: switch (next_ni.next(&elf.mf)) { + else => |next_next_ni| { + const next_next_offset, _ = next_next_ni.location(&elf.mf).resolve(&elf.mf); + break :next_member_end next_next_offset - @sizeOf(std.elf.ar_hdr); + }, + .none => { + _, const parent_size = + ni.parent(&elf.mf).location(&elf.mf).resolve(&elf.mf); + break :next_member_end parent_size; + }, + } - next_offset; + const ar_hdr = elf.arHdrPtr(next_ni); + var name_buf: [16]u8 = undefined; + _ = std.mem.print(&ar_hdr.ar_name, "{s:<16}", .{ + switch (elf.getNode(next_ni)) { + else => unreachable, + .elf => std.mem.print(&name_buf, "{s}_zcu.o/", .{elf.base.comp.root_name}), + .input_member => |ii| std.mem.print(&name_buf, "{s}/", .{ + std.fs.path.basename(ii.path(elf).sub_path), + }), + } catch @panic("TODO: long archive member names"), + }) catch @panic("TODO: long archive member names"); + ar_hdr.ar_date = "0 ".*; + ar_hdr.ar_uid = "0 ".*; + ar_hdr.ar_gid = "0 ".*; + ar_hdr.ar_mode = "644 ".*; + _ = std.mem.print(&ar_hdr.ar_size, "{d:<10}", .{next_member_size}) catch + @panic("archive member too large"); + ar_hdr.ar_fmag = std.elf.ARFMAG.*; + break :member_end next_offset - @sizeOf(std.elf.ar_hdr); + }, + .none => { + _, const parent_size = ni.parent(&elf.mf).location(&elf.mf).resolve(&elf.mf); + break :member_end parent_size; + }, + } - member_offset; + if (update_size) _ = std.mem.print(&elf.arHdrPtr(ni).ar_size, "{d:<10}", .{ + member_size, + }) catch @panic("archive member too large"); + }, + } +} + fn updateDynamicEntry(elf: *Elf, key: u32, new_val: u64) void { switch (elf.shdrPtr(elf.shndx.dynamic)) { inline else => |shdr, class| { @@ -7756,7 +7980,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void }; // Now that we know the index, we can set the relocation's offset. - elf.shndx.rela_plt.relaSetOffset(elf, @fromBackingInt(@intCast(plt_index)), got_plt_section.vaddr(elf) + got_plt_offset); + elf.shndx.rela_plt.relaSetOffset(elf, @fromBackingInt(plt_index), got_plt_section.vaddr(elf) + got_plt_offset); if (plt_index < elf.plt.count()) { // We reused a free entry, so we're already done! @@ -8096,7 +8320,10 @@ fn updateExportsInner( }, .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT }, }; + + try elf.ensureElfNodeSize(); while (try elf.idle(pt.tid)) {} + const value: u64 = Symbol.Id.local(exported_lsi).value(elf); const size: u64, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) { inline else => |exported_sym| .{ @@ -8150,6 +8377,16 @@ pub fn deleteExport(elf: *Elf, exported: Zcu.Exported, name: InternPool.NullTerm _ = name; } +fn dumpStderr(elf: *Elf, tid: Zcu.PerThread.Id) !void { + const comp = elf.base.comp; + const io = comp.io; + var buffer: [512]u8 = undefined; + const stderr = try io.lockStderr(&buffer, null); + defer io.unlockStderr(); + const w = &stderr.file_writer.interface; + _ = try elf.dump(w, tid); +} + pub fn dump(elf: *Elf, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpResult { if (elf.options.enable_link_snapshots) { try elf.printNode(tid, w, .root, 0); @@ -8227,13 +8464,14 @@ pub fn printNode( { const mf_node = &elf.mf.nodes.items[@backingInt(ni)]; const off, const size = mf_node.location().resolve(&elf.mf); - try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ + try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}{s}\n", .{ @backingInt(ni), off, size, mf_node.flags.alignment.toByteUnits(), if (mf_node.flags.fixed) " fixed" else "", if (mf_node.flags.moved) " moved" else "", + if (mf_node.flags.next_moved) " next_moved" else "", if (mf_node.flags.resized) " resized" else "", if (mf_node.flags.has_content) " has_content" else "", }); @@ -8269,11 +8507,19 @@ pub fn printNode( } } -fn ensureNodeSize( - elf: *Elf, - node: MappedFile.Node.Index, - need_size: u64, -) Error!void { +/// Must be called deterministically after any call to `MappedFile.Node.Index.resize` +/// (of `elf.ni.elf` or one of its children) before any possible calls to `idle`. +fn ensureElfNodeSize(elf: *Elf) MappedFile.Error!void { + if (elf.ni.elf == MappedFile.Node.Index.root) return; + var child_it = elf.ni.elf.reverseChildren(&elf.mf); + const last_end = if (child_it.next()) |last_ni| last_end: { + const last_offset, const last_size = last_ni.location(&elf.mf).resolve(&elf.mf); + break :last_end last_offset + last_size; + } else 0; + try elf.ensureNodeSize(elf.ni.elf, last_end + @sizeOf(std.elf.ar_hdr)); +} + +fn ensureNodeSize(elf: *Elf, node: MappedFile.Node.Index, need_size: u64) MappedFile.Error!void { _, const node_size = node.location(&elf.mf).resolve(&elf.mf); if (need_size <= node_size) return; const gpa = elf.base.comp.gpa; diff --git a/src/link/Lld.zig b/src/link/Lld.zig index 715c0ba69f0c8f50ad6306ad7519c173a4d3dc0e..894e21785c1ff5c5a969a12acff6538c8a752e12 100644 --- a/src/link/Lld.zig +++ b/src/link/Lld.zig @@ -99,8 +99,6 @@ pub const Elf = struct { bind_global_refs_locally: bool, pub const HashStyle = enum { sysv, gnu, both }; pub const SortSection = enum { name, alignment }; - /// Deprecated; use 'std.zig.CompressDebugSections' instead. To be removed after 0.16.0 is tagged. - pub const CompressDebugSections = std.zig.CompressDebugSections; fn init(comp: *Compilation, options: link.File.OpenOptions) !Elf { const PtrWidth = enum { p32, p64 }; @@ -208,8 +206,8 @@ pub fn createEmpty( const optimize_mode = comp.root_mod.optimize_mode; const gc_sections: bool = options.gc_sections orelse switch (target.ofmt) { - .coff => optimize_mode != .Debug, - .elf => optimize_mode != .Debug and output_mode != .Obj, + .coff => optimize_mode != .debug, + .elf => optimize_mode != .debug and output_mode != .Obj, .wasm => output_mode != .Obj, else => unreachable, }; @@ -271,12 +269,12 @@ pub fn flush( .wasm => wasmLink(lld, arena), }; result catch |err| switch (err) { - error.OutOfMemory, error.AlreadyReported => |e| return e, + error.OutOfMemory, error.AlreadyReported, error.Canceled => |e| return e, else => |e| return lld.base.comp.link_diags.fail("failed to link with LLD: {t}", .{e}), }; } -fn linkAsArchive(lld: *Lld, arena: Allocator) !void { +fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void { const base = &lld.base; const comp = base.comp; const directory = base.emit.root_dir; // Just an alias to make it shorter to type. @@ -308,8 +306,8 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void { try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len); for (comp.link_inputs) |input| switch (input) { - .res, .dso, .dso_exact => {}, // shared libraries should not be included in static archives - .object, .archive => { + .dso, .dso_exact, .archive => {}, // static archives should not contain shared libraries or other static archives + .res, .object => { const path = try input.path().?.toStringZ(arena); object_files.appendAssumeCapacity(path); }, @@ -340,7 +338,9 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void { const llvm = @import("../codegen/llvm.zig"); const target = &comp.root_mod.resolved_target.result; llvm.initializeLLVMTarget(target.cpu.arch); - const bad = llvm_bindings.WriteArchive( + var err_file_index: usize = undefined; + var err_msg: [*:0]u8 = undefined; + if (llvm_bindings.WriteArchive( full_out_path_z, object_files.items.ptr, object_files.items.len, @@ -348,8 +348,19 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void { .windows => .COFF, else => if (target.os.tag.isDarwin()) .DARWIN else .GNU, }, - ); - if (bad) return error.UnableToWriteArchive; + &err_file_index, + &err_msg, + )) { + defer std.c.free(err_msg); + if (err_file_index < object_files.items.len) { + return comp.link_diags.fail("LLD failed to open input file '{s}': {s}", .{ + object_files.items[err_file_index], + err_msg, + }); + } else { + return comp.link_diags.fail("LLD failed to write archive: {s}", .{err_msg}); + } + } } fn addCommonArgs(argv: *std.array_list.Managed([]const u8), coff: bool) !void { @@ -383,7 +394,7 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { const target = &comp.root_mod.resolved_target.result; const optimize_mode = comp.root_mod.optimize_mode; const entry_name: ?[]const u8 = switch (coff.entry) { - // This logic isn't quite right for disabled or enabled. No point in fixing it + // This logic isn't quite right for default or enabled. No point in fixing it // when the goal is to eliminate dependency on LLD anyway. // https://github.com/ziglang/zig/issues/17751 .disabled, .default, .enabled => null, @@ -456,9 +467,9 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { if (comp.config.lto != .none) { switch (optimize_mode) { - .Debug => {}, - .ReleaseSmall => try argv.append("-OPT:lldlto=2"), - .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"), + .debug => {}, + .small => try argv.append("-OPT:lldlto=2"), + .fast, .safe => try argv.append("-OPT:lldlto=3"), } } if (comp.config.output_mode == .Exe) { @@ -492,6 +503,8 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { if (entry_name) |name| { try argv.append(try arena.print("-ENTRY:{s}", .{name})); + } else if (coff.entry == .disabled) { + try argv.append("-NOENTRY"); } if (coff.repro) { @@ -865,15 +878,15 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { if (comp.config.lto != .none) { switch (comp.root_mod.optimize_mode) { - .Debug => {}, - .ReleaseSmall => try argv.append("--lto-O2"), - .ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"), + .debug => {}, + .small => try argv.append("--lto-O2"), + .fast, .safe => try argv.append("--lto-O3"), } } switch (comp.root_mod.optimize_mode) { - .Debug => {}, - .ReleaseSmall => try argv.append("-O2"), - .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), + .debug => {}, + .small => try argv.append("-O2"), + .fast, .safe => try argv.append("-O3"), } if (elf.entry_name) |name| { @@ -1010,8 +1023,8 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { } if (is_exe_or_dyn_lib and target.os.tag == .netbsd) { - // Add options to produce shared objects with only 2 PT_LOAD segments. - // NetBSD expects 2 PT_LOAD segments in a shared object, otherwise + // Add options to produce shared objects with only 2 PT.LOAD segments. + // NetBSD expects 2 PT.LOAD segments in a shared object, otherwise // ld.elf_so fails loading dynamic libraries with "not found" error. // See https://github.com/ziglang/zig/issues/9109 . try argv.append("--no-rosegment"); @@ -1416,9 +1429,9 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { if (comp.config.lto != .none) { switch (comp.root_mod.optimize_mode) { - .Debug => {}, - .ReleaseSmall => try argv.append("-O2"), - .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), + .debug => {}, + .small => try argv.append("-O2"), + .fast, .safe => try argv.append("-O3"), } } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 41d0c4fd5dc7a7854585b0a0d335c87a608e876c..eb94246a43fe3b4d38d2473f5d53a9512890a20a 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -24,6 +24,8 @@ dylibs: std.ArrayList(File.Index) = .empty, segments: std.ArrayList(macho.segment_command_64) = .empty, sections: std.MultiArrayList(Section) = .{}, +/// Populated by `allocateSections`. +header_size: ?u32 = null, resolver: SymbolResolver = .{}, /// This table will be populated after `scanRelocs` has run. @@ -181,7 +183,7 @@ pub fn createEmpty( .tag = .macho, .comp = comp, .emit = emit, - .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), + .gc_sections = options.gc_sections orelse (optimize_mode != .debug), .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = allow_shlib_undefined, @@ -990,6 +992,11 @@ fn addArchive(self: *MachO, lib: link.Input.Object, handle: File.HandleIndex, fa const tracy = trace(@src()); defer tracy.end(); + if (self.base.isStaticLib()) { + // Ignore static library inputs when generating a static library. + return; + } + const gpa = self.base.comp.gpa; var archive: Archive = .{}; @@ -1068,7 +1075,7 @@ fn isHoisted(self: *MachO, install_name: []const u8) bool { if (mem.startsWith(u8, dirname, "/usr/lib")) return true; if (eatPrefix(dirname, "/System/Library/Frameworks/")) |path| { const basename = fs.path.basename(install_name); - if (mem.indexOfScalar(u8, path, '.')) |index| { + if (mem.findScalar(u8, path, '.')) |index| { if (mem.eql(u8, basename, path[0..index])) return true; } } @@ -1737,14 +1744,14 @@ fn initSyntheticSections(self: *MachO) !void { }); } } else if (eatPrefix(name, "section$start$")) |actual_name| { - const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic + const sep = mem.findScalar(u8, actual_name, '$').?; // TODO error rather than a panic const segname = actual_name[0..sep]; // TODO check segname is valid const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid if (self.getSectionByName(segname, sectname) == null) { _ = try self.addSection(segname, sectname, .{}); } } else if (eatPrefix(name, "section$end$")) |actual_name| { - const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic + const sep = mem.findScalar(u8, actual_name, '$').?; // TODO error rather than a panic const segname = actual_name[0..sep]; // TODO check segname is valid const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid if (self.getSectionByName(segname, sectname) == null) { @@ -1765,7 +1772,7 @@ fn getSegmentProt(segname: []const u8) macho.vm_prot_t { fn getSegmentRank(segname: []const u8) u8 { if (mem.eql(u8, segname, "__PAGEZERO")) return 0x0; if (mem.eql(u8, segname, "__LINKEDIT")) return 0xf; - if (mem.indexOf(u8, segname, "ZIG")) |_| return 0xe; + if (mem.find(u8, segname, "ZIG")) |_| return 0xe; if (mem.startsWith(u8, segname, "__TEXT")) return 0x1; if (mem.startsWith(u8, segname, "__DATA_CONST")) return 0x2; if (mem.startsWith(u8, segname, "__DATA")) return 0x3; @@ -2209,13 +2216,14 @@ fn initSegments(self: *MachO) !void { } fn allocateSections(self: *MachO) !void { - const headerpad = try load_commands.calcMinHeaderPadSize(self); + const header_size = try load_commands.calcMinHeaderSize(self); + self.header_size = header_size; var vmaddr: u64 = if (self.pagezero_seg_index) |index| self.segments.items[index].vmaddr + self.segments.items[index].vmsize else 0; - vmaddr += headerpad; - var fileoff = headerpad; + vmaddr += header_size; + var fileoff = header_size; var prev_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0; const page_size = self.getPageSize(); @@ -2339,7 +2347,7 @@ fn allocateSyntheticSymbols(self: *MachO) void { } } else if (mem.startsWith(u8, name, "section$start$")) { const actual_name = name["section$start$".len..]; - const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic + const sep = mem.findScalar(u8, actual_name, '$').?; // TODO error rather than a panic const segname = actual_name[0..sep]; const sectname = actual_name[sep + 1 ..]; if (self.getSectionByName(segname, sectname)) |sect_id| { @@ -2349,7 +2357,7 @@ fn allocateSyntheticSymbols(self: *MachO) void { } } else if (mem.startsWith(u8, name, "section$end$")) { const actual_name = name["section$end$".len..]; - const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic + const sep = mem.findScalar(u8, actual_name, '$').?; // TODO error rather than a panic const segname = actual_name[0..sep]; const sectname = actual_name[sep + 1 ..]; if (self.getSectionByName(segname, sectname)) |sect_id| { @@ -2895,6 +2903,11 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { ncmds += 1; } + if (self.needsEncryptionInfo()) { + try load_commands.writeEncryptionInfoLC(self, &writer); + ncmds += 1; + } + for (self.rpath_list) |rpath| { try load_commands.writeRpathLC(rpath, &writer); ncmds += 1; @@ -5410,6 +5423,18 @@ pub fn alignPow(macho_file: *MachO, x: u32) error{AlreadyReported}!u32 { return result; } +pub fn needsEncryptionInfo(macho_file: *MachO) bool { + const target = macho_file.getTarget(); + return switch (target.os.tag) { + .ios, + .tvos, + .visionos, + .watchos, + => target.abi != .simulator, + else => false, + }; +} + /// Branch instruction has 26 bits immediate but is 4 byte aligned. const jump_bits = @bitSizeOf(i28); const max_distance = (1 << (jump_bits - 1)); diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index a733e1a5b6c9b3911e27e5e60e1ae4e6faed54a5..91860f45986b106bed46fbf37e9ac35133ff5b49 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -45,7 +45,7 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File const amt = try handle.readPositionalAll(io, buf, pos); if (amt != len) return error.InputOutput; pos += len; - const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len; + const actual_len = mem.findScalar(u8, buf, @as(u8, 0)) orelse len; break :name buf[0..actual_len]; } unreachable; @@ -161,7 +161,7 @@ pub const ar_hdr = extern struct { fn name(self: *const ar_hdr) ?[]const u8 { const value = &self.ar_name; if (mem.startsWith(u8, value, "#1/")) return null; - const sentinel = mem.indexOfScalar(u8, value, '/') orelse value.len; + const sentinel = mem.findScalar(u8, value, '/') orelse value.len; return value[0..sentinel]; } diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 7ac8e28881417cde1fcb9da5a9cc90eaf43b8036..60172cf6382342fc6f40080b31724d8369a504ea 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -43,7 +43,7 @@ pub fn isSymbolStab(symbol: Symbol, macho_file: *MachO) bool { pub fn isTlvInit(symbol: Symbol, macho_file: *MachO) bool { const name = symbol.getName(macho_file); - return std.mem.indexOf(u8, name, "$tlv$init") != null; + return std.mem.find(u8, name, "$tlv$init") != null; } pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool { diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 8d7407a0a397e9f4f0df654ef4eb45fe19e0e108..71a4bc6dc70c0465a079f035d459a07d8720ceed 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -946,8 +946,8 @@ fn updateNavCode( const target = &mod.resolved_target.result; const required_alignment = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { - .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), - .ReleaseSmall => target_util.minFunctionAlignment(target), + .debug, .safe, .fast => target_util.defaultFunctionAlignment(target), + .small => target_util.minFunctionAlignment(target), }, else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), }; @@ -1172,8 +1172,8 @@ fn getNavOutputSection( if (nav.resolved.?.@"const") return macho_file.zig_const_sect_index.?; if (nav_val.isUndef(zcu)) return switch (zcu.navFileScope(nav_index).mod.?.optimize_mode) { - .Debug, .ReleaseSafe => macho_file.zig_data_sect_index.?, - .ReleaseFast, .ReleaseSmall => macho_file.zig_bss_sect_index.?, + .debug, .safe => macho_file.zig_data_sect_index.?, + .fast, .small => macho_file.zig_bss_sect_index.?, }; for (code) |byte| { if (byte != 0) break; diff --git a/src/link/MachO/dyld_info/Trie.zig b/src/link/MachO/dyld_info/Trie.zig index b1fdc18d7593608ea6b3eb732adb46548096352d..92c22967f3e23647d84b399ffdc6ac92a60f2f8e 100644 --- a/src/link/MachO/dyld_info/Trie.zig +++ b/src/link/MachO/dyld_info/Trie.zig @@ -54,7 +54,7 @@ fn putNode(self: *Trie, node_index: Node.Index, allocator: Allocator, label: []c // Check for match with edges from this node. for (self.nodes.items(.edges)[node_index].items) |edge_index| { const edge = &self.edges.items[edge_index]; - const match = mem.indexOfDiff(u8, edge.label, label) orelse return edge.node; + const match = mem.findDiff(u8, edge.label, label) orelse return edge.node; if (match == 0) continue; if (match == edge.label.len) return self.putNode(edge.node, allocator, label[match..]); @@ -351,7 +351,7 @@ fn expectEqualHexStrings(expected: []const u8, given: []const u8) !void { defer testing.allocator.free(expected_fmt); const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{given}); defer testing.allocator.free(given_fmt); - const idx = mem.indexOfDiff(u8, expected_fmt, given_fmt).?; + const idx = mem.findDiff(u8, expected_fmt, given_fmt).?; const padding = try testing.allocator.alloc(u8, idx + 5); defer testing.allocator.free(padding); @memset(padding, ' '); diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index ec556b16bb9a7a50ada47fe9740c25aea9fc775b..62bbc751cb58e82aee019f07065eabf1b8cf8917 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -62,6 +62,10 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 assume_max_path_len, ); } + // LC_ENCRYPTION_INFO_64 + if (macho_file.needsEncryptionInfo()) { + sizeofcmds += @sizeOf(macho.encryption_info_command_64); + } // LC_RPATH { for (macho_file.rpath_list) |rpath| { @@ -163,23 +167,29 @@ pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 { return @as(u32, @intCast(sizeofcmds)); } -pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 { +pub fn calcMinHeaderSize(macho_file: *MachO) !u32 { var padding: u32 = (try calcLoadCommandsSize(macho_file, false)) + (macho_file.headerpad_size orelse MachO.default_headerpad_size); - log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)}); + log.debug("minimum requested header + padding size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)}); if (macho_file.headerpad_max_install_names) { const min_headerpad_size: u32 = try calcLoadCommandsSize(macho_file, true); - log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{ + log.debug("headerpad_max_install_names minimum header + padding size 0x{x}", .{ min_headerpad_size + @sizeOf(macho.mach_header_64), }); padding = @max(padding, min_headerpad_size); } const offset = @sizeOf(macho.mach_header_64) + padding; - log.debug("actual headerpad size 0x{x}", .{offset}); + log.debug("actual header + padding size 0x{x}", .{offset}); - return offset; + // Encryption is done at page granularity, so if the output needs a load + // command for encryption info, ensure that the header + load commands have + // at least one full, unencrypted page. + return if (macho_file.needsEncryptionInfo()) + mem.alignForward(u32, offset, macho_file.getPageSize()) + else + offset; } pub fn writeDylinkerLC(writer: *Writer) !void { @@ -260,6 +270,13 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: *Writer) !void { }, writer); } +pub fn writeEncryptionInfoLC(macho_file: *MachO, writer: *Writer) !void { + try writer.writeAll(mem.asBytes(&macho.encryption_info_command_64{ + .cryptoff = macho_file.header_size.?, + .cryptsize = @as(u32, @intCast(macho_file.getTextSegment().filesize)) - macho_file.header_size.?, + })); +} + pub fn writeRpathLC(rpath: []const u8, writer: *Writer) !void { const rpath_len = rpath.len + 1; const cmdsize = @as(u32, @intCast(mem.alignForward( diff --git a/src/link/MappedFile.zig b/src/link/MappedFile.zig index 6fd6e1ab4a27da8b582f8d5daa1ca122aeb546c9..fa8fe9e3936b87d4773d3e3b2abebe0b14ef017f 100644 --- a/src/link/MappedFile.zig +++ b/src/link/MappedFile.zig @@ -23,6 +23,7 @@ nodes: std.ArrayList(Node), free_ni: Node.Index, large: std.ArrayList(u64), updates: std.ArrayList(Node.Index), +/// This progress node's estimated total items is increased once for each node appended to `updates`. update_prog_node: std.Progress.Node, writers: std.SinglyLinkedList, io_err: ?IoError, @@ -61,7 +62,7 @@ pub const Error = Allocator.Error || Io.Cancelable || error{ MappedFileIo, }; -pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || Io.Cancelable || IoError)!MappedFile { +pub fn init(file: Io.File, gpa: Allocator, io: Io) (Allocator.Error || Io.Cancelable || IoError)!MappedFile { var mf: MappedFile = .{ .io = io, .flags = undefined, @@ -105,7 +106,7 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I return mf; } -pub fn deinit(mf: *MappedFile, gpa: std.mem.Allocator) void { +pub fn deinit(mf: *MappedFile, gpa: Allocator) void { mf.unmap(); mf.nodes.deinit(gpa); mf.large.deinit(gpa); @@ -133,11 +134,15 @@ pub const Node = extern struct { moved: bool, /// Whether this node has been resized. resized: bool, + /// Whether the next sibling has moved or is a different node. + next_moved: bool, /// Whether this node might contain non-zero bytes. has_content: bool, - /// Whether a moved event on this node bubbles down to children. + /// Whether `moved` events on this node bubble down to children. bubbles_moved: bool, - unused: @Int(.unsigned, 32 - @bitSizeOf(std.mem.Alignment) - 6) = 0, + /// Whether `next_moved` events are reported in `updates`. + enable_next_moved: bool, + unused: @Int(.unsigned, 32 - @bitSizeOf(std.mem.Alignment) - 8) = 0, }; pub const Location = union(enum(u1)) { @@ -191,6 +196,22 @@ pub const Node = extern struct { pub fn next(ni: Node.Index, mf: *const MappedFile) Node.Index { return ni.get(mf).next; } + fn setNext( + prev_ni: Node.Index, + gpa: Allocator, + next_ni: Node.Index, + mf: *MappedFile, + ) Allocator.Error!void { + assert(prev_ni != .none); + const prev_next = &prev_ni.get(mf).next; + if (prev_next.* == next_ni) return; + prev_next.* = next_ni; + try prev_ni.nextMoved(gpa, mf); + } + + pub fn prev(ni: Node.Index, mf: *const MappedFile) Node.Index { + return ni.get(mf).prev; + } pub fn ChildIterator(comptime direction: enum { prev, next }) type { return struct { @@ -211,7 +232,7 @@ pub const Node = extern struct { return .{ .mf = mf, .ni = ni.get(mf).last }; } - pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) Allocator.Error!void { + pub fn childrenMoved(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void { var child_ni = ni.get(mf).last; while (child_ni != .none) { try child_ni.moved(gpa, mf); @@ -229,11 +250,11 @@ pub const Node = extern struct { } return false; } - pub fn moved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) Allocator.Error!void { - try mf.updates.ensureUnusedCapacity(gpa, 1); + pub fn moved(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void { + try mf.updates.ensureUnusedCapacity(gpa, 2); ni.movedAssumeCapacity(mf); } - pub fn cleanMoved(ni: Node.Index, mf: *const MappedFile) bool { + pub fn cleanMoved(ni: Node.Index, mf: *MappedFile) bool { const node_moved = &ni.get(mf).flags.moved; defer node_moved.* = false; return node_moved.*; @@ -242,7 +263,11 @@ pub const Node = extern struct { if (ni.hasMoved(mf)) return; const node = ni.get(mf); node.flags.moved = true; - if (node.flags.resized) return; + switch (node.prev) { + .none => {}, + else => |prev_ni| prev_ni.nextMovedAssumeCapacity(mf), + } + if (node.flags.resized or node.flags.next_moved) return; mf.updates.appendAssumeCapacity(ni); mf.update_prog_node.increaseEstimatedTotalItems(1); } @@ -250,11 +275,11 @@ pub const Node = extern struct { pub fn hasResized(ni: Node.Index, mf: *const MappedFile) bool { return ni.get(mf).flags.resized; } - pub fn resized(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) Allocator.Error!void { + pub fn resized(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void { try mf.updates.ensureUnusedCapacity(gpa, 1); ni.resizedAssumeCapacity(mf); } - pub fn cleanResized(ni: Node.Index, mf: *const MappedFile) bool { + pub fn cleanResized(ni: Node.Index, mf: *MappedFile) bool { const node_resized = &ni.get(mf).flags.resized; defer node_resized.* = false; return node_resized.*; @@ -263,7 +288,28 @@ pub const Node = extern struct { const node = ni.get(mf); if (node.flags.resized) return; node.flags.resized = true; - if (node.flags.moved) return; + if (node.flags.moved or node.flags.next_moved) return; + mf.updates.appendAssumeCapacity(ni); + mf.update_prog_node.increaseEstimatedTotalItems(1); + } + + pub fn hasNextMoved(ni: Node.Index, mf: *const MappedFile) bool { + return ni.get(mf).flags.next_moved; + } + pub fn nextMoved(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void { + try mf.updates.ensureUnusedCapacity(gpa, 1); + ni.nextMovedAssumeCapacity(mf); + } + pub fn cleanNextMoved(ni: Node.Index, mf: *MappedFile) bool { + const node_next_moved = &ni.get(mf).flags.next_moved; + defer node_next_moved.* = false; + return node_next_moved.*; + } + pub fn nextMovedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void { + const node = ni.get(mf); + if (!node.flags.enable_next_moved or node.flags.next_moved) return; + node.flags.next_moved = true; + if (node.flags.moved or node.flags.resized) return; mf.updates.appendAssumeCapacity(ni); mf.update_prog_node.increaseEstimatedTotalItems(1); } @@ -333,7 +379,7 @@ pub const Node = extern struct { return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)]; } - pub fn resize(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, size: u64) Error!void { + pub fn resize(ni: Node.Index, mf: *MappedFile, gpa: Allocator, size: u64) Error!void { mf.resizeNode(gpa, ni, size) catch |err| switch (err) { error.OutOfMemory, error.Canceled, @@ -360,7 +406,7 @@ pub const Node = extern struct { pub fn realign( ni: Node.Index, mf: *MappedFile, - gpa: std.mem.Allocator, + gpa: Allocator, new_alignment: std.mem.Alignment, opts: RealignNodeOptions, ) Error!void { @@ -384,7 +430,7 @@ pub const Node = extern struct { pub fn shrink( ni: Node.Index, mf: *MappedFile, - gpa: std.mem.Allocator, + gpa: Allocator, size: u64, shift_next: bool, ) Error!void { @@ -392,7 +438,7 @@ pub const Node = extern struct { mf.updateWriters(); } - pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void { + pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: Allocator, w: *Writer) void { w.* = .{ .gpa = gpa, .mf = mf, @@ -419,7 +465,7 @@ pub const Node = extern struct { } pub const Writer = struct { - gpa: std.mem.Allocator, + gpa: Allocator, mf: *MappedFile, writer_node: std.SinglyLinkedList.Node, ni: Node.Index, @@ -543,14 +589,13 @@ pub const Node = extern struct { } }; -fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { +fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct { parent: Node.Index = .none, prev: Node.Index = .none, next: Node.Index = .none, offset: u64 = 0, add_node: AddNodeOptions, }) (Allocator.Error || Io.Cancelable || IoError)!Node.Index { - if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); mf.nodes_lock.assertUnlocked(); const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { if (std.math.cast(u32, opts.offset)) |small_offset| break :location .{ .small, .{ @@ -570,7 +615,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { }; switch (opts.prev) { .none => opts.parent.get(mf).first = free_ni, - else => |prev_ni| prev_ni.get(mf).next = free_ni, + else => |prev_ni| try prev_ni.setNext(gpa, free_ni, mf), } switch (opts.next) { .none => opts.parent.get(mf).last = free_ni, @@ -588,22 +633,27 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { .fixed = opts.add_node.fixed, .moved = true, .resized = true, + .next_moved = true, .has_content = false, .bubbles_moved = opts.add_node.bubbles_moved, + .enable_next_moved = opts.add_node.enable_next_moved, }, .location_payload = location_payload, }; { + defer { + free_node.flags.moved = false; + free_node.flags.resized = false; + free_node.flags.next_moved = false; + } try mf.realignNode(gpa, free_ni, opts.add_node.alignment, .{}); try mf.resizeNode(gpa, free_ni, opts.add_node.size); - if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); - free_node.flags.moved = false; - free_node.flags.resized = false; } - if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); - if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); mf.updateWriters(); + if (opts.add_node.moved) try free_ni.moved(gpa, mf); + if (opts.add_node.resized) try free_ni.resized(gpa, mf); + if (opts.add_node.next_moved) try free_ni.nextMoved(gpa, mf); return free_ni; } @@ -613,12 +663,14 @@ pub const AddNodeOptions = struct { fixed: bool = false, moved: bool = false, resized: bool = false, + next_moved: bool = false, bubbles_moved: bool = true, + enable_next_moved: bool = false, }; pub fn addOnlyChildNode( mf: *MappedFile, - gpa: std.mem.Allocator, + gpa: Allocator, parent_ni: Node.Index, opts: AddNodeOptions, ) Error!Node.Index { @@ -641,7 +693,7 @@ pub fn addOnlyChildNode( pub fn addFirstChildNode( mf: *MappedFile, - gpa: std.mem.Allocator, + gpa: Allocator, parent_ni: Node.Index, opts: AddNodeOptions, ) Error!Node.Index { @@ -664,7 +716,7 @@ pub fn addFirstChildNode( pub fn addLastChildNode( mf: *MappedFile, - gpa: std.mem.Allocator, + gpa: Allocator, parent_ni: Node.Index, opts: AddNodeOptions, ) Error!Node.Index { @@ -694,7 +746,7 @@ pub fn addLastChildNode( pub fn addNodeAfter( mf: *MappedFile, - gpa: std.mem.Allocator, + gpa: Allocator, prev_ni: Node.Index, opts: AddNodeOptions, ) Error!Node.Index { @@ -721,7 +773,7 @@ pub fn addNodeAfter( fn shrinkNode( mf: *MappedFile, - gpa: std.mem.Allocator, + gpa: Allocator, ni: Node.Index, size: u64, shift_next: bool, @@ -740,7 +792,7 @@ fn shrinkNode( } try mf.large.ensureUnusedCapacity(gpa, 4); - try mf.updates.ensureUnusedCapacity(gpa, 2); + try mf.updates.ensureUnusedCapacity(gpa, 4); ni.setLocationAssumeCapacity(mf, old_offset, size); if (!shift_next or node.next == .none) return; @@ -765,7 +817,7 @@ fn shrinkNode( fn resizeNode( mf: *MappedFile, - gpa: std.mem.Allocator, + gpa: Allocator, ni: Node.Index, requested_size: u64, ) (Allocator.Error || Io.Cancelable || IoError)!void { @@ -904,11 +956,11 @@ fn resizeNode( next_ni.get(mf).prev = node.prev; switch (node.prev) { .none => parent.first = next_ni, - else => |prev_ni| prev_ni.get(mf).next = next_ni, + else => |prev_ni| try prev_ni.setNext(gpa, next_ni, mf), } - last.next = ni; + try parent.last.setNext(gpa, ni, mf); node.prev = parent.last; - node.next = .none; + try ni.setNext(gpa, .none, mf); parent.last = ni; if (node.flags.has_content) { const parent_file_offset = node.parent.fileLocation(mf, false).offset; @@ -972,13 +1024,13 @@ fn resizeNode( if (parent.last != first_floating_ni) { first_floating.prev = parent.last; parent.last = first_floating_ni; - last.next = first_floating_ni; - last_fixed.next = first_floating.next; + try parent.last.setNext(gpa, first_floating_ni, mf); + try last_fixed_ni.setNext(gpa, first_floating.next, mf); switch (first_floating.next) { .none => {}, else => |next_ni| next_ni.get(mf).prev = last_fixed_ni, } - first_floating.next = .none; + try first_floating_ni.setNext(gpa, .none, mf); } if (first_floating.flags.has_content) { const parent_file_offset = @@ -1040,7 +1092,7 @@ fn resizeNode( fn realignNode( mf: *MappedFile, - gpa: std.mem.Allocator, + gpa: Allocator, ni: Node.Index, new_alignment: std.mem.Alignment, opts: Node.Index.RealignNodeOptions, @@ -1241,9 +1293,9 @@ fn copyFileRange( return size - remaining_size; } -fn ensureCapacityForSetLocation(mf: *MappedFile, gpa: std.mem.Allocator) Allocator.Error!void { +fn ensureCapacityForSetLocation(mf: *MappedFile, gpa: Allocator) Allocator.Error!void { try mf.large.ensureUnusedCapacity(gpa, 2); - try mf.updates.ensureUnusedCapacity(gpa, 1); + try mf.updates.ensureUnusedCapacity(gpa, 2); } pub fn ensureTotalCapacity(mf: *MappedFile, new_capacity: usize) Error!void { diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 10d01c2055ff5bf5c1d3734b4a4ae43411d8cc14..aecbc039266604cc905586b71032e91d83b096d0 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -25,10 +25,10 @@ const Mir = @import("../codegen/spirv/Mir.zig"); const Linker = @This(); base: link.File, -fragments: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Mir) = .empty, -pending_navs: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty, -entry_points: std.ArrayListUnmanaged(EntryPointDecl) = .empty, -external_objects: std.ArrayListUnmanaged(ExternalObject) = .empty, +fragments: std.array_hash_map.Auto(InternPool.Nav.Index, Mir) = .empty, +pending_navs: std.ArrayList(InternPool.Nav.Index) = .empty, +entry_points: std.ArrayList(EntryPointDecl) = .empty, +external_objects: std.ArrayList(ExternalObject) = .empty, const EntryPointDecl = struct { nav: InternPool.Nav.Index, @@ -363,16 +363,16 @@ fn mergeFragments(linker: *Linker, gpa: Allocator, arena: Allocator) error{OutOf } // Resolve Zig extern navs against external objects. - var ext_id_offsets: std.ArrayListUnmanaged(Word) = .empty; + var ext_id_offsets: std.ArrayList(Word) = .empty; defer ext_id_offsets.deinit(gpa); try ext_id_offsets.ensureTotalCapacity(gpa, linker.external_objects.items.len); var unresolved_extern_count: u32 = 0; - var resolved_ids: std.AutoArrayHashMapUnmanaged(Id, void) = .empty; + var resolved_ids: std.array_hash_map.Auto(Id, void) = .empty; defer resolved_ids.deinit(gpa); if (maybe_ip) |ip| { - var extern_name_map: std.StringArrayHashMapUnmanaged(InternPool.Nav.Index) = .empty; + var extern_name_map: std.array_hash_map.String(InternPool.Nav.Index) = .empty; defer extern_name_map.deinit(gpa); var nav_it = nav_final_ids.iterator(); @@ -518,14 +518,14 @@ fn mergeZigFragments( frag_infos: []const FragmentInfo, nav_final_ids: *const std.AutoHashMapUnmanaged(InternPool.Nav.Index, Id), uav_final_ids: *const std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Id), - resolved_ids: *const std.AutoArrayHashMapUnmanaged(Id, void), + resolved_ids: *const std.array_hash_map.Auto(Id, void), maybe_ip: ?*InternPool, ) error{OutOfMemory}!void { for (linker.fragments.values(), frag_infos) |*mir, frag_info| { var id_remap: std.AutoHashMapUnmanaged(Id, Id) = .empty; defer id_remap.deinit(gpa); - var resolved_local_ids: std.AutoArrayHashMapUnmanaged(Id, void) = .empty; + var resolved_local_ids: std.array_hash_map.Auto(Id, void) = .empty; defer resolved_local_ids.deinit(gpa); for (mir.nav_refs) |ref| { @@ -569,7 +569,7 @@ fn remapFilteredInsts( id_offset: Word, id_remap: *const std.AutoHashMapUnmanaged(Id, Id), parser: *BinaryModule.Parser, - skip_ids: *const std.AutoArrayHashMapUnmanaged(Id, void), + skip_ids: *const std.array_hash_map.Auto(Id, void), mode: FilterMode, ) error{OutOfMemory}!void { if (words.len == 0) return; @@ -887,9 +887,9 @@ fn appendExternalObjects( has_linkage: *bool, keep_entry_points: bool, is_obj: bool, - resolved_ids: *const std.AutoArrayHashMapUnmanaged(Id, void), + resolved_ids: *const std.array_hash_map.Auto(Id, void), ) error{OutOfMemory}!void { - var export_map: std.StringArrayHashMapUnmanaged(Id) = .empty; + var export_map: std.array_hash_map.String(Id) = .empty; defer export_map.deinit(gpa); for (linker.external_objects.items, ext_id_offsets) |ext_obj, id_offset| { @@ -908,7 +908,7 @@ fn appendExternalObjects( } for (per_obj_remaps) |*m| m.* = .empty; - var resolved_linkage_ids: std.AutoArrayHashMapUnmanaged(Id, void) = .empty; + var resolved_linkage_ids: std.array_hash_map.Auto(Id, void) = .empty; defer resolved_linkage_ids.deinit(gpa); for (resolved_ids.keys()) |id| { diff --git a/src/link/SpirV/dedup_types.zig b/src/link/SpirV/dedup_types.zig index df0d9a29dd78258acda42be564a14ab748638bce..8841c4185033c8ace7131236f0e549ef10745118 100644 --- a/src/link/SpirV/dedup_types.zig +++ b/src/link/SpirV/dedup_types.zig @@ -85,7 +85,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void { for (inst.operands, 0..) |word, i| { if (i == result_id_index) continue; - if (std.mem.indexOfScalar(u16, id_offsets.items, @intCast(i)) != null) { + if (std.mem.findScalar(u16, id_offsets.items, @intCast(i)) != null) { const canonical = id_remap.get(@fromBackingInt(@intCast(word))) orelse @as(Id, @fromBackingInt(@intCast(word))); try key_words.append(gpa, @backingInt(canonical)); } else { @@ -182,7 +182,7 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void { } else null; for (inst_slice, 0..) |*word, i| { - if (std.mem.indexOfScalar(u16, id_offsets.items, @intCast(i)) == null) continue; + if (std.mem.findScalar(u16, id_offsets.items, @intCast(i)) == null) continue; max_id = @max(max_id, word.*); if (maybe_result_id_index != null and i == maybe_result_id_index.?) continue; diff --git a/src/link/SpirV/prune_unused.zig b/src/link/SpirV/prune_unused.zig index 2ca052152fdbb371e05a8d8fc5aac95fa8402f11..a41b0d878d07b7c3e3179429dae74e27aaf044b8 100644 --- a/src/link/SpirV/prune_unused.zig +++ b/src/link/SpirV/prune_unused.zig @@ -187,7 +187,7 @@ fn markAlive( parser: *BinaryModule.Parser, binary: BinaryModule, inst: BinaryModule.Instruction, - alive: *std.DynamicBitSetUnmanaged, + alive: *std.bit_set.Dynamic, id_to_index: *const std.AutoHashMapUnmanaged(ResultId, u32), code_offsets: *const std.ArrayList(usize), id_offset_buf: *std.ArrayList(u16), diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index a1445d3b4fbe49d94f43cb88cab30a237f4cd7cc..9fba1510ba1f847d2c1ed1cdd2f15eab3c30504f 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -133,25 +133,21 @@ object_total_sections: u32 = 0, /// All comdat symbols from all objects concatenated. object_comdat_symbols: std.MultiArrayList(Comdat.Symbol) = .empty, -/// Relocations to be emitted into an object file. Remains empty when not -/// emitting an object file. -out_relocs: std.MultiArrayList(OutReloc) = .empty, +/// Relocations produced by Zig code and data lowering. These retain semantic +/// targets until `flush`, where final output indexes are known. +zcu_relocations: std.MultiArrayList(ZcuRelocation) = .empty, /// List of locations within `string_bytes` that must be patched with the virtual /// memory address of a Uav during `flush`. -/// When emitting an object file, `out_relocs` is used instead. +/// When emitting an object file, `zcu_relocations` is used instead. uav_fixups: std.ArrayList(UavFixup) = .empty, /// List of locations within `string_bytes` that must be patched with the virtual /// memory address of a Nav during `flush`. -/// When emitting an object file, `out_relocs` is used instead. +/// When emitting an object file, `zcu_relocations` is used instead. /// No functions here only global variables. nav_fixups: std.ArrayList(NavFixup) = .empty, /// When a nav reference is a function pointer, this tracks the required function /// table entry index that needs to overwrite the code in the final output. func_table_fixups: std.ArrayList(FuncTableFixup) = .empty, -/// Symbols to be emitted into an object file. Remains empty when not emitting -/// an object file. -symbol_table: std.array_hash_map.Auto(String, void) = .empty, - /// When importing objects from the host environment, a name must be supplied. /// LLVM uses "env" by default when none is given. /// This value is passed to object files since wasm tooling conventions provides @@ -244,7 +240,9 @@ function_imports: std.array_hash_map.Auto(String, FunctionImportId) = .empty, /// remove elements from the table, and the remainder are either undefined /// symbol errors, or symbol table entries depending on the output mode. data_imports: std.array_hash_map.Auto(String, DataImportId) = .empty, -/// Set of data symbols that will appear in the final binary. Used to populate +/// Set of data symbols that will appear in the final binary when outputting an object file. +datas: std.array_hash_map.Auto(ObjectDataImport.Resolution, void) = .empty, +/// Set of data segment symbols that will appear in the final binary. Used to populate /// `Flush.data_segments` before sorting. data_segments: std.array_hash_map.Auto(DataSegmentId, void) = .empty, @@ -302,11 +300,6 @@ pub const TagNameOff = extern struct { len: u32, }; -/// Index into `Wasm.zcu_indirect_function_set`. -pub const ZcuIndirectFunctionSetIndex = enum(u32) { - _, -}; - pub const UavFixup = extern struct { uavs_exe_index: UavsExeIndex, /// Index into `string_bytes`. @@ -315,14 +308,14 @@ pub const UavFixup = extern struct { }; pub const NavFixup = extern struct { - navs_exe_index: NavsExeIndex, + nav_index: InternPool.Nav.Index, /// Index into `string_bytes`. offset: u32, addend: u32, }; pub const FuncTableFixup = extern struct { - table_index: ZcuIndirectFunctionSetIndex, + nav_index: InternPool.Nav.Index, /// Index into `string_bytes`. offset: u32, }; @@ -355,7 +348,9 @@ pub const FunctionIndex = enum(u32) { pub fn fromSymbolName(wasm: *const Wasm, name: String) ?FunctionIndex { if (wasm.object_function_imports.getPtr(name)) |import| { - return fromResolution(wasm, import.resolution); + if (import.resolution != .unresolved) { + return fromResolution(wasm, import.resolution); + } } if (wasm.function_exports.get(name)) |index| return index; if (wasm.hidden_function_exports.get(name)) |index| return index; @@ -374,7 +369,8 @@ pub const GlobalExport = extern struct { }; /// 0. Index into `Flush.function_imports` -/// 1. Index into `functions`. +/// 1. Index into `Flush.intrinsic_function_imports` +/// 2. Index into `functions`. /// /// Note that function_imports indexes are subject to swap removals during /// `flush`. @@ -386,7 +382,11 @@ pub const OutputFunctionIndex = enum(u32) { } pub fn fromFunctionIndex(wasm: *const Wasm, index: FunctionIndex) OutputFunctionIndex { - return @fromBackingInt(@intCast(wasm.flush_buffer.function_imports.entries.len + @backingInt(index))); + return @fromBackingInt(@intCast( + wasm.flush_buffer.function_imports.entries.len + + wasm.flush_buffer.intrinsic_function_imports.entries.len + + @backingInt(index), + )); } pub fn fromObjectFunction(wasm: *const Wasm, index: ObjectFunctionIndex) OutputFunctionIndex { @@ -429,6 +429,9 @@ pub const OutputFunctionIndex = enum(u32) { pub fn fromSymbolName(wasm: *const Wasm, name: String) OutputFunctionIndex { if (wasm.flush_buffer.function_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i)); + if (wasm.flush_buffer.intrinsic_function_imports.getIndex(name)) |i| return @fromBackingInt(@intCast( + wasm.flush_buffer.function_imports.entries.len + i, + )); return fromFunctionIndex(wasm, FunctionIndex.fromSymbolName(wasm, name) orelse { if (std.debug.runtime_safety) { std.debug.panic("function index for symbol not found: {s}", .{name.slice(wasm)}); @@ -437,6 +440,56 @@ pub const OutputFunctionIndex = enum(u32) { } }; +// Order +// 0. Flush.data_imports +// 1. Wasm.datas +pub const OutputDataIndex = enum(u32) { + _, + + pub fn fromSymbolName(wasm: *const Wasm, name: String) OutputDataIndex { + if (wasm.flush_buffer.data_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i)); + if (wasm.object_data_imports.getPtr(name)) |import| { + if (import.resolution != .unresolved) return fromResolution(wasm, import.resolution).?; + } + if (wasm.flush_buffer.data_exports.get(name)) |symbol| return fromResolution(wasm, symbol.resolution).?; + if (std.debug.runtime_safety) { + std.debug.panic("data index for symbol not found: {s}", .{name.slice(wasm)}); + } else unreachable; + } + + pub fn fromObjectData(wasm: *const Wasm, index: ObjectData.Index) OutputDataIndex { + return fromResolution(wasm, .fromObjectDataIndex(wasm, index)).?; + } + + pub fn fromResolution(wasm: *const Wasm, resolution: ObjectDataImport.Resolution) ?OutputDataIndex { + const i = wasm.datas.getIndex(resolution) orelse return null; + return @fromBackingInt(@intCast(wasm.flush_buffer.data_imports.entries.len + i)); + } + + pub fn fromUav(wasm: *const Wasm, ip_index: InternPool.Index) OutputDataIndex { + const comp = wasm.base.comp; + const resolution: ObjectDataImport.Resolution = if (comp.config.output_mode == .Obj) + .pack(wasm, .{ .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)) }) + else + .pack(wasm, .{ .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)) }); + return fromResolution(wasm, resolution).?; + } + + pub fn fromNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) OutputDataIndex { + const zcu = wasm.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const nav = ip.getNav(nav_index); + if (nav.getExtern(ip)) |ext| { + return fromSymbolName(wasm, wasm.getExistingString(ext.name.toSlice(ip)).?); + } + const resolution: ObjectDataImport.Resolution = if (wasm.base.comp.config.output_mode == .Obj) + .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)) }) + else + .pack(wasm, .{ .nav_exe = @fromBackingInt(@intCast(wasm.navs_exe.getIndex(nav_index).?)) }); + return fromResolution(wasm, resolution).?; + } +}; + /// Index into `Wasm.globals`. pub const GlobalIndex = enum(u32) { _, @@ -452,17 +505,17 @@ pub const GlobalIndex = enum(u32) { return .stack_pointer; } - pub fn ptr(index: GlobalIndex, f: *const Flush) *Wasm.GlobalImport.Resolution { - return &f.globals.items[@backingInt(index)]; + pub fn fromResolution(wasm: *const Wasm, resolution: GlobalImport.Resolution) ?GlobalIndex { + const i = wasm.globals.getIndex(resolution) orelse return null; + return @fromBackingInt(@intCast(wasm.flush_buffer.global_imports.entries.len + i)); } pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?GlobalIndex { - const i = wasm.globals.getIndex(.fromIpNav(wasm, nav_index)) orelse return null; - return @fromBackingInt(@intCast(i)); + return fromResolution(wasm, .fromIpNav(wasm, nav_index)); } pub fn fromObjectGlobal(wasm: *const Wasm, i: ObjectGlobalIndex) GlobalIndex { - return @fromBackingInt(@intCast(wasm.globals.getIndex(.fromObjectGlobal(wasm, i)).?)); + return fromResolution(wasm, .fromObjectGlobal(wasm, i)).?; } pub fn fromObjectGlobalHandlingWeak(wasm: *const Wasm, index: ObjectGlobalIndex) GlobalIndex { @@ -474,8 +527,9 @@ pub const GlobalIndex = enum(u32) { } pub fn fromSymbolName(wasm: *const Wasm, name: String) GlobalIndex { + if (wasm.flush_buffer.global_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i)); const import = wasm.object_global_imports.getPtr(name).?; - return @fromBackingInt(@intCast(wasm.globals.getIndex(import.resolution).?)); + return fromResolution(wasm, import.resolution).?; } }; @@ -483,10 +537,6 @@ pub const GlobalIndex = enum(u32) { pub const TableIndex = enum(u32) { _, - pub fn ptr(index: TableIndex, f: *const Flush) *Wasm.TableImport.Resolution { - return &f.tables.items[@backingInt(index)]; - } - pub fn fromObjectTable(wasm: *const Wasm, i: ObjectTableIndex) TableIndex { return @fromBackingInt(@intCast(wasm.tables.getIndex(.fromObjectTable(i)).?)); } @@ -668,9 +718,10 @@ pub const SymbolFlags = packed struct(u32) { flags.ref_type = .funcref; } - pub fn isIncluded(flags: SymbolFlags, is_dynamic: bool) bool { + pub fn isIncluded(flags: SymbolFlags, is_dynamic: bool, is_obj: bool) bool { return flags.exported or (is_dynamic and !flags.visibility_hidden) or + (is_obj and flags.binding != .local) or (flags.no_strip and flags.must_link); } @@ -696,8 +747,8 @@ pub const SymbolFlags = packed struct(u32) { /// Masks off the Zig-specific stuff. pub fn toAbiInteger(flags: SymbolFlags) u32 { var copy = flags; - copy.initZigSpecific(false, false); - return @bitCast(copy); + copy.initZigSpecific(false, flags.no_strip); + return @backingInt(copy); } }; @@ -812,7 +863,7 @@ pub const UavsExeIndex = enum(u32) { /// Used when emitting a relocatable object. pub const ZcuDataObj = extern struct { code: DataPayload, - relocs: OutReloc.Slice, + relocs: ZcuRelocation.Slice, }; /// Used when not emitting a relocatable object. @@ -855,7 +906,9 @@ const ZcuDataStarts = struct { var uavs_i = zds.uavs_i; while (uavs_i < wasm.uavs_obj.entries.len) : (uavs_i += 1) { // Call to `lowerZcuData` here possibly creates more entries in these tables. - wasm.uavs_obj.values()[uavs_i] = try lowerZcuData(wasm, pt, wasm.uavs_obj.keys()[uavs_i]); + const uav = wasm.uavs_obj.keys()[uavs_i]; + const zcu_data = try lowerZcuData(wasm, pt, uav); + wasm.uavs_obj.values()[uavs_i] = zcu_data; } } @@ -906,6 +959,51 @@ pub const ZcuFunc = union { return &wasm.zcu_funcs.values()[@backingInt(i)]; } + pub fn flags(i: @This(), wasm: *const Wasm) SymbolFlags { + const zcu = wasm.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const ip_index = i.key(wasm).*; + switch (ip.indexToKey(ip_index)) { + .func => |func| { + const nav = ip.getNav(func.owner_nav); + if (nav.getExtern(ip)) |ext| { + const name_slice = ext.name.toSlice(ip); + const name_string = wasm.getExistingString(name_slice).?; + return .{ + .binding = switch (ext.linkage) { + .internal => .local, + .strong => .strong, + .weak => .weak, + .link_once => @panic("TODO: COMDAT"), + }, + .visibility_hidden = switch (ext.visibility) { + .default => false, + .hidden => true, + .protected => false, + }, + .undefined = false, + .exported = wasm.missing_exports.contains(name_string), + .explicit_name = false, + .no_strip = false, + .tls = ext.is_threadlocal, + .absolute = false, + }; + } else { + return .{ + .binding = .local, + .tls = nav.resolved.?.@"threadlocal", + }; + } + }, + .enum_type => { + return .{ + .binding = .local, + }; + }, + else => unreachable, + } + } + pub fn name(i: @This(), wasm: *const Wasm) [:0]const u8 { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; @@ -1034,6 +1132,15 @@ pub const FunctionImport = extern struct { return pack(wasm, .{ .object_function = object_function }); } + pub fn flags(r: Resolution, wasm: *Wasm) SymbolFlags { + return switch (unpack(r, wasm)) { + .unresolved => unreachable, + .__wasm_apply_global_tls_relocs, .__wasm_call_ctors, .__wasm_init_memory, .__wasm_init_tls => unreachable, + .object_function => |i| i.ptr(wasm).flags, + .zcu_func => |i| i.flags(wasm), + }; + } + pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool { return switch (r.unpack(wasm)) { .unresolved, .zcu_func => true, @@ -1136,6 +1243,7 @@ pub const GlobalImport = extern struct { __tls_base, __tls_size, // Next, index into `object_globals`. + // Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object. // Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object. _, @@ -1150,6 +1258,8 @@ pub const GlobalImport = extern struct { __tls_base, __tls_size, object_global: ObjectGlobalIndex, + uav_exe: UavsExeIndex, + uav_obj: UavsObjIndex, nav_exe: NavsExeIndex, nav_obj: NavsObjIndex, }; @@ -1170,12 +1280,22 @@ pub const GlobalImport = extern struct { return .{ .object_global = @fromBackingInt(@intCast(object_global_index)) }; const comp = wasm.base.comp; const is_obj = comp.config.output_mode == .Obj; - const nav_index = object_global_index - wasm.object_globals.items.len; - return if (is_obj) .{ - .nav_obj = @fromBackingInt(@intCast(nav_index)), - } else .{ - .nav_exe = @fromBackingInt(@intCast(nav_index)), - }; + const uav_index = object_global_index - wasm.object_globals.items.len; + if (is_obj) { + if (uav_index < wasm.uavs_obj.entries.len) { + return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) }; + } + return .{ .nav_obj = @fromBackingInt( + @intCast(uav_index - wasm.uavs_obj.entries.len), + ) }; + } else { + if (uav_index < wasm.uavs_exe.entries.len) { + return .{ .uav_exe = @fromBackingInt(@intCast(uav_index)) }; + } + return .{ .nav_exe = @fromBackingInt( + @intCast(uav_index - wasm.uavs_exe.entries.len), + ) }; + } }, }; } @@ -1190,11 +1310,29 @@ pub const GlobalImport = extern struct { .__tls_base => .__tls_base, .__tls_size => .__tls_size, .object_global => |i| @fromBackingInt(@intCast(first_object_global + @backingInt(i))), - .nav_obj => |i| @fromBackingInt(@intCast(first_object_global + wasm.object_globals.items.len + @backingInt(i))), - .nav_exe => |i| @fromBackingInt(@intCast(first_object_global + wasm.object_globals.items.len + @backingInt(i))), + inline .uav_obj, .uav_exe => |i| @fromBackingInt(@intCast( + first_object_global + wasm.object_globals.items.len + @backingInt(i), + )), + .nav_obj => |i| @fromBackingInt(@intCast( + first_object_global + wasm.object_globals.items.len + + wasm.uavs_obj.entries.len + @backingInt(i), + )), + .nav_exe => |i| @fromBackingInt(@intCast( + first_object_global + wasm.object_globals.items.len + + wasm.uavs_exe.entries.len + @backingInt(i), + )), }; } + pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution { + const is_obj = wasm.base.comp.config.output_mode == .Obj; + return pack(wasm, if (is_obj) .{ + .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)), + } else .{ + .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)), + }); + } + pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution { const comp = wasm.base.comp; const is_obj = comp.config.output_mode == .Obj; @@ -1209,7 +1347,22 @@ pub const GlobalImport = extern struct { return pack(wasm, .{ .object_global = object_global }); } - pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 { + pub fn flags(r: Resolution, wasm: *const Wasm) SymbolFlags { + return switch (unpack(r, wasm)) { + .unresolved, + .__heap_base, + .__heap_end, + .__stack_pointer, + .__tls_align, + .__tls_base, + .__tls_size, + => unreachable, + .object_global => |i| i.ptr(wasm).flags, + .uav_obj, .uav_exe, .nav_obj, .nav_exe => unreachable, + }; + } + + pub fn name(r: Resolution, wasm: *const Wasm, buf: []u8) ?[]const u8 { return switch (unpack(r, wasm)) { .unresolved => unreachable, .__heap_base => @tagName(Unpacked.__heap_base), @@ -1219,6 +1372,11 @@ pub const GlobalImport = extern struct { .__tls_base => @tagName(Unpacked.__tls_base), .__tls_size => @tagName(Unpacked.__tls_size), .object_global => |i| i.name(wasm).slice(wasm), + inline .uav_obj, .uav_exe => |i| std.fmt.bufPrint( + buf, + "__anon_{d}", + .{@backingInt(i.key(wasm).*)}, + ) catch unreachable, .nav_obj => |i| i.name(wasm), .nav_exe => |i| i.name(wasm), }; @@ -1349,6 +1507,22 @@ pub const TableImport = extern struct { return pack(.{ .object_table = object_table }); } + pub fn name(r: Resolution, wasm: *const Wasm) ?[]const u8 { + return switch (unpack(r)) { + .unresolved => unreachable, + .__indirect_function_table => @tagName(Unpacked.__indirect_function_table), + .object_table => |i| i.ptr(wasm).name.slice(wasm), + }; + } + + pub fn flags(r: Resolution, wasm: *const Wasm) SymbolFlags { + return switch (unpack(r)) { + .unresolved => unreachable, + .__indirect_function_table => unreachable, + .object_table => |i| i.ptr(wasm).flags, + }; + } + pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType { return switch (unpack(r)) { .unresolved => unreachable, @@ -1602,6 +1776,8 @@ pub const ObjectDataImport = extern struct { unresolved, __zig_error_names, __zig_error_name_table, + __zig_tag_names, + __zig_tag_name_table, __heap_base, __heap_end, /// Next, an `ObjectData.Index`. @@ -1615,6 +1791,8 @@ pub const ObjectDataImport = extern struct { unresolved, __zig_error_names, __zig_error_name_table, + __zig_tag_names, + __zig_tag_name_table, __heap_base, __heap_end, object: ObjectData.Index, @@ -1629,6 +1807,8 @@ pub const ObjectDataImport = extern struct { .unresolved => .unresolved, .__zig_error_names => .__zig_error_names, .__zig_error_name_table => .__zig_error_name_table, + .__zig_tag_names => .__zig_tag_names, + .__zig_tag_name_table => .__zig_tag_name_table, .__heap_base => .__heap_base, .__heap_end => .__heap_end, _ => { @@ -1665,6 +1845,8 @@ pub const ObjectDataImport = extern struct { .unresolved => .unresolved, .__zig_error_names => .__zig_error_names, .__zig_error_name_table => .__zig_error_name_table, + .__zig_tag_names => .__zig_tag_names, + .__zig_tag_name_table => .__zig_tag_name_table, .__heap_base => .__heap_base, .__heap_end => .__heap_end, .object => |i| @fromBackingInt(@intCast(first_object + @backingInt(i))), @@ -1678,12 +1860,32 @@ pub const ObjectDataImport = extern struct { return pack(wasm, .{ .object = object_data_index }); } + pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution { + const is_obj = wasm.base.comp.config.output_mode == .Obj; + return pack(wasm, if (is_obj) .{ + .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)), + } else .{ + .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)), + }); + } + + pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution { + const is_obj = wasm.base.comp.config.output_mode == .Obj; + return pack(wasm, if (is_obj) .{ + .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)), + } else .{ + .nav_exe = @fromBackingInt(@intCast(wasm.navs_exe.getIndex(nav_index).?)), + }); + } + pub fn objectDataSegment(r: Resolution, wasm: *const Wasm) ?ObjectDataSegment.Index { return switch (unpack(r, wasm)) { .unresolved => unreachable, .object => |i| i.ptr(wasm).segment, .__zig_error_names, .__zig_error_name_table, + .__zig_tag_names, + .__zig_tag_name_table, .__heap_base, .__heap_end, .uav_exe, @@ -1706,12 +1908,107 @@ pub const ObjectDataImport = extern struct { }, .__zig_error_names => .{ .segment = .__zig_error_names, .offset = 0 }, .__zig_error_name_table => .{ .segment = .__zig_error_name_table, .offset = 0 }, + .__zig_tag_names => .{ .segment = .__zig_tag_names, .offset = 0 }, + .__zig_tag_name_table => .{ .segment = .__zig_tag_name_table, .offset = 0 }, .__heap_base => .{ .segment = .__heap_base, .offset = 0 }, .__heap_end => .{ .segment = .__heap_end, .offset = 0 }, - .uav_exe => @panic("TODO"), - .uav_obj => @panic("TODO"), - .nav_exe => @panic("TODO"), - .nav_obj => @panic("TODO"), + .uav_exe => |i| .{ .segment = .pack(wasm, .{ .uav_exe = i }), .offset = 0 }, + .uav_obj => |i| .{ .segment = .pack(wasm, .{ .uav_obj = i }), .offset = 0 }, + .nav_exe => |i| .{ .segment = .pack(wasm, .{ .nav_exe = i }), .offset = 0 }, + .nav_obj => |i| .{ .segment = .pack(wasm, .{ .nav_obj = i }), .offset = 0 }, + }; + } + + pub fn flags(r: Resolution, wasm: *const Wasm) SymbolFlags { + return switch (unpack(r, wasm)) { + .unresolved => unreachable, + .__zig_error_names, + .__zig_error_name_table, + .__zig_tag_names, + .__zig_tag_name_table, + => .{ .binding = .local }, + .__heap_base, + .__heap_end, + => unreachable, + .object => |i| i.ptr(wasm).flags, + inline .nav_exe, .nav_obj => |i| { + const zcu = wasm.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const nav = ip.getNav(i.key(wasm).*); + if (nav.getExtern(ip)) |ext| { + const name_slice = ext.name.toSlice(ip); + const name_string = wasm.getExistingString(name_slice).?; + return .{ + .binding = switch (ext.linkage) { + .internal => .local, + .strong => .strong, + .weak => .weak, + .link_once => @panic("TODO: COMDAT"), + }, + .visibility_hidden = switch (ext.visibility) { + .default => false, + .hidden => true, + .protected => false, + }, + .undefined = false, + .exported = wasm.missing_exports.contains(name_string), + .explicit_name = false, + .no_strip = false, + .tls = ext.is_threadlocal, + .absolute = false, + }; + } else { + return .{ + .binding = .local, + .tls = nav.resolved.?.@"threadlocal", + }; + } + }, + .uav_exe, .uav_obj => .{ .binding = .local }, + }; + } + + pub fn name(r: Resolution, wasm: *const Wasm, buf: []u8) []const u8 { + return switch (unpack(r, wasm)) { + .unresolved => unreachable, + .object => |i| i.ptr(wasm).name.slice(wasm), + .__zig_error_names => @tagName(.__zig_error_names), + .__zig_error_name_table => @tagName(.__zig_error_name_table), + .__zig_tag_names => @tagName(.__zig_tag_names), + .__zig_tag_name_table => @tagName(.__zig_tag_name_table), + .__heap_base => @tagName(.__heap_base), + .__heap_end => @tagName(.__heap_end), + inline .uav_exe, .uav_obj => |i| std.fmt.bufPrint( + buf, + "__anon_{d}", + .{@backingInt(i.key(wasm).*)}, + ) catch unreachable, + inline .nav_exe, .nav_obj => |i| i.name(wasm), + }; + } + + pub fn size(r: Resolution, wasm: *const Wasm) u32 { + return switch (unpack(r, wasm)) { + .unresolved => unreachable, + .__zig_error_names => @intCast(wasm.error_name_bytes.items.len), + .__zig_error_name_table => { + const comp = wasm.base.comp; + const zcu = comp.zcu.?; + const errors_len = wasm.error_name_offs.items.len; + const elem_size = Zcu.Type.slice_const_u8_sentinel_0.abiSize(zcu); + return @intCast(errors_len * elem_size); + }, + .__zig_tag_names => @intCast(wasm.tag_name_bytes.items.len), + .__zig_tag_name_table => { + const comp = wasm.base.comp; + const zcu = comp.zcu.?; + const table_len = wasm.tag_name_offs.items.len; + const elem_size = Zcu.Type.slice_const_u8_sentinel_0.abiSize(zcu); + return @intCast(table_len * elem_size); + }, + .__heap_base, .__heap_end => wasm.pointerSize(), + .object => |i| i.ptr(wasm).size, + inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len, }; } }; @@ -1910,6 +2207,38 @@ pub const DataSegmentId = enum(u32) { }; } + pub fn isStrings(id: DataSegmentId, wasm: *const Wasm) bool { + return switch (unpack(id, wasm)) { + .__zig_error_names, .__zig_tag_names => true, + + .__zig_error_name_table, + .__zig_tag_name_table, + .__heap_base, + .__heap_end, + => false, + + .object => |i| i.ptr(wasm).flags.strings, + .uav_exe, .uav_obj => false, + .nav_exe, .nav_obj => false, + }; + } + + pub fn isRetain(id: DataSegmentId, wasm: *const Wasm) bool { + return switch (unpack(id, wasm)) { + .__zig_error_names, + .__zig_error_name_table, + .__zig_tag_names, + .__zig_tag_name_table, + .__heap_base, + .__heap_end, + => false, + + .object => |i| i.ptr(wasm).flags.retain, + .uav_exe, .uav_obj => false, + .nav_exe, .nav_obj => false, + }; + } + pub fn isBss(id: DataSegmentId, wasm: *const Wasm) bool { return id.category(wasm) == .zero; } @@ -2181,6 +2510,7 @@ const PreloadedStrings = struct { _initialize: String, _start: String, memory: String, + env: String, }; /// Index into string_bytes @@ -2209,14 +2539,14 @@ pub const String = enum(u32) { } pub fn hash(_: @This(), adapted_key: []const u8) u64 { - assert(mem.indexOfScalar(u8, adapted_key, 0) == null); + assert(mem.findScalar(u8, adapted_key, 0) == null); return std.hash_map.hashString(adapted_key); } }; pub fn slice(index: String, wasm: *const Wasm) [:0]const u8 { const start_slice = wasm.string_bytes.items[@backingInt(index)..]; - return start_slice[0..mem.indexOfScalar(u8, start_slice, 0).? :0]; + return start_slice[0..mem.findScalar(u8, start_slice, 0).? :0]; } pub fn toOptional(i: String) OptionalString { @@ -2262,6 +2592,34 @@ pub const ZcuImportIndex = enum(u32) { return &wasm.imports.keys()[@backingInt(index)]; } + pub fn flags(index: ZcuImportIndex, wasm: *const Wasm) SymbolFlags { + const zcu = wasm.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const nav_index = index.ptr(wasm).*; + const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern"; + const name_slice = ext.name.toSlice(ip); + const name_string = wasm.getExistingString(name_slice).?; + return .{ + .binding = switch (ext.linkage) { + .internal => .local, + .strong => .strong, + .weak => .weak, + .link_once => @panic("TODO: COMDAT"), + }, + .visibility_hidden = switch (ext.visibility) { + .default => false, + .hidden => true, + .protected => false, + }, + .undefined = true, + .exported = wasm.missing_exports.contains(name_string), + .explicit_name = false, + .no_strip = false, + .tls = ext.is_threadlocal, + .absolute = false, + }; + } + pub fn importName(index: ZcuImportIndex, wasm: *const Wasm) String { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; @@ -2348,6 +2706,13 @@ pub const FunctionImportId = enum(u32) { } } + pub fn flags(id: FunctionImportId, wasm: *const Wasm) SymbolFlags { + return switch (id.unpack(wasm)) { + .object_function_import => |i| i.value(wasm).flags, + .zcu_import => |i| i.flags(wasm), + }; + } + pub fn importName(id: FunctionImportId, wasm: *const Wasm) String { return switch (unpack(id, wasm)) { inline .object_function_import, .zcu_import => |i| i.importName(wasm), @@ -2385,38 +2750,61 @@ pub const FunctionImportId = enum(u32) { } }; -/// 0. Index into `object_global_imports`. -/// 1. Index into `imports`. +/// 0. `__stack_pointer`. +/// 1. Index into `object_global_imports`. +/// 2. Index into `imports`. pub const GlobalImportId = enum(u32) { + __stack_pointer, _, pub const Unpacked = union(enum) { + __stack_pointer, object_global_import: GlobalImport.Index, zcu_import: ZcuImportIndex, }; pub fn pack(unpacked: Unpacked, wasm: *const Wasm) GlobalImportId { return switch (unpacked) { - .object_global_import => |i| @fromBackingInt(@intCast(@backingInt(i))), - .zcu_import => |i| @fromBackingInt(@intCast(@backingInt(i) + wasm.object_global_imports.entries.len)), + .__stack_pointer => .__stack_pointer, + .object_global_import => |i| @fromBackingInt(@intCast(@backingInt(i) + 1)), + .zcu_import => |i| @fromBackingInt(@intCast(@backingInt(i) + wasm.object_global_imports.entries.len + 1)), }; } pub fn unpack(id: GlobalImportId, wasm: *const Wasm) Unpacked { - const i = @backingInt(id); - if (i < wasm.object_global_imports.entries.len) return .{ .object_global_import = @fromBackingInt(@intCast(i)) }; - const zcu_import_i = i - wasm.object_global_imports.entries.len; - return .{ .zcu_import = @fromBackingInt(@intCast(zcu_import_i)) }; + return switch (id) { + .__stack_pointer => .__stack_pointer, + _ => { + const i = @backingInt(id) - 1; + if (i < wasm.object_global_imports.entries.len) { + return .{ .object_global_import = @fromBackingInt(@intCast(i)) }; + } + const zcu_import_i = i - wasm.object_global_imports.entries.len; + return .{ .zcu_import = @fromBackingInt(@intCast(zcu_import_i)) }; + }, + }; } pub fn fromObject(object_global_import: GlobalImport.Index, wasm: *const Wasm) GlobalImportId { return pack(.{ .object_global_import = object_global_import }, wasm); } + pub fn flags(id: GlobalImportId, wasm: *const Wasm) SymbolFlags { + return switch (id.unpack(wasm)) { + .__stack_pointer => .{ + .binding = .strong, + .undefined = true, + }, + .object_global_import => |i| i.value(wasm).flags, + .zcu_import => |i| i.flags(wasm), + }; + } + /// This function is allowed O(N) lookup because it is only called during /// diagnostic generation. pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation { switch (id.unpack(wasm)) { + .__stack_pointer => return .zig_object_nofile, .object_global_import => |obj_global_index| { // TODO binary search for (wasm.objects.items, 0..) |o, i| { @@ -2433,18 +2821,28 @@ pub const GlobalImportId = enum(u32) { pub fn importName(id: GlobalImportId, wasm: *const Wasm) String { return switch (unpack(id, wasm)) { + .__stack_pointer => wasm.preloaded_strings.__stack_pointer, inline .object_global_import, .zcu_import => |i| i.importName(wasm), }; } pub fn moduleName(id: GlobalImportId, wasm: *const Wasm) OptionalString { return switch (unpack(id, wasm)) { + .__stack_pointer => wasm.preloaded_strings.env.toOptional(), inline .object_global_import, .zcu_import => |i| i.moduleName(wasm), }; } pub fn globalType(id: GlobalImportId, wasm: *Wasm) ObjectGlobal.Type { return switch (unpack(id, wasm)) { + .__stack_pointer => .{ + .valtype = switch (wasm.pointerSize()) { + 4 => .i32, + 8 => .i64, + else => unreachable, + }, + .mutable = true, + }, inline .object_global_import, .zcu_import => |i| i.globalType(wasm), }; } @@ -2482,6 +2880,13 @@ pub const DataImportId = enum(u32) { return pack(.{ .object_data_import = object_data_import }, wasm); } + pub fn flags(id: DataImportId, wasm: *const Wasm) SymbolFlags { + return switch (id.unpack(wasm)) { + .object_data_import => |i| i.value(wasm).flags, + .zcu_import => |i| i.flags(wasm), + }; + } + pub fn sourceLocation(id: DataImportId, wasm: *const Wasm) SourceLocation { switch (id.unpack(wasm)) { .object_data_import => |obj_data_index| { @@ -2499,33 +2904,42 @@ pub const DataImportId = enum(u32) { } }; -/// Index into `Wasm.symbol_table`. -pub const SymbolTableIndex = enum(u32) { - _, - - pub fn key(i: @This(), wasm: *const Wasm) *String { - return &wasm.symbol_table.keys()[@backingInt(i)]; - } -}; - -pub const OutReloc = struct { +pub const ZcuRelocation = struct { tag: Object.RelocationType, offset: u32, pointee: Pointee, addend: i32, - pub const Pointee = union { - symbol_index: SymbolTableIndex, + pub const Pointee = union(enum) { + function_nav: InternPool.Nav.Index, + function_name: String, + tag_function: InternPool.Index, + data_uav: InternPool.Index, + data_nav: InternPool.Nav.Index, + data_resolution: ObjectDataImport.Resolution, + stack_pointer, type_index: FunctionType.Index, }; pub const Slice = extern struct { - /// Index into `out_relocs`. + /// Index into `zcu_relocations`. off: u32, len: u32, - pub fn slice(s: Slice, wasm: *const Wasm) []OutReloc { - return wasm.relocations.items[s.off..][0..s.len]; + pub fn tags(s: Slice, wasm: *const Wasm) []const Object.RelocationType { + return wasm.zcu_relocations.items(.tag)[s.off..][0..s.len]; + } + + pub fn offsets(s: Slice, wasm: *const Wasm) []const u32 { + return wasm.zcu_relocations.items(.offset)[s.off..][0..s.len]; + } + + pub fn pointees(s: Slice, wasm: *const Wasm) []const Pointee { + return wasm.zcu_relocations.items(.pointee)[s.off..][0..s.len]; + } + + pub fn addends(s: Slice, wasm: *const Wasm) []const i32 { + return wasm.zcu_relocations.items(.addend)[s.off..][0..s.len]; } }; }; @@ -3137,9 +3551,9 @@ pub fn deinit(wasm: *Wasm) void { wasm.table_imports.deinit(gpa); wasm.tables.deinit(gpa); wasm.data_imports.deinit(gpa); + wasm.datas.deinit(gpa); wasm.data_segments.deinit(gpa); - wasm.symbol_table.deinit(gpa); - wasm.out_relocs.deinit(gpa); + wasm.zcu_relocations.deinit(gpa); wasm.uav_fixups.deinit(gpa); wasm.nav_fixups.deinit(gpa); wasm.func_table_fixups.deinit(gpa); @@ -3351,6 +3765,25 @@ pub fn updateExports( const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; + const is_obj = wasm.base.comp.config.output_mode == .Obj; + switch (exported) { + .nav => {}, // handled in updateNav + .uav => |uav_index| { // export may be the only reference + const zds: ZcuDataStarts = .init(wasm); + if (is_obj) { + const gop = try wasm.uavs_obj.getOrPut(gpa, uav_index); + if (!gop.found_existing) gop.value_ptr.* = undefined; + } else { + const gop = try wasm.uavs_exe.getOrPut(gpa, uav_index); + if (!gop.found_existing) gop.value_ptr.* = .{ + .code = undefined, + .count = 0, + }; + gop.value_ptr.count += 1; + } + try zds.finish(wasm, pt); + }, + } for (export_indices) |export_idx| { const exp = export_idx.ptr(zcu); const name_slice = exp.opts.name.toSlice(ip); @@ -3443,7 +3876,11 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void { // Zig always depends on a stack pointer global. // If emitting an object, it's an import. Otherwise, the linker synthesizes it. if (is_obj) { - @panic("TODO"); + try wasm.global_imports.putNoClobber( + gpa, + wasm.preloaded_strings.__stack_pointer, + .__stack_pointer, + ); } else { try wasm.globals.put(gpa, .__stack_pointer, {}); assert(wasm.globals.entries.len - 1 == @backingInt(GlobalIndex.stack_pointer)); @@ -3453,7 +3890,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void { // These loops do both recursive marking of alive symbols well as checking for undefined symbols. // At the end, output functions and globals will be populated. for (wasm.object_function_imports.keys(), wasm.object_function_imports.values(), 0..) |name, *import, i| { - if (import.flags.isIncluded(rdynamic)) { + if (import.flags.isIncluded(rdynamic, is_obj)) { try markFunctionImport(wasm, name, import, @fromBackingInt(@intCast(i))); } } @@ -3467,7 +3904,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void { wasm.functions_end_prelink = @intCast(wasm.functions.entries.len); for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| { - if (import.flags.isIncluded(rdynamic)) { + if (import.flags.isIncluded(rdynamic, is_obj)) { try markGlobalImport(wasm, name, import, @fromBackingInt(@intCast(i))); } } @@ -3475,13 +3912,13 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void { wasm.global_exports_len = @intCast(wasm.global_exports.items.len); for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| { - if (import.flags.isIncluded(rdynamic)) { + if (import.flags.isIncluded(rdynamic, is_obj)) { try markTableImport(wasm, name, import, @fromBackingInt(@intCast(i))); } } for (wasm.object_data_imports.keys(), wasm.object_data_imports.values(), 0..) |name, *import, i| { - if (import.flags.isIncluded(rdynamic)) { + if (import.flags.isIncluded(rdynamic, is_obj)) { try markDataImport(wasm, name, import, @fromBackingInt(@intCast(i))); } } @@ -3512,18 +3949,23 @@ pub fn markFunctionImport( const comp = wasm.base.comp; const gpa = comp.gpa; + const is_obj = comp.config.output_mode == .Obj; try wasm.functions.ensureUnusedCapacity(gpa, 1); if (import.resolution == .unresolved) { - if (name == wasm.preloaded_strings.__wasm_init_memory) { - try wasm.resolveFunctionSynthetic(import, .__wasm_init_memory, &.{}, &.{}); - } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) { - try wasm.resolveFunctionSynthetic(import, .__wasm_apply_global_tls_relocs, &.{}, &.{}); - } else if (name == wasm.preloaded_strings.__wasm_call_ctors) { - try wasm.resolveFunctionSynthetic(import, .__wasm_call_ctors, &.{}, &.{}); - } else if (name == wasm.preloaded_strings.__wasm_init_tls) { - try wasm.resolveFunctionSynthetic(import, .__wasm_init_tls, &.{.i32}, &.{}); + if (!is_obj) { + if (name == wasm.preloaded_strings.__wasm_init_memory) { + try wasm.resolveFunctionSynthetic(import, .__wasm_init_memory, &.{}, &.{}); + } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) { + try wasm.resolveFunctionSynthetic(import, .__wasm_apply_global_tls_relocs, &.{}, &.{}); + } else if (name == wasm.preloaded_strings.__wasm_call_ctors) { + try wasm.resolveFunctionSynthetic(import, .__wasm_call_ctors, &.{}, &.{}); + } else if (name == wasm.preloaded_strings.__wasm_init_tls) { + try wasm.resolveFunctionSynthetic(import, .__wasm_init_tls, &.{.i32}, &.{}); + } else { + try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm)); + } } else { try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm)); } @@ -3576,28 +4018,33 @@ fn markGlobalImport( const comp = wasm.base.comp; const gpa = comp.gpa; + const is_obj = comp.config.output_mode == .Obj; try wasm.globals.ensureUnusedCapacity(gpa, 1); if (import.resolution == .unresolved) { - if (name == wasm.preloaded_strings.__heap_base) { - import.resolution = .__heap_base; - wasm.globals.putAssumeCapacity(.__heap_base, {}); - } else if (name == wasm.preloaded_strings.__heap_end) { - import.resolution = .__heap_end; - wasm.globals.putAssumeCapacity(.__heap_end, {}); - } else if (name == wasm.preloaded_strings.__stack_pointer) { - import.resolution = .__stack_pointer; - wasm.globals.putAssumeCapacity(.__stack_pointer, {}); - } else if (name == wasm.preloaded_strings.__tls_align) { - import.resolution = .__tls_align; - wasm.globals.putAssumeCapacity(.__tls_align, {}); - } else if (name == wasm.preloaded_strings.__tls_base) { - import.resolution = .__tls_base; - wasm.globals.putAssumeCapacity(.__tls_base, {}); - } else if (name == wasm.preloaded_strings.__tls_size) { - import.resolution = .__tls_size; - wasm.globals.putAssumeCapacity(.__tls_size, {}); + if (!is_obj) { + if (name == wasm.preloaded_strings.__heap_base) { + import.resolution = .__heap_base; + wasm.globals.putAssumeCapacity(.__heap_base, {}); + } else if (name == wasm.preloaded_strings.__heap_end) { + import.resolution = .__heap_end; + wasm.globals.putAssumeCapacity(.__heap_end, {}); + } else if (name == wasm.preloaded_strings.__stack_pointer) { + import.resolution = .__stack_pointer; + wasm.globals.putAssumeCapacity(.__stack_pointer, {}); + } else if (name == wasm.preloaded_strings.__tls_align) { + import.resolution = .__tls_align; + wasm.globals.putAssumeCapacity(.__tls_align, {}); + } else if (name == wasm.preloaded_strings.__tls_base) { + import.resolution = .__tls_base; + wasm.globals.putAssumeCapacity(.__tls_base, {}); + } else if (name == wasm.preloaded_strings.__tls_size) { + import.resolution = .__tls_size; + wasm.globals.putAssumeCapacity(.__tls_size, {}); + } else { + try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm)); + } } else { try wasm.global_imports.put(gpa, name, .fromObject(global_index, wasm)); } @@ -3625,7 +4072,7 @@ fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex, override_export: bool) link.Err try wasm.markRelocations(global.relocations(wasm)); } -fn markTableImport( +pub fn markTableImport( wasm: *Wasm, name: String, import: *TableImport, @@ -3636,13 +4083,18 @@ fn markTableImport( const comp = wasm.base.comp; const gpa = comp.gpa; + const is_obj = comp.config.output_mode == .Obj; try wasm.tables.ensureUnusedCapacity(gpa, 1); if (import.resolution == .unresolved) { - if (name == wasm.preloaded_strings.__indirect_function_table) { - import.resolution = .__indirect_function_table; - wasm.tables.putAssumeCapacity(.__indirect_function_table, {}); + if (!is_obj) { + if (name == wasm.preloaded_strings.__indirect_function_table) { + import.resolution = .__indirect_function_table; + wasm.tables.putAssumeCapacity(.__indirect_function_table, {}); + } else { + try wasm.table_imports.put(gpa, name, table_index); + } } else { try wasm.table_imports.put(gpa, name, table_index); } @@ -3676,22 +4128,38 @@ pub fn markDataImport( const comp = wasm.base.comp; const gpa = comp.gpa; + const is_obj = comp.config.output_mode == .Obj; + + try wasm.data_segments.ensureUnusedCapacity(gpa, 1); if (import.resolution == .unresolved) { - if (name == wasm.preloaded_strings.__heap_base) { - import.resolution = .__heap_base; - wasm.data_segments.putAssumeCapacity(.__heap_base, {}); - } else if (name == wasm.preloaded_strings.__heap_end) { - import.resolution = .__heap_end; - wasm.data_segments.putAssumeCapacity(.__heap_end, {}); + if (!is_obj) { + if (name == wasm.preloaded_strings.__heap_base) { + import.resolution = .__heap_base; + wasm.data_segments.putAssumeCapacity(.__heap_base, {}); + } else if (name == wasm.preloaded_strings.__heap_end) { + import.resolution = .__heap_end; + wasm.data_segments.putAssumeCapacity(.__heap_end, {}); + } else { + try wasm.data_imports.put(gpa, name, .fromObject(data_index, wasm)); + } } else { try wasm.data_imports.put(gpa, name, .fromObject(data_index, wasm)); } - } else if (import.resolution.objectDataSegment(wasm)) |segment_index| { - try markDataSegment(wasm, segment_index); + } else switch (import.resolution.unpack(wasm)) { + .object => |object_data_index| try markData(wasm, object_data_index), + else => {}, } } +fn markData(wasm: *Wasm, i: ObjectData.Index) link.Error!void { + const gpa = wasm.base.comp.gpa; + const gop = try wasm.datas.getOrPut(gpa, .fromObjectDataIndex(wasm, i)); + if (gop.found_existing) return; + + try markDataSegment(wasm, i.ptr(wasm).segment); +} + fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Error!void { const gpa = wasm.base.comp.gpa; for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, pointee, offset| { @@ -3782,7 +4250,7 @@ fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.Err .memory_addr_tls_sleb, .memory_addr_locrel_i32, .memory_addr_tls_sleb64, - => try markDataSegment(wasm, pointee.data.ptr(wasm).segment), + => try markData(wasm, pointee.data), .type_index_leb => continue, } @@ -3829,7 +4297,13 @@ pub fn flush( const hidden_function_exports_end_zcu: u32 = @intCast(wasm.hidden_function_exports.entries.len); defer wasm.hidden_function_exports.shrinkRetainingCapacity(hidden_function_exports_end_zcu); + const global_exports_end_zcu: u32 = @intCast(wasm.global_exports.items.len); + defer wasm.global_exports.shrinkRetainingCapacity(global_exports_end_zcu); + wasm.flush_buffer.clear(); + wasm.tag_name_bytes.clearRetainingCapacity(); + wasm.tag_name_offs.clearRetainingCapacity(); + wasm.tag_name_table_ref_count = 0; try wasm.flush_buffer.missing_exports.reinit(gpa, wasm.missing_exports.keys(), &.{}); try wasm.flush_buffer.function_imports.reinit(gpa, wasm.function_imports.keys(), wasm.function_imports.values()); try wasm.flush_buffer.global_imports.reinit(gpa, wasm.global_imports.keys(), wasm.global_imports.values()); @@ -3858,7 +4332,7 @@ pub fn internOptionalString(wasm: *Wasm, optional_bytes: ?[]const u8) Allocator. } pub fn internString(wasm: *Wasm, bytes: []const u8) Allocator.Error!String { - assert(mem.indexOfScalar(u8, bytes, 0) == null); + assert(mem.findScalar(u8, bytes, 0) == null); wasm.string_bytes_lock.lock(); defer wasm.string_bytes_lock.unlock(); const gpa = wasm.base.comp.gpa; @@ -3889,7 +4363,7 @@ pub fn internStringFmt(wasm: *Wasm, comptime format: []const u8, args: anytype) } pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String { - assert(mem.indexOfScalar(u8, bytes, 0) == null); + assert(mem.findScalar(u8, bytes, 0) == null); return wasm.string_table.getKeyAdapted(bytes, @as(String.TableIndexAdapter, .{ .bytes = wasm.string_bytes.items, })); @@ -3953,6 +4427,255 @@ pub fn getExistingFunctionType( }); } +fn internIntrinsicType( + wasm: *Wasm, + params: []const InternPool.Index, + return_type: Zcu.Type, +) Allocator.Error!FunctionType.Index { + const target = &wasm.base.comp.root_mod.resolved_target.result; + return wasm.internFunctionType(.{ .wasm_mvp = .{} }, params, return_type, false, target); +} + +pub fn intrinsicFunctionType(wasm: *Wasm, intrinsic: Mir.Intrinsic) Allocator.Error!FunctionType.Index { + return switch (intrinsic) { + .__addhf3 => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16), + .__addtf3 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128), + .__addxf3 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80), + .__ashlti3 => internIntrinsicType(wasm, &.{ .i128_type, .i32_type }, .i128), + .__ashrti3 => internIntrinsicType(wasm, &.{ .i128_type, .i32_type }, .i128), + .__bitreversedi2 => internIntrinsicType(wasm, &.{.u64_type}, .u64), + .__bitreversesi2 => internIntrinsicType(wasm, &.{.u32_type}, .u32), + .__bswapdi2 => internIntrinsicType(wasm, &.{.u64_type}, .u64), + .__bswapsi2 => internIntrinsicType(wasm, &.{.u32_type}, .u32), + .__ceilh => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__ceilx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__cosh => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__cosx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__divei5 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type }, .void), + .__divhf3 => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16), + .__divtf3 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128), + .__divti3 => internIntrinsicType(wasm, &.{ .i128_type, .i128_type }, .i128), + .__divxf3 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80), + .__eqtf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool), + .__eqxf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool), + .__exp2h => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__exp2x => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__exph => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__expx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__extenddftf2 => internIntrinsicType(wasm, &.{.f64_type}, .f128), + .__extenddfxf2 => internIntrinsicType(wasm, &.{.f64_type}, .f80), + .__extendhfsf2 => internIntrinsicType(wasm, &.{.f16_type}, .f32), + .__extendhftf2 => internIntrinsicType(wasm, &.{.f16_type}, .f128), + .__extendhfxf2 => internIntrinsicType(wasm, &.{.f16_type}, .f80), + .__extendsftf2 => internIntrinsicType(wasm, &.{.f32_type}, .f128), + .__extendsfxf2 => internIntrinsicType(wasm, &.{.f32_type}, .f80), + .__extendxftf2 => internIntrinsicType(wasm, &.{.f80_type}, .f128), + .__fabsh => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__fabsx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__fixdfdi => internIntrinsicType(wasm, &.{.f64_type}, .i64), + .__fixdfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f64_type }, .void), + .__fixdfsi => internIntrinsicType(wasm, &.{.f64_type}, .i32), + .__fixdfti => internIntrinsicType(wasm, &.{.f64_type}, .i128), + .__fixhfdi => internIntrinsicType(wasm, &.{.f16_type}, .i64), + .__fixhfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f16_type }, .void), + .__fixhfsi => internIntrinsicType(wasm, &.{.f16_type}, .i32), + .__fixhfti => internIntrinsicType(wasm, &.{.f16_type}, .i128), + .__fixsfdi => internIntrinsicType(wasm, &.{.f32_type}, .i64), + .__fixsfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f32_type }, .void), + .__fixsfsi => internIntrinsicType(wasm, &.{.f32_type}, .i32), + .__fixsfti => internIntrinsicType(wasm, &.{.f32_type}, .i128), + .__fixtfdi => internIntrinsicType(wasm, &.{.f128_type}, .i64), + .__fixtfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f128_type }, .void), + .__fixtfsi => internIntrinsicType(wasm, &.{.f128_type}, .i32), + .__fixtfti => internIntrinsicType(wasm, &.{.f128_type}, .i128), + .__fixunsdfdi => internIntrinsicType(wasm, &.{.f64_type}, .u64), + .__fixunsdfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f64_type }, .void), + .__fixunsdfsi => internIntrinsicType(wasm, &.{.f64_type}, .u32), + .__fixunsdfti => internIntrinsicType(wasm, &.{.f64_type}, .u128), + .__fixunshfdi => internIntrinsicType(wasm, &.{.f16_type}, .u64), + .__fixunshfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f16_type }, .void), + .__fixunshfsi => internIntrinsicType(wasm, &.{.f16_type}, .u32), + .__fixunshfti => internIntrinsicType(wasm, &.{.f16_type}, .u128), + .__fixunssfdi => internIntrinsicType(wasm, &.{.f32_type}, .u64), + .__fixunssfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f32_type }, .void), + .__fixunssfsi => internIntrinsicType(wasm, &.{.f32_type}, .u32), + .__fixunssfti => internIntrinsicType(wasm, &.{.f32_type}, .u128), + .__fixunstfdi => internIntrinsicType(wasm, &.{.f128_type}, .u64), + .__fixunstfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f128_type }, .void), + .__fixunstfsi => internIntrinsicType(wasm, &.{.f128_type}, .u32), + .__fixunstfti => internIntrinsicType(wasm, &.{.f128_type}, .u128), + .__fixunsxfdi => internIntrinsicType(wasm, &.{.f80_type}, .u64), + .__fixunsxfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f80_type }, .void), + .__fixunsxfsi => internIntrinsicType(wasm, &.{.f80_type}, .u32), + .__fixunsxfti => internIntrinsicType(wasm, &.{.f80_type}, .u128), + .__fixxfdi => internIntrinsicType(wasm, &.{.f80_type}, .i64), + .__fixxfei => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .f80_type }, .void), + .__fixxfsi => internIntrinsicType(wasm, &.{.f80_type}, .i32), + .__fixxfti => internIntrinsicType(wasm, &.{.f80_type}, .i128), + .__floatdidf => internIntrinsicType(wasm, &.{.i64_type}, .f64), + .__floatdihf => internIntrinsicType(wasm, &.{.i64_type}, .f16), + .__floatdisf => internIntrinsicType(wasm, &.{.i64_type}, .f32), + .__floatditf => internIntrinsicType(wasm, &.{.i64_type}, .f128), + .__floatdixf => internIntrinsicType(wasm, &.{.i64_type}, .f80), + .__floateidf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f64), + .__floateihf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f16), + .__floateisf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f32), + .__floateitf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f128), + .__floateixf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f80), + .__floatsidf => internIntrinsicType(wasm, &.{.i32_type}, .f64), + .__floatsihf => internIntrinsicType(wasm, &.{.i32_type}, .f16), + .__floatsisf => internIntrinsicType(wasm, &.{.i32_type}, .f32), + .__floatsitf => internIntrinsicType(wasm, &.{.i32_type}, .f128), + .__floatsixf => internIntrinsicType(wasm, &.{.i32_type}, .f80), + .__floattidf => internIntrinsicType(wasm, &.{.i128_type}, .f64), + .__floattihf => internIntrinsicType(wasm, &.{.i128_type}, .f16), + .__floattisf => internIntrinsicType(wasm, &.{.i128_type}, .f32), + .__floattitf => internIntrinsicType(wasm, &.{.i128_type}, .f128), + .__floattixf => internIntrinsicType(wasm, &.{.i128_type}, .f80), + .__floatundidf => internIntrinsicType(wasm, &.{.u64_type}, .f64), + .__floatundihf => internIntrinsicType(wasm, &.{.u64_type}, .f16), + .__floatundisf => internIntrinsicType(wasm, &.{.u64_type}, .f32), + .__floatunditf => internIntrinsicType(wasm, &.{.u64_type}, .f128), + .__floatundixf => internIntrinsicType(wasm, &.{.u64_type}, .f80), + .__floatuneidf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f64), + .__floatuneihf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f16), + .__floatuneisf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f32), + .__floatuneitf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f128), + .__floatuneixf => internIntrinsicType(wasm, &.{ .usize_type, .usize_type }, .f80), + .__floatunsidf => internIntrinsicType(wasm, &.{.u32_type}, .f64), + .__floatunsihf => internIntrinsicType(wasm, &.{.u32_type}, .f16), + .__floatunsisf => internIntrinsicType(wasm, &.{.u32_type}, .f32), + .__floatunsitf => internIntrinsicType(wasm, &.{.u32_type}, .f128), + .__floatunsixf => internIntrinsicType(wasm, &.{.u32_type}, .f80), + .__floatuntidf => internIntrinsicType(wasm, &.{.u128_type}, .f64), + .__floatuntihf => internIntrinsicType(wasm, &.{.u128_type}, .f16), + .__floatuntisf => internIntrinsicType(wasm, &.{.u128_type}, .f32), + .__floatuntitf => internIntrinsicType(wasm, &.{.u128_type}, .f128), + .__floatuntixf => internIntrinsicType(wasm, &.{.u128_type}, .f80), + .__floorh => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__floorx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__fmah => internIntrinsicType(wasm, &.{ .f16_type, .f16_type, .f16_type }, .f16), + .__fmax => internIntrinsicType(wasm, &.{ .f80_type, .f80_type, .f80_type }, .f80), + .__fmaxh => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16), + .__fmaxx => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80), + .__fminh => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16), + .__fminx => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80), + .__fmodh => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16), + .__fmodx => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80), + .__getf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool), + .__gexf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool), + .__gttf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool), + .__gtxf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool), + .__letf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool), + .__lexf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool), + .__log10h => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__log10x => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__log2h => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__log2x => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__logh => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__logx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__lshrti3 => internIntrinsicType(wasm, &.{ .i128_type, .i32_type }, .i128), + .__lttf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool), + .__ltxf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool), + .__modei5 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type }, .void), + .__modti3 => internIntrinsicType(wasm, &.{ .i128_type, .i128_type }, .i128), + .__mulhf3 => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16), + .__mulodi4 => internIntrinsicType(wasm, &.{ .i64_type, .i64_type, .usize_type }, .i64), + .__muloti4 => internIntrinsicType(wasm, &.{ .i128_type, .i128_type, .usize_type }, .i128), + .__multf3 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128), + .__multi3 => internIntrinsicType(wasm, &.{ .i128_type, .i128_type }, .i128), + .__mulxf3 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80), + .__netf2 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .bool), + .__nexf2 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .bool), + .__roundh => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__roundx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__sinh => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__sinx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__sqrth => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__sqrtx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__subhf3 => internIntrinsicType(wasm, &.{ .f16_type, .f16_type }, .f16), + .__subtf3 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128), + .__subxf3 => internIntrinsicType(wasm, &.{ .f80_type, .f80_type }, .f80), + .__tanh => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__tanx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__trunch => internIntrinsicType(wasm, &.{.f16_type}, .f16), + .__truncsfhf2 => internIntrinsicType(wasm, &.{.f32_type}, .f16), + .__trunctfdf2 => internIntrinsicType(wasm, &.{.f128_type}, .f64), + .__trunctfhf2 => internIntrinsicType(wasm, &.{.f128_type}, .f16), + .__trunctfsf2 => internIntrinsicType(wasm, &.{.f128_type}, .f32), + .__trunctfxf2 => internIntrinsicType(wasm, &.{.f128_type}, .f80), + .__truncx => internIntrinsicType(wasm, &.{.f80_type}, .f80), + .__truncxfdf2 => internIntrinsicType(wasm, &.{.f80_type}, .f64), + .__truncxfhf2 => internIntrinsicType(wasm, &.{.f80_type}, .f16), + .__truncxfsf2 => internIntrinsicType(wasm, &.{.f80_type}, .f32), + .__udivei5 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type }, .void), + .__udivti3 => internIntrinsicType(wasm, &.{ .u128_type, .u128_type }, .u128), + .__umodei5 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type }, .void), + .__umodti3 => internIntrinsicType(wasm, &.{ .u128_type, .u128_type }, .u128), + .ceilf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .cos => internIntrinsicType(wasm, &.{.f64_type}, .f64), + .cosf => internIntrinsicType(wasm, &.{.f32_type}, .f32), + .cosf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .exp => internIntrinsicType(wasm, &.{.f64_type}, .f64), + .exp2 => internIntrinsicType(wasm, &.{.f64_type}, .f64), + .exp2f => internIntrinsicType(wasm, &.{.f32_type}, .f32), + .exp2f128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .expf => internIntrinsicType(wasm, &.{.f32_type}, .f32), + .expf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .fabsf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .floorf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .fma => internIntrinsicType(wasm, &.{ .f64_type, .f64_type, .f64_type }, .f64), + .fmaf => internIntrinsicType(wasm, &.{ .f32_type, .f32_type, .f32_type }, .f32), + .fmaf128 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type, .f128_type }, .f128), + .fmax => internIntrinsicType(wasm, &.{ .f64_type, .f64_type }, .f64), + .fmaxf => internIntrinsicType(wasm, &.{ .f32_type, .f32_type }, .f32), + .fmaxf128 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128), + .fmin => internIntrinsicType(wasm, &.{ .f64_type, .f64_type }, .f64), + .fminf => internIntrinsicType(wasm, &.{ .f32_type, .f32_type }, .f32), + .fminf128 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128), + .fmod => internIntrinsicType(wasm, &.{ .f64_type, .f64_type }, .f64), + .fmodf => internIntrinsicType(wasm, &.{ .f32_type, .f32_type }, .f32), + .fmodf128 => internIntrinsicType(wasm, &.{ .f128_type, .f128_type }, .f128), + .log => internIntrinsicType(wasm, &.{.f64_type}, .f64), + .log10 => internIntrinsicType(wasm, &.{.f64_type}, .f64), + .log10f => internIntrinsicType(wasm, &.{.f32_type}, .f32), + .log10f128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .log2 => internIntrinsicType(wasm, &.{.f64_type}, .f64), + .log2f => internIntrinsicType(wasm, &.{.f32_type}, .f32), + .log2f128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .logf => internIntrinsicType(wasm, &.{.f32_type}, .f32), + .logf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .roundf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .sin => internIntrinsicType(wasm, &.{.f64_type}, .f64), + .sinf => internIntrinsicType(wasm, &.{.f32_type}, .f32), + .sinf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .sqrtf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .tan => internIntrinsicType(wasm, &.{.f64_type}, .f64), + .tanf => internIntrinsicType(wasm, &.{.f32_type}, .f32), + .tanf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .truncf128 => internIntrinsicType(wasm, &.{.f128_type}, .f128), + .memcpy => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type }, .usize), + .memmove => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type }, .usize), + .memset => internIntrinsicType(wasm, &.{ .usize_type, .i32_type, .usize_type }, .usize), + .__addo_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .bool_type, .u16_type }, .bool), + .__subo_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .bool_type, .u16_type }, .bool), + .__cmp_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .bool_type, .u16_type }, .i8), + .__and_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .u16_type }, .void), + .__or_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .u16_type }, .void), + .__xor_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .u16_type }, .void), + .__not_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .bool_type, .u16_type }, .void), + .__shlo_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .u16_type, .bool_type, .u16_type }, .bool), + .__shr_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .u16_type, .bool_type, .u16_type }, .void), + .__clz_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .u16_type }, .u16), + .__ctz_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .u16_type }, .u16), + .__popcount_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .u16_type }, .u16), + .__bitreverse_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .bool_type, .u16_type }, .void), + .__byteswap_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .bool_type, .u16_type }, .void), + .__mulo_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .usize_type, .bool_type, .u16_type }, .bool), + .__abs_limb64 => internIntrinsicType(wasm, &.{ .usize_type, .usize_type, .u16_type }, .void), + }; +} + pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr { const gpa = wasm.base.comp.gpa; // We can't use string table deduplication here since these expressions can @@ -3972,64 +4695,63 @@ pub fn addRelocatableDataPayload(wasm: *Wasm, bytes: []const u8) Allocator.Error }; } -pub fn uavSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex { +pub fn addNavReloc( + wasm: *Wasm, + reloc_offset: usize, + nav_index: InternPool.Nav.Index, + nav_ty: Zcu.Type, + addend: u32, +) !void { const comp = wasm.base.comp; - assert(comp.config.output_mode == .Obj); - const gpa = comp.gpa; - const name = try wasm.internStringFmt("__anon_{d}", .{@backingInt(ip_index)}); - const gop = try wasm.symbol_table.getOrPut(gpa, name); - gop.value_ptr.* = {}; - return @fromBackingInt(@intCast(gop.index)); -} - -pub fn navSymbolIndex(wasm: *Wasm, nav_index: InternPool.Nav.Index) Allocator.Error!SymbolTableIndex { - const comp = wasm.base.comp; - assert(comp.config.output_mode == .Obj); const zcu = comp.zcu.?; const ip = &zcu.intern_pool; const gpa = comp.gpa; - const nav = ip.getNav(nav_index); - const name = try wasm.internString(nav.fqn.toSlice(ip)); - const gop = try wasm.symbol_table.getOrPut(gpa, name); - gop.value_ptr.* = {}; - return @fromBackingInt(@intCast(gop.index)); -} -pub fn errorNameTableSymbolIndex(wasm: *Wasm) Allocator.Error!SymbolTableIndex { - const comp = wasm.base.comp; - assert(comp.config.output_mode == .Obj); - const gpa = comp.gpa; - const gop = try wasm.symbol_table.getOrPut(gpa, wasm.preloaded_strings.__zig_error_name_table); - gop.value_ptr.* = {}; - return @fromBackingInt(@intCast(gop.index)); -} + const is_obj = comp.config.output_mode == .Obj; -pub fn stackPointerSymbolIndex(wasm: *Wasm) Allocator.Error!SymbolTableIndex { - const comp = wasm.base.comp; - assert(comp.config.output_mode == .Obj); - const gpa = comp.gpa; - const gop = try wasm.symbol_table.getOrPut(gpa, wasm.preloaded_strings.__stack_pointer); - gop.value_ptr.* = {}; - return @fromBackingInt(@intCast(gop.index)); -} - -pub fn tagTableIndexSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex { - const comp = wasm.base.comp; - assert(comp.config.output_mode == .Obj); - const gpa = comp.gpa; - const name = try wasm.internStringFmt("__zig_tag_name_{d}", .{ip_index}); - const gop = try wasm.symbol_table.getOrPut(gpa, name); - gop.value_ptr.* = {}; - return @fromBackingInt(@intCast(gop.index)); -} - -pub fn symbolNameIndex(wasm: *Wasm, name: String) Allocator.Error!SymbolTableIndex { - const comp = wasm.base.comp; - assert(comp.config.output_mode == .Obj); - const gpa = comp.gpa; - const gop = try wasm.symbol_table.getOrPut(gpa, name); - gop.value_ptr.* = {}; - return @fromBackingInt(@intCast(gop.index)); + if (nav_ty.zigTypeTag(zcu) == .@"fn") { + const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index); + if (!gop.found_existing) gop.value_ptr.* = {}; + if (is_obj) { + assert(addend == 0); + try wasm.zcu_relocations.append(gpa, .{ + .offset = @intCast(reloc_offset), + .pointee = .{ .function_nav = nav_index }, + .tag = switch (wasm.pointerSize()) { + 4 => .table_index_i32, + 8 => .table_index_i64, + else => unreachable, + }, + .addend = 0, + }); + } else { + try wasm.func_table_fixups.append(gpa, .{ + .nav_index = nav_index, + .offset = @intCast(reloc_offset), + }); + } + } else { + if (is_obj) { + if (ip.getNav(nav_index).getExtern(ip) == null) _ = try wasm.refNavObj(nav_index); + try wasm.zcu_relocations.append(gpa, .{ + .offset = @intCast(reloc_offset), + .pointee = .{ .data_nav = nav_index }, + .tag = switch (wasm.pointerSize()) { + 4 => .memory_addr_i32, + 8 => .memory_addr_i64, + else => unreachable, + }, + .addend = @intCast(addend), + }); + } else { + try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1); + wasm.nav_fixups.appendAssumeCapacity(.{ + .nav_index = nav_index, + .offset = @intCast(reloc_offset), + .addend = addend, + }); + } + } } pub fn addUavReloc( @@ -4057,12 +4779,12 @@ pub fn addUavReloc( if (comp.config.output_mode == .Obj) { const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val); if (!gop.found_existing) gop.value_ptr.* = undefined; // to avoid recursion, `ZcuDataStarts` will lower the value later - try wasm.out_relocs.append(gpa, .{ + try wasm.zcu_relocations.append(gpa, .{ .offset = @intCast(reloc_offset), - .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav_val) }, + .pointee = .{ .data_uav = uav_val }, .tag = switch (wasm.pointerSize()) { - 32 => .memory_addr_i32, - 64 => .memory_addr_i64, + 4 => .memory_addr_i32, + 8 => .memory_addr_i64, else => unreachable, }, .addend = @intCast(addend), @@ -4085,7 +4807,7 @@ pub fn addUavReloc( pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex { const comp = wasm.base.comp; const gpa = comp.gpa; - assert(comp.config.output_mode != .Obj); + assert(comp.config.output_mode == .Obj); const gop = try wasm.navs_obj.getOrPut(gpa, nav_index); if (!gop.found_existing) gop.value_ptr.* = .{ // Lowering the value is delayed to avoid recursion. @@ -4113,7 +4835,7 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex { } /// Asserts it is called after `Flush.data_segments` is fully populated and sorted. -pub fn uavAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 { +pub fn uavAddr(wasm: *const Wasm, ip_index: InternPool.Index) u32 { assert(wasm.flush_buffer.memory_layout_finished); const comp = wasm.base.comp; assert(comp.config.output_mode != .Obj); @@ -4123,7 +4845,7 @@ pub fn uavAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 { } /// Asserts it is called after `Flush.data_segments` is fully populated and sorted. -pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 { +pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 { assert(wasm.flush_buffer.memory_layout_finished); const comp = wasm.base.comp; assert(comp.config.output_mode != .Obj); @@ -4139,23 +4861,34 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 { .@"extern" => |ext| if (wasm.getExistingString(ext.name.toSlice(ip))) |symbol_name| { if (wasm.object_data_imports.getPtr(symbol_name)) |import| { switch (import.resolution.unpack(wasm)) { - .unresolved => unreachable, + .unresolved => {}, .object => |object_data_index| { const object_data = object_data_index.ptr(wasm); const ds_id: DataSegmentId = .fromObjectDataSegment(wasm, object_data.segment); const segment_base_addr = wasm.flush_buffer.data_segments.get(ds_id).?; return segment_base_addr + object_data.offset; }, - .__zig_error_names => @panic("TODO"), - .__zig_error_name_table => @panic("TODO"), - .__heap_base => @panic("TODO"), - .__heap_end => @panic("TODO"), - .uav_exe => @panic("TODO"), - .uav_obj => @panic("TODO"), - .nav_exe => @panic("TODO"), - .nav_obj => @panic("TODO"), + .__heap_base, + .__heap_end, + .uav_exe, + .nav_exe, + => { + const data_loc = import.resolution.dataLoc(wasm); + return wasm.flush_buffer.data_segments.get(data_loc.segment).? + data_loc.offset; + }, + .__zig_error_names, + .__zig_error_name_table, + .__zig_tag_names, + .__zig_tag_name_table, + .uav_obj, + .nav_obj, + => unreachable, } } + if (wasm.flush_buffer.data_exports.get(symbol_name)) |symbol| { + const data_loc = symbol.resolution.dataLoc(wasm); + return wasm.flush_buffer.data_segments.get(data_loc.segment).? + data_loc.offset; + } }, else => {}, } @@ -4177,8 +4910,12 @@ pub fn tagIndexTableAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 { assert(comp.config.output_mode != .Obj); const f = &wasm.flush_buffer; const table_base_addr = f.data_segments.get(.__zig_tag_name_table).?; - const table_index = f.enum_tag_name_table.get(ip_index).?; - return table_base_addr + table_index * 8; + return table_base_addr + wasm.tagIndexTableOffset(ip_index); +} + +pub fn tagIndexTableOffset(wasm: *const Wasm, ip_index: InternPool.Index) u32 { + const table_index = wasm.flush_buffer.enum_tag_name_table.get(ip_index).?; + return table_index * wasm.pointerSize() * 2; } fn convertZcuFnType( @@ -4201,12 +4938,15 @@ fn convertZcuFnType( try params_buffer.append(gpa, .i32); // memory address is always a 32-bit handle } else if (return_type.hasRuntimeBits(zcu)) { if (cc == .wasm_mvp) { - switch (abi.classifyType(return_type, zcu)) { - .direct => |scalar_ty| { - assert(!abi.lowerAsDoubleI64(scalar_ty, zcu)); - try returns_buffer.append(gpa, CodeGen.typeToValtype(scalar_ty, zcu, target)); + switch (abi.classifyType(return_type, zcu, target)) { + .direct => |scalar_type| { + try returns_buffer.append(gpa, CodeGen.typeToValtype(scalar_type, zcu, target)); + }, + .double_i64, .indirect => unreachable, + .unrolled => |vector| { + assert(vector.len == 1); + try returns_buffer.append(gpa, CodeGen.typeToValtype(vector.elem_type, zcu, target)); }, - .indirect => unreachable, } } else { try returns_buffer.append(gpa, CodeGen.typeToValtype(return_type, zcu, target)); @@ -4222,16 +4962,22 @@ fn convertZcuFnType( switch (cc) { .wasm_mvp => { - switch (abi.classifyType(param_type, zcu)) { - .direct => |scalar_ty| { - if (!abi.lowerAsDoubleI64(scalar_ty, zcu)) { - try params_buffer.append(gpa, CodeGen.typeToValtype(scalar_ty, zcu, target)); - } else { - try params_buffer.append(gpa, .i64); - try params_buffer.append(gpa, .i64); + switch (abi.classifyType(param_type, zcu, target)) { + .direct => |scalar_type| { + try params_buffer.append(gpa, CodeGen.typeToValtype(scalar_type, zcu, target)); + }, + .double_i64 => { + try params_buffer.append(gpa, .i64); + try params_buffer.append(gpa, .i64); + }, + .indirect => { + try params_buffer.append(gpa, CodeGen.typeToValtype(param_type, zcu, target)); + }, + .unrolled => |vector| { + for (0..vector.len) |_| { + try params_buffer.append(gpa, CodeGen.typeToValtype(vector.elem_type, zcu, target)); } }, - .indirect => try params_buffer.append(gpa, CodeGen.typeToValtype(param_type, zcu, target)), } }, else => try params_buffer.append(gpa, CodeGen.typeToValtype(param_type, zcu, target)), @@ -4255,7 +5001,7 @@ pub fn isBss(wasm: *const Wasm, optional_name: OptionalString) bool { /// those entries. fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !ZcuDataObj { const code_start: u32 = @intCast(wasm.string_bytes.items.len); - const relocs_start: u32 = @intCast(wasm.out_relocs.len); + const relocs_start: u32 = @intCast(wasm.zcu_relocations.len); const uav_fixups_start: u32 = @intCast(wasm.uav_fixups.items.len); const nav_fixups_start: u32 = @intCast(wasm.nav_fixups.items.len); const func_table_fixups_start: u32 = @intCast(wasm.func_table_fixups.items.len); @@ -4271,8 +5017,9 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu } const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start); - const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start); + const relocs_len: u32 = @intCast(wasm.zcu_relocations.len - relocs_start); const any_fixups = + relocs_len != 0 or uav_fixups_start != wasm.uav_fixups.items.len or nav_fixups_start != wasm.nav_fixups.items.len or func_table_fixups_start != wasm.func_table_fixups.items.len; diff --git a/src/link/Wasm/Archive.zig b/src/link/Wasm/Archive.zig index 65a1ee313b8c6bc5e8710728cd877284c47b544f..48665264f3cab69532a8e70d371fe506578d3ea8 100644 --- a/src/link/Wasm/Archive.zig +++ b/src/link/Wasm/Archive.zig @@ -45,7 +45,7 @@ const Header = extern struct { fn nameOrIndex(archive: Header) !NameOrIndex { const value = getValue(&archive.name); - const slash_index = mem.indexOfScalar(u8, value, '/') orelse return error.MalformedArchive; + const slash_index = mem.findScalar(u8, value, '/') orelse return error.MalformedArchive; const len = value.len; if (slash_index == len - 1) { // Name stored directly diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 410ebb7e4434595ecbe1353810235ad1f6b468b2..e80d768ae122c3a92ec66ed98e202dc5b6c242ed 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -7,7 +7,6 @@ const Object = @import("Object.zig"); const Zcu = @import("../../Zcu.zig"); const Alignment = Wasm.Alignment; const String = Wasm.String; -const Relocation = Wasm.Relocation; const InternPool = @import("../../InternPool.zig"); const Mir = @import("../../codegen/wasm/Mir.zig"); @@ -33,8 +32,13 @@ data_segment_groups: ArrayList(DataSegmentGroup) = .empty, binary_bytes: ArrayList(u8) = .empty, missing_exports: std.array_hash_map.Auto(String, void) = .empty, function_imports: std.array_hash_map.Auto(String, Wasm.FunctionImportId) = .empty, +intrinsic_function_imports: std.array_hash_map.Auto(String, Wasm.FunctionType.Index) = .empty, +/// Function aliases emitted after function symbols. +function_export_symbols: std.array_hash_map.Auto(String, FunctionExportSymbol) = .empty, global_imports: std.array_hash_map.Auto(String, Wasm.GlobalImportId) = .empty, data_imports: std.array_hash_map.Auto(String, Wasm.DataImportId) = .empty, +/// Data aliases emitted after data symbols. +data_exports: std.array_hash_map.Auto(String, DataExportSymbol) = .empty, indirect_function_table: std.array_hash_map.Auto(Wasm.OutputFunctionIndex, void) = .empty, @@ -43,6 +47,9 @@ func_types: std.array_hash_map.Auto(Wasm.FunctionType.Index, void) = .empty, enum_tag_name_table: std.array_hash_map.Auto(InternPool.Index, u32) = .empty, +code_relocs: std.ArrayList(Relocation) = .empty, +data_relocs: std.ArrayList(Relocation) = .empty, + /// For debug purposes only. memory_layout_finished: bool = false, @@ -55,6 +62,74 @@ pub const FuncTypeIndex = enum(u32) { } }; +/// Index into SYMTAB_FUNCTION. +const FunctionSymbolIndex = enum(u32) { + _, + + fn fromOutputFunctionIndex(i: Wasm.OutputFunctionIndex) FunctionSymbolIndex { + return @fromBackingInt(@backingInt(i)); + } + + fn fromObjectFunctionHandlingWeak(wasm: *const Wasm, index: Wasm.ObjectFunctionIndex) FunctionSymbolIndex { + return fromOutputFunctionIndex(.fromObjectFunctionHandlingWeak(wasm, index)); + } + + fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) FunctionSymbolIndex { + return fromOutputFunctionIndex(.fromIpNav(wasm, nav_index)); + } + + fn fromTagIndexType(wasm: *const Wasm, ip_index: InternPool.Index) FunctionSymbolIndex { + return fromOutputFunctionIndex(.fromTagIndexType(wasm, ip_index)); + } + + fn fromSymbolName(wasm: *const Wasm, name: String) FunctionSymbolIndex { + const f = &wasm.flush_buffer; + if (f.function_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i)); + if (f.intrinsic_function_imports.getIndex(name)) |i| return @fromBackingInt(@intCast( + f.function_imports.entries.len + i, + )); + if (f.function_export_symbols.getIndex(name)) |i| return @fromBackingInt(@intCast( + f.function_imports.entries.len + f.intrinsic_function_imports.entries.len + + wasm.functions.entries.len + i, + )); + return fromOutputFunctionIndex(.fromSymbolName(wasm, name)); + } +}; + +/// Index into SYMTAB_DATA. +const DataSymbolIndex = enum(u32) { + _, + + fn fromOutputDataIndex(i: Wasm.OutputDataIndex) DataSymbolIndex { + return @fromBackingInt(@backingInt(i)); + } + + fn fromResolution(wasm: *const Wasm, resolution: Wasm.ObjectDataImport.Resolution) DataSymbolIndex { + return fromOutputDataIndex(Wasm.OutputDataIndex.fromResolution(wasm, resolution).?); + } + + fn fromObjectData(wasm: *const Wasm, index: Wasm.ObjectData.Index) DataSymbolIndex { + return fromOutputDataIndex(.fromObjectData(wasm, index)); + } + + fn fromUav(wasm: *const Wasm, ip_index: InternPool.Index) DataSymbolIndex { + return fromOutputDataIndex(.fromUav(wasm, ip_index)); + } + + fn fromNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) DataSymbolIndex { + return fromOutputDataIndex(.fromNav(wasm, nav_index)); + } + + fn fromSymbolName(wasm: *const Wasm, name: String) DataSymbolIndex { + const f = &wasm.flush_buffer; + if (f.data_imports.getIndex(name)) |i| return @fromBackingInt(@intCast(i)); + if (f.data_exports.getIndex(name)) |i| return @fromBackingInt(@intCast( + f.data_imports.entries.len + wasm.datas.entries.len + i, + )); + return fromOutputDataIndex(.fromSymbolName(wasm, name)); + } +}; + /// Index into `indirect_function_table`. const IndirectFunctionTableIndex = enum(u32) { _, @@ -71,9 +146,8 @@ const IndirectFunctionTableIndex = enum(u32) { return @fromBackingInt(@intCast(f.indirect_function_table.getIndex(i).?)); } - fn fromZcuIndirectFunctionSetIndex(i: Wasm.ZcuIndirectFunctionSetIndex) IndirectFunctionTableIndex { - // These are the same since those are added to the table first. - return @fromBackingInt(@intCast(@backingInt(i))); + fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) IndirectFunctionTableIndex { + return fromOutputFunctionIndex(&wasm.flush_buffer, .fromIpNav(wasm, nav_index)); } fn toAbi(i: IndirectFunctionTableIndex) u32 { @@ -81,6 +155,39 @@ const IndirectFunctionTableIndex = enum(u32) { } }; +const SymbolTableOffsets = struct { + function: u32, + data: u32, + global: u32, + table: u32, +}; + +const FunctionExportSymbol = struct { + function_index: Wasm.FunctionIndex, + flags: Wasm.SymbolFlags, +}; + +const DataExportSymbol = struct { + resolution: Wasm.ObjectDataImport.Resolution, + flags: Wasm.SymbolFlags, +}; + +const Relocation = struct { + tag: Object.RelocationType, + offset: u32, + pointee: Pointee, + addend: i32, + + const Pointee = union { + data: DataSymbolIndex, + type_index: FuncTypeIndex, + section: Wasm.ObjectSectionIndex, + function: FunctionSymbolIndex, + global: Wasm.GlobalIndex, + table: Wasm.TableIndex, + }; +}; + const DataSegmentGroup = struct { first_segment: Wasm.DataSegmentId, end_addr: u32, @@ -90,9 +197,14 @@ pub fn clear(f: *Flush) void { f.data_segments.clearRetainingCapacity(); f.data_segment_groups.clearRetainingCapacity(); f.binary_bytes.clearRetainingCapacity(); + f.intrinsic_function_imports.clearRetainingCapacity(); + f.function_export_symbols.clearRetainingCapacity(); + f.data_exports.clearRetainingCapacity(); f.indirect_function_table.clearRetainingCapacity(); f.func_types.clearRetainingCapacity(); f.enum_tag_name_table.clearRetainingCapacity(); + f.code_relocs.clearRetainingCapacity(); + f.data_relocs.clearRetainingCapacity(); f.memory_layout_finished = false; } @@ -102,11 +214,16 @@ pub fn deinit(f: *Flush, gpa: Allocator) void { f.binary_bytes.deinit(gpa); f.missing_exports.deinit(gpa); f.function_imports.deinit(gpa); + f.intrinsic_function_imports.deinit(gpa); + f.function_export_symbols.deinit(gpa); f.global_imports.deinit(gpa); f.data_imports.deinit(gpa); + f.data_exports.deinit(gpa); f.indirect_function_table.deinit(gpa); f.func_types.deinit(gpa); f.enum_tag_name_table.deinit(gpa); + f.code_relocs.deinit(gpa); + f.data_relocs.deinit(gpa); f.* = undefined; } @@ -131,51 +248,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { if (comp.zcu) |zcu| { const ip: *const InternPool = &zcu.intern_pool; // No mutations allowed! + const function_imports_start = wasm.function_imports.entries.len; + const global_imports_start = wasm.global_imports.entries.len; + const data_imports_start = wasm.data_imports.entries.len; log.debug("total MIR instructions: {d}", .{wasm.mir_instructions.len}); - // Detect any intrinsics that were called; they need to have dependencies on the symbols marked. - // Likewise detect `@tagName` calls so those functions can be included in the output and synthesized. - for (wasm.mir_instructions.items(.tag), wasm.mir_instructions.items(.data)) |tag, *data| switch (tag) { - .call_intrinsic => { - const symbol_name = try wasm.internString(@tagName(data.intrinsic)); - const i: Wasm.FunctionImport.Index = @fromBackingInt(@intCast(wasm.object_function_imports.getIndex(symbol_name) orelse { - return diags.fail("missing compiler runtime intrinsic '{t}' (undefined linker symbol)", .{ - data.intrinsic, - }); - })); - try wasm.markFunctionImport(symbol_name, i.value(wasm), i); - log.debug("markFunctionImport intrinsic {d}={t}", .{ i, data.intrinsic }); - }, - .call_tag_index => { - assert(ip.indexToKey(data.ip_index) == .enum_type); - const gop = try wasm.zcu_funcs.getOrPut(gpa, data.ip_index); - if (!gop.found_existing) { - const int_tag_ty = Zcu.Type.fromInterned(data.ip_index).backingIntType(zcu); - gop.value_ptr.* = .{ .tag_name = .{ - .symbol_name = try wasm.internStringFmt("__zig_tag_index_{d}", .{data.ip_index}), - .type_index = try wasm.internFunctionType(.auto, &.{int_tag_ty.ip_index}, .u32, false, target), - } }; - } - try wasm.functions.put(gpa, .fromZcuFunc(wasm, @fromBackingInt(@intCast(gop.index))), {}); - }, - .enum_tag_name_table_ref => { - assert(ip.indexToKey(data.ip_index) == .enum_type); - const gop = try f.enum_tag_name_table.getOrPut(gpa, data.ip_index); - if (!gop.found_existing) { - wasm.tag_name_table_ref_count += 1; - gop.value_ptr.* = @intCast(wasm.tag_name_offs.items.len); - const tag_names = ip.loadEnumType(data.ip_index).field_names; - for (tag_names.get(ip)) |tag_name| { - const slice = tag_name.toSlice(ip); - try wasm.tag_name_offs.append(gpa, @intCast(wasm.tag_name_bytes.items.len)); - try wasm.tag_name_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); - } - } - }, - else => continue, - }; - { var i = wasm.function_imports_len_prelink; while (i < f.function_imports.entries.len) { @@ -225,10 +303,24 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index }); const function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?; const explicit = f.missing_exports.swapRemove(nav_export.name); - const is_hidden = !explicit and switch (export_index.ptr(zcu).opts.visibility) { + const opts = export_index.ptr(zcu).opts; + const is_hidden = !explicit and switch (opts.visibility) { .hidden => true, .default, .protected => false, }; + if (is_obj) try f.function_export_symbols.put(gpa, nav_export.name, .{ + .function_index = function_index, + .flags = .{ + .binding = switch (opts.linkage) { + .internal => .local, + .strong => .strong, + .weak => .weak, + .link_once => @panic("TODO: COMDAT"), + }, + .visibility_hidden = is_hidden, + .exported = !is_hidden, + }, + }); if (is_hidden) { try wasm.hidden_function_exports.put(gpa, nav_export.name, function_index); } else { @@ -239,17 +331,170 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { if (nav_export.name.toOptional() == entry_name) wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index); } else { - // This is a data export because Zcu currently has no way to - // export wasm globals. - _ = f.missing_exports.swapRemove(nav_export.name); + // data exports are linker symbols + // explicit exports become address globals + const explicit = f.missing_exports.swapRemove(nav_export.name); + const opts = export_index.ptr(zcu).opts; + try f.data_exports.put(gpa, nav_export.name, .{ + .resolution = .fromIpNav(wasm, nav_export.nav_index), + .flags = if (is_obj) .{ + .binding = switch (opts.linkage) { + .internal => .local, + .strong => .strong, + .weak => .weak, + .link_once => @panic("TODO: COMDAT"), + }, + .visibility_hidden = !explicit and switch (opts.visibility) { + .default => false, + .hidden => true, + .protected => false, + }, + .exported = explicit, + .tls = ip.getNav(nav_export.nav_index).resolved.?.@"threadlocal", + } else .{}, + }); _ = f.data_imports.swapRemove(nav_export.name); - if (!is_obj) { - diags.addError("unable to export data symbol '{s}'; not emitting a relocatable", .{ - nav_export.name.slice(wasm), + if (explicit and !is_obj) { + const global_resolution: Wasm.GlobalImport.Resolution = .fromIpNav( + wasm, + nav_export.nav_index, + ); + try wasm.globals.put(gpa, global_resolution, {}); + try wasm.global_exports.append(gpa, .{ + .name = nav_export.name, + .global_index = Wasm.GlobalIndex.fromResolution(wasm, global_resolution).?, }); } } } + // handle exported values without navs + for (wasm.uav_exports.keys(), wasm.uav_exports.values()) |uav_export, export_index| { + assert(!ip.isFunctionType(ip.typeOf(uav_export.uav_index))); + const explicit = f.missing_exports.swapRemove(uav_export.name); + const opts = export_index.ptr(zcu).opts; + try f.data_exports.put(gpa, uav_export.name, .{ + .resolution = .fromIpIndex(wasm, uav_export.uav_index), + .flags = if (is_obj) .{ + .binding = switch (opts.linkage) { + .internal => .local, + .strong => .strong, + .weak => .weak, + .link_once => @panic("TODO: COMDAT"), + }, + .visibility_hidden = !explicit and switch (opts.visibility) { + .default => false, + .hidden => true, + .protected => false, + }, + .exported = explicit, + } else .{}, + }); + _ = f.data_imports.swapRemove(uav_export.name); + if (explicit and !is_obj) { + const global_resolution: Wasm.GlobalImport.Resolution = .fromIpIndex( + wasm, + uav_export.uav_index, + ); + try wasm.globals.put(gpa, global_resolution, {}); + try wasm.global_exports.append(gpa, .{ + .name = uav_export.name, + .global_index = Wasm.GlobalIndex.fromResolution(wasm, global_resolution).?, + }); + } + } + + // Detect any intrinsics that were called; they need to have dependencies on the symbols marked. + // Likewise detect `@tagName` calls so those functions can be included in the output and synthesized. + for (wasm.mir_instructions.items(.tag), wasm.mir_instructions.items(.data)) |tag, *data| switch (tag) { + .call_intrinsic => { + const symbol_name = try wasm.internString(@tagName(data.intrinsic)); + if (Wasm.FunctionIndex.fromSymbolName(wasm, symbol_name) == null and + !f.function_imports.contains(symbol_name)) + { + if (wasm.object_function_imports.getIndex(symbol_name)) |object_import_index| { + const i: Wasm.FunctionImport.Index = @fromBackingInt(@intCast(object_import_index)); + try wasm.markFunctionImport(symbol_name, i.value(wasm), i); + if (Wasm.FunctionIndex.fromSymbolName(wasm, symbol_name) == null) { + try f.function_imports.put(gpa, symbol_name, .fromObject(i, wasm)); + } + } else if (is_obj) { + const gop = try f.intrinsic_function_imports.getOrPut(gpa, symbol_name); + if (!gop.found_existing) gop.value_ptr.* = try wasm.intrinsicFunctionType(data.intrinsic); + } else { + return diags.fail("missing compiler runtime intrinsic '{t}' (undefined linker symbol)", .{ + data.intrinsic, + }); + } + } + }, + .call_indirect => { + const fn_info = zcu.typeToFunc(.fromInterned(data.ip_index)).?; + const type_index = wasm.getExistingFunctionType( + fn_info.cc, + fn_info.param_types.get(ip), + .fromInterned(fn_info.return_type), + fn_info.is_var_args, + target, + ).?; + try f.func_types.put(gpa, type_index, {}); + }, + .call_tag_index => { + assert(ip.indexToKey(data.ip_index) == .enum_type); + const gop = try wasm.zcu_funcs.getOrPut(gpa, data.ip_index); + if (!gop.found_existing) { + const int_tag_ty = Zcu.Type.fromInterned(data.ip_index).backingIntType(zcu); + gop.value_ptr.* = .{ .tag_name = .{ + .symbol_name = try wasm.internStringFmt("__zig_tag_index_{d}", .{data.ip_index}), + .type_index = try wasm.internFunctionType(.auto, &.{int_tag_ty.ip_index}, .u32, false, target), + } }; + } + try wasm.functions.put(gpa, .fromZcuFunc(wasm, @fromBackingInt(@intCast(gop.index))), {}); + }, + .enum_tag_name_table_ref => { + assert(ip.indexToKey(data.ip_index) == .enum_type); + const gop = try f.enum_tag_name_table.getOrPut(gpa, data.ip_index); + if (!gop.found_existing) { + wasm.tag_name_table_ref_count += 1; + gop.value_ptr.* = @intCast(wasm.tag_name_offs.items.len); + const tag_names = ip.loadEnumType(data.ip_index).field_names; + for (tag_names.get(ip)) |tag_name| { + const slice = tag_name.toSlice(ip); + try wasm.tag_name_offs.append(gpa, @intCast(wasm.tag_name_bytes.items.len)); + try wasm.tag_name_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); + } + } + }, + else => continue, + }; + + // marking above may discover additional imports + try f.function_imports.ensureUnusedCapacity(gpa, wasm.function_imports.entries.len - function_imports_start); + for ( + wasm.function_imports.keys()[function_imports_start..], + wasm.function_imports.values()[function_imports_start..], + ) |name, id| { + if (!f.function_imports.contains(name) and Wasm.FunctionIndex.fromSymbolName(wasm, name) == null) { + f.function_imports.putAssumeCapacity(name, id); + } + } + + try f.global_imports.ensureUnusedCapacity(gpa, wasm.global_imports.entries.len - global_imports_start); + for ( + wasm.global_imports.keys()[global_imports_start..], + wasm.global_imports.values()[global_imports_start..], + ) |name, id| { + if (!f.global_imports.contains(name)) f.global_imports.putAssumeCapacity(name, id); + } + + try f.data_imports.ensureUnusedCapacity(gpa, wasm.data_imports.entries.len - data_imports_start); + for ( + wasm.data_imports.keys()[data_imports_start..], + wasm.data_imports.values()[data_imports_start..], + ) |name, id| { + if (!f.data_imports.contains(name) and !f.data_exports.contains(name)) { + f.data_imports.putAssumeCapacity(name, id); + } + } for (f.missing_exports.keys()) |exp_name| { diags.addError("manually specified export name '{s}' undefined", .{exp_name.slice(wasm)}); @@ -300,7 +545,27 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { if (wasm.object_init_funcs.items.len > 0) { // Zig has no constructors so these are only for object file inputs. mem.sortUnstable(Wasm.InitFunc, wasm.object_init_funcs.items, {}, Wasm.InitFunc.lessThan); - try wasm.functions.put(gpa, .__wasm_call_ctors, {}); + if (!is_obj) try wasm.functions.put(gpa, .__wasm_call_ctors, {}); + } + + if (is_obj) { + try wasm.datas.ensureUnusedCapacity(gpa, wasm.uavs_obj.entries.len + wasm.navs_obj.entries.len + 4); + for (0..wasm.uavs_obj.entries.len) |i| wasm.datas.putAssumeCapacity( + .pack(wasm, .{ .uav_obj = @fromBackingInt(@intCast(i)) }), + {}, + ); + for (0..wasm.navs_obj.entries.len) |i| wasm.datas.putAssumeCapacity( + .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(i)) }), + {}, + ); + if (wasm.error_name_table_ref_count > 0) { + wasm.datas.putAssumeCapacity(.__zig_error_names, {}); + wasm.datas.putAssumeCapacity(.__zig_error_name_table, {}); + } + if (wasm.tag_name_table_ref_count > 0) { + wasm.datas.putAssumeCapacity(.__zig_tag_names, {}); + wasm.datas.putAssumeCapacity(.__zig_tag_name_table, {}); + } } // Merge and order the data segments. Depends on garbage collection so that @@ -341,14 +606,33 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // dropped in __wasm_init_memory, which is registered as the start function // We also initialize bss segments (using memory.fill) as part of this // function. - if (wasm.any_passive_inits) { + if (!is_obj and wasm.any_passive_inits) { try wasm.addFunction(.__wasm_init_memory, &.{}, &.{}); } try wasm.tables.ensureUnusedCapacity(gpa, 1); if (f.indirect_function_table.entries.len > 0) { - wasm.tables.putAssumeCapacity(.__indirect_function_table, {}); + if (is_obj) { + const name = wasm.preloaded_strings.__indirect_function_table; + const gop = try wasm.object_table_imports.getOrPut(gpa, name); + if (!gop.found_existing) gop.value_ptr.* = .{ + .flags = .{ + .undefined = true, + .no_strip = true, + }, + .module_name = wasm.preloaded_strings.env, + .name = name, + .source_location = .zig_object_nofile, + .resolution = .unresolved, + .limits_min = 1, + .limits_max = 0, + }; + const import_index: Wasm.TableImport.Index = @fromBackingInt(@intCast(gop.index)); + try wasm.markTableImport(name, gop.value_ptr, import_index); + } else { + wasm.tables.putAssumeCapacity(.__indirect_function_table, {}); + } } // Sort order: @@ -449,7 +733,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { const start_addr = alignment.forward(memory_ptr); const want_new_segment = b: { - if (is_obj) break :b false; + if (is_obj) break :b i != 0; switch (seen_tls) { .before => switch (category) { .tls => { @@ -489,7 +773,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { log.debug("0x{x} {d} {s}", .{ start_addr, @backingInt(segment_id), segment_id.name(wasm) }); memory_ptr = start_addr + size; } - if (category != .zero) try f.data_segment_groups.append(gpa, .{ + if (is_obj or category != .zero) try f.data_segment_groups.append(gpa, .{ .first_segment = first_segment, .end_addr = @intCast(memory_ptr), }); @@ -555,7 +839,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // When we have TLS GOT entries and shared memory is enabled, we must // perform runtime relocations or else we don't create the function. - if (shared_memory and virtual_addrs.tls_base != null) { + if (!is_obj and shared_memory and virtual_addrs.tls_base != null) { // This logic that checks `any_tls_relocs` is missing the part where it // also notices threadlocal globals from Zcu code. if (wasm.any_tls_relocs) try wasm.addFunction(.__wasm_apply_global_tls_relocs, &.{}, &.{}); @@ -582,6 +866,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { for (f.function_imports.values()) |id| { try f.func_types.put(gpa, id.functionType(wasm), {}); } + for (f.intrinsic_function_imports.values()) |type_index| { + try f.func_types.put(gpa, type_index, {}); + } for (wasm.functions.keys()) |function| { try f.func_types.put(gpa, function.typeIndex(wasm), {}); } @@ -617,7 +904,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); for (f.function_imports.values()) |id| { - const module_name = id.moduleName(wasm).slice(wasm).?; + const module_name = (id.moduleName(wasm).unwrap() orelse wasm.preloaded_strings.env).slice(wasm); try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len))); try binary_bytes.appendSlice(gpa, module_name); @@ -631,6 +918,20 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { } total_imports += f.function_imports.entries.len; + for (f.intrinsic_function_imports.keys(), f.intrinsic_function_imports.values()) |name_string, type_index| { + const module_name = wasm.preloaded_strings.env.slice(wasm); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len))); + try binary_bytes.appendSlice(gpa, module_name); + + const name = name_string.slice(wasm); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + + try binary_bytes.append(gpa, @backingInt(std.wasm.ExternalKind.function)); + try appendLeb128(gpa, binary_bytes, @backingInt(FuncTypeIndex.fromTypeIndex(type_index, f))); + } + total_imports += f.intrinsic_function_imports.entries.len; + for (wasm.table_imports.values()) |id| { const table_import = id.value(wasm); const module_name = table_import.module_name.slice(wasm); @@ -662,7 +963,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { } for (f.global_imports.values()) |id| { - const module_name = id.moduleName(wasm).slice(wasm).?; + const module_name = (id.moduleName(wasm).unwrap() orelse wasm.preloaded_strings.env).slice(wasm); try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len))); try binary_bytes.appendSlice(gpa, module_name); @@ -726,12 +1027,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { for (wasm.globals.keys()) |global_resolution| { switch (global_resolution.unpack(wasm)) { .unresolved => unreachable, - .__heap_base => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_base), - .__heap_end => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_end), - .__stack_pointer => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.stack_pointer), - .__tls_align => try appendGlobal(gpa, binary_bytes, 0, @intCast(virtual_addrs.tls_align.toByteUnits().?)), - .__tls_base => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.tls_base.?), - .__tls_size => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.tls_size.?), + .__heap_base => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_base, is64), + .__heap_end => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_end, is64), + .__stack_pointer => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.stack_pointer, is64), + .__tls_align => try appendGlobal(gpa, binary_bytes, 0, @intCast(virtual_addrs.tls_align.toByteUnits().?), is64), + .__tls_base => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.tls_base.?, is64), + .__tls_size => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.tls_size.?, is64), .object_global => |i| { const global = i.ptr(wasm); try binary_bytes.appendSlice(gpa, &.{ @@ -740,8 +1041,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { }); try emitExpr(wasm, binary_bytes, global.expr); }, - .nav_exe => unreachable, // Zig source code currently cannot represent this. - .nav_obj => unreachable, // Zig source code currently cannot represent this. + .uav_exe => |i| try appendGlobal(gpa, binary_bytes, 0, wasm.uavAddr(i.key(wasm).*), is64), + .nav_exe => |i| try appendGlobal(gpa, binary_bytes, 0, wasm.navAddr(i.key(wasm).*), is64), + .uav_obj, .nav_obj => unreachable, } } @@ -766,7 +1068,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { if (wasm.export_table and f.indirect_function_table.entries.len > 0) { const name = "__indirect_function_table"; - const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); + const index: u32 = @intCast(wasm.table_imports.entries.len + + wasm.tables.getIndex(.__indirect_function_table).?); try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); try binary_bytes.appendSlice(gpa, name); try binary_bytes.append(gpa, @backingInt(std.wasm.ExternalKind.table)); @@ -803,16 +1106,18 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // start section if (wasm.functions.getIndex(.__wasm_init_memory)) |func_index| { try emitStartSection(gpa, binary_bytes, .fromFunctionIndex(wasm, @fromBackingInt(@intCast(func_index)))); - } else if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| { - try emitStartSection(gpa, binary_bytes, func_index); + section_index += 1; } // element section - if (f.indirect_function_table.entries.len > 0) { + if (!is_obj and f.indirect_function_table.entries.len > 0) { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); // indirect function table elements - const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); + const table_index: u32 = @intCast( + wasm.table_imports.getIndex(wasm.preloaded_strings.__indirect_function_table) orelse + wasm.table_imports.entries.len + wasm.tables.getIndex(.__indirect_function_table).?, + ); // passive with implicit 0-index table or set table index manually const flags: u32 = if (table_index == 0) 0x0 else 0x02; try appendLeb128(gpa, binary_bytes, flags); @@ -841,11 +1146,13 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { if (f.data_segment_groups.items.len > 0) { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len)); + section_index += 1; } // Code section. if (wasm.functions.count() != 0) { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const section_offset = binary_bytes.items.len - uleb128size(@intCast(wasm.functions.count())); for (wasm.functions.keys()) |resolution| switch (resolution.unpack(wasm)) { .unresolved => unreachable, @@ -870,10 +1177,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { const code = ptr.code.slice(wasm); try appendLeb128(gpa, binary_bytes, code.len); const code_start = binary_bytes.items.len; + const output_offset: u32 = @intCast(binary_bytes.items.len - section_offset); try binary_bytes.appendSlice(gpa, code); - if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm); + if (is_obj) { + try processRelocs( + wasm, + &f.code_relocs, + output_offset, + ptr.offset, + ptr.relocations(wasm), + ); + } else { + applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm); + } }, .zcu_func => |i| { + const function_offset: u32 = @intCast(binary_bytes.items.len - section_offset); const code_start = try reserveSize(gpa, binary_bytes); defer replaceSize(binary_bytes, code_start); @@ -899,7 +1218,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { .func_tys = undefined, .error_name_table_ref_count = undefined, }; + const body_start: u32 = @intCast(binary_bytes.items.len); + const relocs_start: u32 = @intCast(wasm.zcu_relocations.len); + defer wasm.zcu_relocations.shrinkRetainingCapacity(relocs_start); try mir.lower(wasm, binary_bytes); + const relocs_len: u32 = @intCast(wasm.zcu_relocations.len - relocs_start); + if (is_obj) { + const body_len: u32 = @intCast(binary_bytes.items.len - @as(usize, body_start)); + const output_offset = function_offset + uleb128size(body_len); + try processZcuRelocs( + wasm, + &f.code_relocs, + output_offset, + body_start, + .{ .off = relocs_start, .len = relocs_len }, + ); + } }, } }, @@ -921,8 +1255,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { } } for (wasm.nav_fixups.items) |nav_fixup| { - const ds_id: Wasm.DataSegmentId = .pack(wasm, .{ .nav_exe = nav_fixup.navs_exe_index }); - const vaddr = f.data_segments.get(ds_id).? + nav_fixup.addend; + const vaddr = wasm.navAddr(nav_fixup.nav_index) + nav_fixup.addend; if (!is64) { mem.writeInt(u32, wasm.string_bytes.items[nav_fixup.offset..][0..4], vaddr, .little); } else { @@ -930,7 +1263,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { } } for (wasm.func_table_fixups.items) |fixup| { - const table_index: IndirectFunctionTableIndex = .fromZcuIndirectFunctionSetIndex(fixup.table_index); + const table_index: IndirectFunctionTableIndex = .fromIpNav(wasm, fixup.nav_index); if (!is64) { mem.writeInt(u32, wasm.string_bytes.items[fixup.offset..][0..4], table_index.toAbi(), .little); } else { @@ -942,6 +1275,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Data section. if (f.data_segment_groups.items.len != 0) { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const section_offset = binary_bytes.items.len - uleb128size(@intCast(f.data_segment_groups.items.len)); var group_index: u32 = 0; var segment_offset: u32 = 0; @@ -976,7 +1310,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { try appendLeb128(gpa, binary_bytes, group_size); } if (segment_id.isEmpty(wasm)) { - // It counted for virtual memory but it does not go into the binary. + if (is_obj) { + const group_size = group_end_addr - group_start_addr; + try binary_bytes.appendNTimes(gpa, 0, group_size - segment_offset); + segment_offset = group_size; + } continue; } @@ -986,6 +1324,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { segment_offset = needed_offset; const code_start = binary_bytes.items.len; + const output_offset: u32 = @intCast(binary_bytes.items.len - section_offset); append: { const code = switch (segment_id.unpack(wasm)) { .__heap_base => { @@ -1001,12 +1340,19 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { break :append; }, .__zig_error_name_table => { - if (is_obj) @panic("TODO error name table reloc"); - const base = f.data_segments.get(.__zig_error_names).?; - if (!is64) { - try emitTagNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32); + if (is_obj) { + try emitRelocatableNameTable( + wasm, + binary_bytes, + &f.data_relocs, + output_offset, + wasm.error_name_offs.items, + wasm.error_name_bytes.items, + .__zig_error_names, + ); } else { - try emitTagNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64); + const base = f.data_segments.get(.__zig_error_names).?; + try emitTagNameTable(wasm, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, is64); } break :append; }, @@ -1015,22 +1361,51 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { break :append; }, .__zig_tag_name_table => { - if (is_obj) @panic("TODO tag name table reloc"); - const base = f.data_segments.get(.__zig_tag_names).?; - if (!is64) { - try emitTagNameTable(gpa, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u32); + if (is_obj) { + try emitRelocatableNameTable( + wasm, + binary_bytes, + &f.data_relocs, + output_offset, + wasm.tag_name_offs.items, + wasm.tag_name_bytes.items, + .__zig_tag_names, + ); } else { - try emitTagNameTable(gpa, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u64); + const base = f.data_segments.get(.__zig_tag_names).?; + try emitTagNameTable(wasm, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, is64); } break :append; }, .object => |i| { const ptr = i.ptr(wasm); try binary_bytes.appendSlice(gpa, ptr.payload.slice(wasm)); - if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm); + if (is_obj) { + try processRelocs( + wasm, + &f.data_relocs, + output_offset, + ptr.offset, + ptr.relocations(wasm), + ); + } else { + applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm); + } break :append; }, - inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code, + inline .uav_obj, .nav_obj => |i| { + const zcu_data = i.value(wasm); + try binary_bytes.appendSlice(gpa, zcu_data.code.slice(wasm)); + try processZcuRelocs( + wasm, + &f.data_relocs, + output_offset, + zcu_data.code.off.unwrap().?, + zcu_data.relocs, + ); + break :append; + }, + inline .uav_exe, .nav_exe => |i| i.value(wasm).code, }; try binary_bytes.appendSlice(gpa, code.slice(wasm)); } @@ -1043,7 +1418,274 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { } if (is_obj) { - @panic("TODO emit link section for object file and emit modified relocations"); + var symbol_table_offsets: SymbolTableOffsets = undefined; + { + const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); + defer writeCustomSectionHeader(binary_bytes, header_offset); + + const linking_name = "linking"; + try appendLeb128(gpa, binary_bytes, @as(u32, linking_name.len)); + try binary_bytes.appendSlice(gpa, linking_name); + + try appendLeb128(gpa, binary_bytes, @as(u32, 2)); + + // WASM_SEGMENT_INFO + { + const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); + defer replaceHeader(binary_bytes, sub_offset, @backingInt(Object.SubsectionType.segment_info)); + + const total_data_segments: u32 = @intCast(f.data_segment_groups.items.len); + try appendLeb128(gpa, binary_bytes, total_data_segments); + + for (f.data_segment_groups.items) |group| { + const segment = group.first_segment; + const name, _ = splitSegmentName(segment.name(wasm)); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + + try appendLeb128(gpa, binary_bytes, @as(u32, segment.alignment(wasm).toLog2Units())); + + var flags: u32 = 0; + if (segment.isStrings(wasm)) flags |= 1; + if (segment.isTls(wasm)) flags |= 2; + if (segment.isRetain(wasm)) flags |= 4; + try appendLeb128(gpa, binary_bytes, flags); + } + } + + // WASM_SYMBOL_TABLE + { + const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); + defer replaceHeader(binary_bytes, sub_offset, @backingInt(Object.SubsectionType.symbol_table)); + + const total_symbols: u32 = @intCast( + f.function_imports.entries.len + f.intrinsic_function_imports.entries.len + + wasm.functions.entries.len + + f.function_export_symbols.entries.len + + f.data_imports.entries.len + wasm.datas.entries.len + f.data_exports.entries.len + + f.global_imports.entries.len + wasm.globals.entries.len + + wasm.table_imports.entries.len + wasm.tables.entries.len, + ); + try appendLeb128(gpa, binary_bytes, total_symbols); + var symbol_count: u32 = 0; + + // SYMTAB_FUNCTION + { + symbol_table_offsets.function = symbol_count; + for (f.function_imports.values(), 0..) |i, function_index| { + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function)); + const flags = i.flags(wasm); + assert(flags.undefined); + try appendLeb128(gpa, binary_bytes, flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index))); + if (flags.explicit_name) { + unreachable; // never set + } + symbol_count += 1; + } + const intrinsic_flags: Wasm.SymbolFlags = .{ .undefined = true }; + for (f.intrinsic_function_imports.keys(), f.function_imports.entries.len..) |_, function_index| { + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function)); + try appendLeb128(gpa, binary_bytes, intrinsic_flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index))); + symbol_count += 1; + } + for ( + wasm.functions.keys(), + f.function_imports.entries.len + f.intrinsic_function_imports.entries.len.., + ) |resolution, function_index| { + const name = resolution.name(wasm).?; + const flags = resolution.flags(wasm); + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function)); + assert(!flags.undefined); + try appendLeb128(gpa, binary_bytes, flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index))); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + symbol_count += 1; + } + for ( + f.function_export_symbols.keys(), + f.function_export_symbols.values(), + ) |name_string, symbol| { + const name = name_string.slice(wasm); + const function_index: Wasm.OutputFunctionIndex = .fromFunctionIndex( + wasm, + symbol.function_index, + ); + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.function)); + try appendLeb128(gpa, binary_bytes, symbol.flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @backingInt(function_index)); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + symbol_count += 1; + } + } + + // SYMTAB_DATA + { + symbol_table_offsets.data = symbol_count; + for (f.data_imports.keys(), f.data_imports.values()) |name_string, data_index| { + const name = name_string.slice(wasm); + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.data)); + const flags = data_index.flags(wasm); + assert(flags.undefined); + try appendLeb128(gpa, binary_bytes, flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + symbol_count += 1; + } + for (wasm.datas.keys()) |resolution| { + var buf: [32]u8 = undefined; + const name = resolution.name(wasm, &buf); + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.data)); + const flags = resolution.flags(wasm); + assert(!flags.undefined); + try appendLeb128(gpa, binary_bytes, flags.toAbiInteger()); + + const data_loc = resolution.dataLoc(wasm); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + + const segment_index = f.data_segments.getIndex(data_loc.segment).?; + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(segment_index))); + try appendLeb128(gpa, binary_bytes, data_loc.offset); + try appendLeb128(gpa, binary_bytes, resolution.size(wasm)); + symbol_count += 1; + } + for (f.data_exports.keys(), f.data_exports.values()) |name_string, symbol| { + const name = name_string.slice(wasm); + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.data)); + try appendLeb128(gpa, binary_bytes, symbol.flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + + const data_loc = symbol.resolution.dataLoc(wasm); + const segment_index = f.data_segments.getIndex(data_loc.segment).?; + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(segment_index))); + try appendLeb128(gpa, binary_bytes, data_loc.offset); + try appendLeb128(gpa, binary_bytes, symbol.resolution.size(wasm)); + symbol_count += 1; + } + } + + // SYMTAB_GLOBAL + { + symbol_table_offsets.global = symbol_count; + for (f.global_imports.values(), 0..) |i, global_index| { + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.global)); + const flags = i.flags(wasm); + assert(flags.undefined); + try appendLeb128(gpa, binary_bytes, flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index))); + if (flags.explicit_name) { + unreachable; // never set + } + symbol_count += 1; + } + for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| { + var buf: [32]u8 = undefined; + const name = resolution.name(wasm, &buf).?; + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.global)); + const flags = resolution.flags(wasm); + assert(!flags.undefined); + try appendLeb128(gpa, binary_bytes, flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index))); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + symbol_count += 1; + } + } + + // SYMTAB_EVENT + { + // TODO not parsed yet + } + + // SYMTAB_SECTION + { + // TODO not parsed correctly yet + } + + // SYMTAB_TABLE + { + symbol_table_offsets.table = symbol_count; + for (wasm.table_imports.values(), 0..) |i, table_index| { + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.table)); + const flags = i.value(wasm).flags; + assert(flags.undefined); + try appendLeb128(gpa, binary_bytes, flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(table_index))); + if (flags.explicit_name) { + unreachable; // never set + } + symbol_count += 1; + } + for (wasm.tables.keys(), wasm.table_imports.entries.len..) |resolution, table_index| { + const name = resolution.name(wasm).?; + try binary_bytes.append(gpa, @backingInt(Object.Symbol.Tag.table)); + const flags = resolution.flags(wasm); + assert(!flags.undefined); + try appendLeb128(gpa, binary_bytes, flags.toAbiInteger()); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(table_index))); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + symbol_count += 1; + } + } + assert(symbol_count == total_symbols); + } + + // WASM_INIT_FUNCS + { + const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); + defer replaceHeader(binary_bytes, sub_offset, @backingInt(Object.SubsectionType.init_funcs)); + + const init_funcs = wasm.object_init_funcs.items; + const total_functions: u32 = b: { + var cnt: u32 = 0; + for (init_funcs) |init_func| { + const func = init_func.function_index.ptr(wasm); + if (!func.object_index.ptr(wasm).is_included) continue; + cnt += 1; + } + break :b cnt; + }; + try appendLeb128(gpa, binary_bytes, total_functions); + + for (init_funcs) |init_func| { + const func = init_func.function_index.ptr(wasm); + if (!func.object_index.ptr(wasm).is_included) continue; + + try appendLeb128(gpa, binary_bytes, init_func.priority); + const out_index: Wasm.OutputFunctionIndex = .fromObjectFunction(wasm, init_func.function_index); + const symbol_index: u32 = symbol_table_offsets.function + @backingInt(out_index); + try appendLeb128(gpa, binary_bytes, symbol_index); + } + } + + // WASM_COMDAT_INFO + { + // TODO + } + } + + if (f.code_relocs.items.len != 0) try emitRelocSection( + wasm, + binary_bytes, + code_section_index.?, + "reloc.CODE", + f.code_relocs.items, + symbol_table_offsets, + ); + if (f.data_relocs.items.len != 0) try emitRelocSection( + wasm, + binary_bytes, + data_section_index.?, + "reloc.DATA", + f.data_relocs.items, + symbol_table_offsets, + ); } else if (comp.config.debug_format != .strip) { try emitNameSection(wasm, f.data_segment_groups.items, binary_bytes); } @@ -1121,7 +1763,10 @@ fn emitNameSection( const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); defer replaceHeader(binary_bytes, sub_offset, @backingInt(std.wasm.NameSubsection.function)); - const total_functions: u32 = @intCast(f.function_imports.entries.len + wasm.functions.entries.len); + const total_functions: u32 = @intCast( + f.function_imports.entries.len + f.intrinsic_function_imports.entries.len + + wasm.functions.entries.len, + ); try appendLeb128(gpa, binary_bytes, total_functions); for (f.function_imports.keys(), 0..) |name_index, function_index| { @@ -1130,7 +1775,16 @@ fn emitNameSection( try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); try binary_bytes.appendSlice(gpa, name); } - for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| { + for (f.intrinsic_function_imports.keys(), f.function_imports.entries.len..) |name_index, function_index| { + const name = name_index.slice(wasm); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index))); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); + } + for ( + wasm.functions.keys(), + f.function_imports.entries.len + f.intrinsic_function_imports.entries.len.., + ) |resolution, function_index| { const name = resolution.name(wasm).?; try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index))); try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); @@ -1152,7 +1806,8 @@ fn emitNameSection( try binary_bytes.appendSlice(gpa, name); } for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| { - const name = resolution.name(wasm).?; + var buf: [32]u8 = undefined; + const name = resolution.name(wasm, &buf).?; try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index))); try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len))); try binary_bytes.appendSlice(gpa, name); @@ -1270,7 +1925,7 @@ fn emitProducerSection(gpa: Allocator, binary_bytes: *ArrayList(u8)) !void { fn splitSegmentName(name: []const u8) struct { []const u8, []const u8 } { const start = @intFromBool(name.len >= 1 and name[0] == '.'); - const pivot = mem.indexOfScalarPos(u8, name, start, '.') orelse name.len; + const pivot = mem.findScalarPos(u8, name, start, '.') orelse name.len; return .{ name[0..pivot], name[pivot..] }; } @@ -1418,29 +2073,6 @@ pub fn emitExpr(wasm: *const Wasm, binary_bytes: *ArrayList(u8), expr: Wasm.Expr try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode } -fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.array_list.Managed(u8)) !void { - const gpa = wasm.base.comp.gpa; - try appendLeb128(gpa, binary_bytes, @backingInt(Wasm.SubsectionType.segment_info)); - const segment_offset = binary_bytes.items.len; - - try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(wasm.segment_info.count()))); - for (wasm.segment_info.values()) |segment_info| { - log.debug("Emit segment: {s} align({d}) flags({b})", .{ - segment_info.name, - segment_info.alignment, - segment_info.flags, - }); - try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(segment_info.name.len))); - try binary_bytes.appendSlice(gpa, segment_info.name); - try appendLeb128(gpa, binary_bytes, segment_info.alignment.toLog2Units()); - try appendLeb128(gpa, binary_bytes, segment_info.flags); - } - - var buf: [5]u8 = undefined; - leb.writeUnsignedFixed(5, &buf, @as(u32, @intCast(binary_bytes.items.len - segment_offset))); - try binary_bytes.insertSlice(segment_offset, &buf); -} - fn uleb128size(x: u32) u32 { var value = x; var size: u32 = 0; @@ -1449,22 +2081,395 @@ fn uleb128size(x: u32) u32 { } fn emitTagNameTable( - gpa: Allocator, + wasm: *const Wasm, code: *ArrayList(u8), tag_name_offs: []const u32, tag_name_bytes: []const u8, base: u32, - comptime Int: type, + is64: bool, ) error{OutOfMemory}!void { - const ptr_size_bytes = @divExact(@bitSizeOf(Int), 8); + const gpa = wasm.base.comp.gpa; + const ptr_size_bytes: usize = if (is64) 8 else 4; try code.ensureUnusedCapacity(gpa, ptr_size_bytes * 2 * tag_name_offs.len); for (tag_name_offs) |off| { - const name_len: u32 = @intCast(mem.indexOfScalar(u8, tag_name_bytes[off..], 0).?); - mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), base + off, .little); - mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little); + const name_len: u32 = @intCast(mem.findScalar(u8, tag_name_bytes[off..], 0).?); + if (is64) { + mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), base + off, .little); + mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), name_len, .little); + } else { + mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), base + off, .little); + mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), name_len, .little); + } } } +fn emitRelocatableNameTable( + wasm: *const Wasm, + code: *ArrayList(u8), + relocs: *ArrayList(Relocation), + output_offset: u32, + name_offs: []const u32, + name_bytes: []const u8, + names_resolution: Wasm.ObjectDataImport.Resolution, +) error{OutOfMemory}!void { + const gpa = wasm.base.comp.gpa; + const ptr_size = @divExact(wasm.base.comp.root_mod.resolved_target.result.ptrBitWidth(), 8); + const table_start = code.items.len; + const data_index: DataSymbolIndex = .fromResolution(wasm, names_resolution); + try code.ensureUnusedCapacity(gpa, @as(usize, ptr_size) * 2 * name_offs.len); + try relocs.ensureUnusedCapacity(gpa, name_offs.len); + for (name_offs) |off| { + const name_len: u32 = @intCast(mem.findScalar(u8, name_bytes[off..], 0).?); + const reloc_offset = output_offset + @as(u32, @intCast(code.items.len - table_start)); + switch (ptr_size) { + 4 => { + @memset(code.addManyAsArrayAssumeCapacity(4), 0); + mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), name_len, .little); + }, + 8 => { + @memset(code.addManyAsArrayAssumeCapacity(8), 0); + mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), @intCast(name_len), .little); + }, + else => unreachable, + } + relocs.appendAssumeCapacity(.{ + .tag = if (ptr_size == 4) .memory_addr_i32 else .memory_addr_i64, + .offset = reloc_offset, + .pointee = .{ .data = data_index }, + .addend = @intCast(off), + }); + } +} + +fn emitRelocSection( + wasm: *const Wasm, + binary_bytes: *ArrayList(u8), + section_index: u32, + reloc_name: []const u8, + relocs: []const Relocation, + symbol_table_offsets: SymbolTableOffsets, +) !void { + const comp = wasm.base.comp; + const gpa = comp.gpa; + + const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); + defer writeCustomSectionHeader(binary_bytes, header_offset); + + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(reloc_name.len))); + try binary_bytes.appendSlice(gpa, reloc_name); + + try appendLeb128(gpa, binary_bytes, section_index); + try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(relocs.len))); + + for (relocs) |r| { + try binary_bytes.append(gpa, @backingInt(r.tag)); + try appendLeb128(gpa, binary_bytes, r.offset); + switch (r.tag) { + .memory_addr_leb, + .memory_addr_sleb, + .memory_addr_i32, + .memory_addr_rel_sleb, + .memory_addr_leb64, + .memory_addr_sleb64, + .memory_addr_i64, + .memory_addr_rel_sleb64, + .memory_addr_tls_sleb, + .memory_addr_locrel_i32, + .memory_addr_tls_sleb64, + => { + const symbol_index: u32 = symbol_table_offsets.data + @backingInt(r.pointee.data); + try appendLeb128(gpa, binary_bytes, symbol_index); + }, + .section_offset_i32 => { + @panic("TODO"); + }, + .type_index_leb => { + try appendLeb128(gpa, binary_bytes, @backingInt(r.pointee.type_index)); + }, + .function_offset_i32, + .function_offset_i64, + .function_index_leb, + .function_index_i32, + .table_index_sleb, + .table_index_i32, + .table_index_sleb64, + .table_index_i64, + .table_index_rel_sleb, + .table_index_rel_sleb64, + => { + const symbol_index: u32 = symbol_table_offsets.function + @backingInt(r.pointee.function); + try appendLeb128(gpa, binary_bytes, symbol_index); + }, + .global_index_leb, .global_index_i32 => { + const symbol_index: u32 = symbol_table_offsets.global + @backingInt(r.pointee.global); + try appendLeb128(gpa, binary_bytes, symbol_index); + }, + .table_number_leb => { + const symbol_index: u32 = symbol_table_offsets.table + @backingInt(r.pointee.table); + try appendLeb128(gpa, binary_bytes, symbol_index); + }, + .event_index_leb => @panic("TODO"), + } + switch (r.tag) { + .memory_addr_leb, + .memory_addr_sleb, + .memory_addr_i32, + .memory_addr_rel_sleb, + .memory_addr_leb64, + .memory_addr_sleb64, + .memory_addr_i64, + .memory_addr_rel_sleb64, + .memory_addr_tls_sleb, + .memory_addr_locrel_i32, + .memory_addr_tls_sleb64, + .function_offset_i32, + .function_offset_i64, + .section_offset_i32, + => { + try appendLeb128(gpa, binary_bytes, r.addend); + }, + else => {}, + } + } +} + +fn processZcuRelocs( + wasm: *const Wasm, + out: *ArrayList(Relocation), + output_offset: u32, + input_offset: u32, + relocs: Wasm.ZcuRelocation.Slice, +) !void { + const gpa = wasm.base.comp.gpa; + for ( + relocs.tags(wasm), + relocs.pointees(wasm), + relocs.offsets(wasm), + relocs.addends(wasm), + ) |tag, pointee, offset, addend| { + const output_pointee: Relocation.Pointee = switch (pointee) { + .function_nav => |nav_index| .{ .function = .fromIpNav(wasm, nav_index) }, + .function_name => |name| .{ .function = .fromSymbolName(wasm, name) }, + .tag_function => |ip_index| .{ .function = .fromTagIndexType(wasm, ip_index) }, + .data_uav => |ip_index| .{ .data = .fromUav(wasm, ip_index) }, + .data_nav => |nav_index| .{ .data = .fromNav(wasm, nav_index) }, + .data_resolution => |resolution| .{ .data = .fromResolution(wasm, resolution) }, + .stack_pointer => .{ .global = .fromSymbolName(wasm, wasm.preloaded_strings.__stack_pointer) }, + .type_index => |type_index| .{ .type_index = .fromTypeIndex(type_index, &wasm.flush_buffer) }, + }; + try out.append(gpa, .{ + .tag = tag, + .offset = output_offset + (offset - input_offset), + .pointee = output_pointee, + .addend = addend, + }); + } +} + +fn processRelocs( + wasm: *const Wasm, + out: *ArrayList(Relocation), + output_offset: u32, + input_offset: u32, + relocs: Wasm.ObjectRelocation.IterableSlice, +) !void { + const gpa = wasm.base.comp.gpa; + for ( + relocs.slice.tags(wasm), + relocs.slice.pointees(wasm), + relocs.slice.offsets(wasm), + relocs.slice.addends(wasm), + ) |tag, pointee, offset, addend| { + if (offset >= relocs.end) break; + const rebased_offset = output_offset + (offset - input_offset); + try out.ensureUnusedCapacity(gpa, 1); + switch (tag) { + .function_index_i32 => out.appendAssumeCapacity(.{ + .tag = .function_index_i32, + .offset = rebased_offset, + .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) }, + .addend = addend, + }), + .function_index_leb => out.appendAssumeCapacity(.{ + .tag = .function_index_leb, + .offset = rebased_offset, + .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) }, + .addend = addend, + }), + .function_offset_i32 => @panic("TODO this value is not known yet"), + .function_offset_i64 => @panic("TODO this value is not known yet"), + .table_index_i32 => out.appendAssumeCapacity(.{ + .tag = .table_index_i32, + .offset = rebased_offset, + .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) }, + .addend = addend, + }), + .table_index_i64 => out.appendAssumeCapacity(.{ + .tag = .table_index_i64, + .offset = rebased_offset, + .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) }, + .addend = addend, + }), + .table_index_rel_sleb => @panic("TODO what does this reloc tag mean?"), + .table_index_rel_sleb64 => @panic("TODO what does this reloc tag mean?"), + .table_index_sleb => out.appendAssumeCapacity(.{ + .tag = .table_index_sleb, + .offset = rebased_offset, + .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) }, + .addend = addend, + }), + .table_index_sleb64 => out.appendAssumeCapacity(.{ + .tag = .table_index_sleb64, + .offset = rebased_offset, + .pointee = .{ .function = .fromObjectFunctionHandlingWeak(wasm, pointee.function) }, + .addend = addend, + }), + + .function_import_index_i32 => out.appendAssumeCapacity(.{ + .tag = .function_index_i32, + .offset = rebased_offset, + .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + .function_import_index_leb => out.appendAssumeCapacity(.{ + .tag = .function_index_leb, + .offset = rebased_offset, + .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + .function_import_offset_i32 => @panic("TODO this value is not known yet"), + .function_import_offset_i64 => @panic("TODO this value is not known yet"), + .table_import_index_i32 => out.appendAssumeCapacity(.{ + .tag = .table_index_i32, + .offset = rebased_offset, + .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + .table_import_index_i64 => out.appendAssumeCapacity(.{ + .tag = .table_index_i64, + .offset = rebased_offset, + .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + .table_import_index_rel_sleb => @panic("TODO what does this reloc tag mean?"), + .table_import_index_rel_sleb64 => @panic("TODO what does this reloc tag mean?"), + .table_import_index_sleb => out.appendAssumeCapacity(.{ + .tag = .table_index_sleb, + .offset = rebased_offset, + .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + .table_import_index_sleb64 => out.appendAssumeCapacity(.{ + .tag = .table_index_sleb64, + .offset = rebased_offset, + .pointee = .{ .function = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + + .global_index_i32 => out.appendAssumeCapacity(.{ + .tag = .global_index_i32, + .offset = rebased_offset, + .pointee = .{ .global = .fromObjectGlobalHandlingWeak(wasm, pointee.global) }, + .addend = addend, + }), + .global_index_leb => out.appendAssumeCapacity(.{ + .tag = .global_index_leb, + .offset = rebased_offset, + .pointee = .{ .global = .fromObjectGlobalHandlingWeak(wasm, pointee.global) }, + .addend = addend, + }), + + .global_import_index_i32 => out.appendAssumeCapacity(.{ + .tag = .global_index_i32, + .offset = rebased_offset, + .pointee = .{ .global = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + .global_import_index_leb => out.appendAssumeCapacity(.{ + .tag = .global_index_leb, + .offset = rebased_offset, + .pointee = .{ .global = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + + .memory_addr_i32, + .memory_addr_i64, + .memory_addr_leb, + .memory_addr_leb64, + .memory_addr_sleb, + .memory_addr_sleb64, + .memory_addr_tls_sleb, + .memory_addr_tls_sleb64, + => out.appendAssumeCapacity(.{ + .tag = memoryRelocationType(tag), + .offset = rebased_offset, + .pointee = .{ .data = .fromObjectData(wasm, pointee.data) }, + .addend = addend, + }), + .memory_addr_locrel_i32 => @panic("TODO implement relocation memory_addr_locrel_i32"), + .memory_addr_rel_sleb => @panic("TODO implement relocation memory_addr_rel_sleb"), + .memory_addr_rel_sleb64 => @panic("TODO implement relocation memory_addr_rel_sleb64"), + + .memory_addr_import_i32, + .memory_addr_import_i64, + .memory_addr_import_leb, + .memory_addr_import_leb64, + .memory_addr_import_sleb, + .memory_addr_import_sleb64, + => out.appendAssumeCapacity(.{ + .tag = memoryRelocationType(tag), + .offset = rebased_offset, + .pointee = .{ .data = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + .memory_addr_import_locrel_i32 => @panic("TODO implement relocation memory_addr_import_locrel_i32"), + .memory_addr_import_rel_sleb => @panic("TODO implement relocation memory_addr_import_rel_sleb"), + .memory_addr_import_rel_sleb64 => @panic("TODO implement memory_addr_import_rel_sleb64"), + .memory_addr_import_tls_sleb => @panic("TODO"), + .memory_addr_import_tls_sleb64 => @panic("TODO"), + + .section_offset_i32 => @panic("TODO this value is not known yet"), + + .table_number_leb => out.appendAssumeCapacity(.{ + .tag = .table_number_leb, + .offset = rebased_offset, + .pointee = .{ .table = .fromObjectTable(wasm, pointee.table) }, + .addend = addend, + }), + .table_import_number_leb => out.appendAssumeCapacity(.{ + .tag = .table_number_leb, + .offset = rebased_offset, + .pointee = .{ .table = .fromSymbolName(wasm, pointee.symbol_name) }, + .addend = addend, + }), + + .type_index_leb => out.appendAssumeCapacity(.{ + .tag = .type_index_leb, + .offset = rebased_offset, + .pointee = .{ .type_index = .fromTypeIndex(pointee.type_index, &wasm.flush_buffer) }, + .addend = addend, + }), + } + } +} + +fn memoryRelocationType(tag: Wasm.ObjectRelocation.Tag) Object.RelocationType { + return switch (tag) { + .memory_addr_i32, .memory_addr_import_i32 => .memory_addr_i32, + .memory_addr_i64, .memory_addr_import_i64 => .memory_addr_i64, + .memory_addr_leb, .memory_addr_import_leb => .memory_addr_leb, + .memory_addr_leb64, .memory_addr_import_leb64 => .memory_addr_leb64, + .memory_addr_locrel_i32, .memory_addr_import_locrel_i32 => .memory_addr_locrel_i32, + .memory_addr_rel_sleb, .memory_addr_import_rel_sleb => .memory_addr_rel_sleb, + .memory_addr_rel_sleb64, .memory_addr_import_rel_sleb64 => .memory_addr_rel_sleb64, + .memory_addr_sleb, .memory_addr_import_sleb => .memory_addr_sleb, + .memory_addr_sleb64, .memory_addr_import_sleb64 => .memory_addr_sleb64, + .memory_addr_tls_sleb, .memory_addr_import_tls_sleb => .memory_addr_tls_sleb, + .memory_addr_tls_sleb64, .memory_addr_import_tls_sleb64 => .memory_addr_tls_sleb64, + else => unreachable, + }; +} + fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.IterableSlice, wasm: *const Wasm) void { for ( relocs.slice.tags(wasm), @@ -1579,12 +2584,17 @@ const RelocAddr = struct { fn fromSymbolName(wasm: *const Wasm, name: String, addend: i32) RelocAddr { const flush = &wasm.flush_buffer; if (wasm.object_data_imports.getPtr(name)) |import| { - return fromDataLoc(flush, import.resolution.dataLoc(wasm), addend); - } else if (wasm.data_imports.get(name)) |id| { + if (import.resolution != .unresolved) { + return fromDataLoc(flush, import.resolution.dataLoc(wasm), addend); + } + } + if (flush.data_exports.get(name)) |symbol| { + return fromDataLoc(flush, symbol.resolution.dataLoc(wasm), addend); + } + if (wasm.data_imports.get(name)) |id| { return fromDataLoc(flush, .fromDataImportId(wasm, id), addend); - } else { - unreachable; } + unreachable; } fn fromDataLoc(flush: *const Flush, data_loc: Wasm.DataLoc, addend: i32) RelocAddr { @@ -1702,13 +2712,11 @@ fn emitInitMemoryFunction( } const segment_groups = wasm.flush_buffer.data_segment_groups.items; - var prev_end: u32 = 0; for (segment_groups, 0..) |group, segment_index| { - defer prev_end = group.end_addr; const segment = group.first_segment; if (!segment.isPassive(wasm)) continue; - const start_addr: u32 = @intCast(segment.alignment(wasm).forward(prev_end)); + const start_addr = wasm.flush_buffer.data_segments.get(segment).?; const segment_size: u32 = group.end_addr - start_addr; try binary_bytes.ensureUnusedCapacity(gpa, 6 + 6 + 1 + 5 + 6 + 6 + 1 + 6 * 2 + 1 + 1); @@ -2028,12 +3036,15 @@ fn appendReservedUleb32(bytes: *ArrayList(u8), val: u32) void { }; } -fn appendGlobal(gpa: Allocator, bytes: *ArrayList(u8), mutable: u8, val: u32) Allocator.Error!void { - try bytes.ensureUnusedCapacity(gpa, 9); - bytes.appendAssumeCapacity(@backingInt(std.wasm.Valtype.i32)); +fn appendGlobal(gpa: Allocator, bytes: *ArrayList(u8), mutable: u8, val: u64, is64: bool) Allocator.Error!void { + try bytes.ensureUnusedCapacity(gpa, if (is64) 14 else 9); + bytes.appendAssumeCapacity(@backingInt(@as(std.wasm.Valtype, if (is64) .i64 else .i32))); bytes.appendAssumeCapacity(mutable); - bytes.appendAssumeCapacity(@backingInt(std.wasm.Opcode.i32_const)); - appendReservedUleb32(bytes, val); + if (is64) { + appendReservedI64Const(bytes, val); + } else { + appendReservedI32Const(bytes, @intCast(val)); + } bytes.appendAssumeCapacity(@backingInt(std.wasm.Opcode.end)); } diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index a9b5a1fe42a27b160b833b9854468ebbba419c17..dbd02289d66cd40ce3e5c43d7cb6ff99f9570dd2 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -146,7 +146,7 @@ pub const Symbol = struct { pointee: Pointee, /// https://github.com/WebAssembly/tool-conventions/blob/df8d737539eb8a8f446ba5eab9dc670c40dfb81e/Linking.md#symbol-table-subsection - const Tag = enum(u8) { + pub const Tag = enum(u8) { function, data, global, @@ -856,7 +856,7 @@ pub fn parse( start_function = @fromBackingInt(@intCast(functions_start + index)); }, .element => { - log.warn("unimplemented: element section in {f} {?s}", .{ path, archive_member_name }); + // element section is not needed for linking, validating it serves no purpose pos = section_end; }, .code => { diff --git a/src/main.zig b/src/main.zig index 4fe6de03247578285c251daed3eb8d3982ac5dca..4ef9537109d9adf1f09048d8e7f28f5aa2780d9b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -44,9 +44,9 @@ pub const std_options: std.Options = .{ .logFn = log, .log_level = switch (builtin.mode) { - .Debug => .debug, - .ReleaseSafe, .ReleaseFast => .info, - .ReleaseSmall => .err, + .debug => .debug, + .safe, .fast => .info, + .small => .err, }, }; pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null; @@ -158,8 +158,8 @@ pub fn log( const use_safe_allocator = build_options.debug_gpa or (native_os != .wasi and !builtin.link_libc and switch (builtin.mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, + .debug, .safe => true, + .fast, .small => false, }); var safe_allocator: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{ @@ -359,8 +359,7 @@ fn mainArgs( .prepend_global_cache_path = true, .prepend_zig_exe_path = true, .prepend_seed = true, - .debug_env_var = .ZIG_DEBUG_MAKER, - .release_mode = .ReleaseSafe, + .release_mode = .safe, }); }, .clang, .@"-cc1", .@"-cc1as" => { @@ -557,10 +556,6 @@ const usage_build_generic = \\ -fno-function-sections All functions go into same section \\ -fdata-sections Places each data in a separate section \\ -fno-data-sections All data go into same section - \\ -fformatted-panics Enable formatted safety panics - \\ -fno-formatted-panics Disable formatted safety panics - \\ -fstructured-cfg (SPIR-V) force SPIR-V kernels to use structured control flow - \\ -fno-structured-cfg (SPIR-V) force SPIR-V kernels to not use structured control flow \\ -mexec-model=[value] (WASI) Execution model \\ -municode (Windows) Use wmain/wWinMain as entry point \\ --time-report Send timing diagnostics to '--listen' clients @@ -568,10 +563,10 @@ const usage_build_generic = \\Per-Module Compile Options: \\ -target [name] -- see the targets command \\ -O [mode] Choose what to optimize for - \\ Debug (default) Optimizations off, safety on - \\ ReleaseFast Optimize for performance, safety off - \\ ReleaseSafe Optimize for performance, safety on - \\ ReleaseSmall Optimize for small binary, safety off + \\ debug (default) Prioritize bug detection, accurate debug info, compilation speed + \\ fast Prioritize runtime performance. Safety checks off. + \\ safe Enable both safety checks and machine code optimizations + \\ small Prioritize small binary size. Safety checks off. \\ -ofmt=[fmt] Override target object format \\ elf Executable and Linking Format \\ c C source code @@ -994,7 +989,7 @@ fn buildOutputType( var minor_subsystem_version: ?u16 = null; var mingw_unicode_entry_point: bool = false; var enable_link_snapshots: bool = false; - var debug_compiler_runtime_libs: ?std.lang.OptimizeMode = null; + var debug_compiler_runtime_libs: ?std.lang.Optimize = null; var install_name: ?[]const u8 = null; var hash_style: link.File.Lld.Elf.HashStyle = .both; var entitlements: ?[]const u8 = null; @@ -1200,10 +1195,6 @@ fn buildOutputType( if (mem.eql(u8, next_arg, "--")) break; try extra_rcflags.append(arena, next_arg); } - } else if (mem.eql(u8, arg, "-fstructured-cfg")) { - mod_opts.structured_cfg = true; - } else if (mem.eql(u8, arg, "-fno-structured-cfg")) { - mod_opts.structured_cfg = false; } else if (mem.eql(u8, arg, "--color")) { const next_arg = args_iter.next() orelse { fatal("expected [auto|on|off] after --color", .{}); @@ -1433,7 +1424,7 @@ fn buildOutputType( enable_link_snapshots = true; } } else if (mem.eql(u8, arg, "--debug-rt")) { - debug_compiler_runtime_libs = .Debug; + debug_compiler_runtime_libs = .debug; } else if (mem.cutPrefix(u8, arg, "--debug-rt=")) |rest| { debug_compiler_runtime_libs = parseOptimizeMode(rest); } else if (mem.eql(u8, arg, "--debug-incremental")) { @@ -1650,12 +1641,6 @@ fn buildOutputType( create_module.opts.debug_format = .{ .dwarf = .@"32" }; } else if (mem.eql(u8, arg, "-gdwarf64")) { create_module.opts.debug_format = .{ .dwarf = .@"64" }; - } else if (mem.eql(u8, arg, "-fformatted-panics")) { - // Remove this after 0.15.0 is tagged. - warn("-fformatted-panics is deprecated and does nothing", .{}); - } else if (mem.eql(u8, arg, "-fno-formatted-panics")) { - // Remove this after 0.15.0 is tagged. - warn("-fno-formatted-panics is deprecated and does nothing", .{}); } else if (mem.eql(u8, arg, "-fsingle-threaded")) { mod_opts.single_threaded = true; } else if (mem.eql(u8, arg, "-fno-single-threaded")) { @@ -2162,7 +2147,7 @@ fn buildOutputType( preprocessor_arg[0] == '-' and preprocessor_arg[2] != '-') { - if (mem.indexOfScalar(u8, preprocessor_arg, '=')) |equals_pos| { + if (mem.findScalar(u8, preprocessor_arg, '=')) |equals_pos| { const key = preprocessor_arg[0..equals_pos]; const value = preprocessor_arg[equals_pos + 1 ..]; try preprocessor_args.append(key); @@ -2184,7 +2169,7 @@ fn buildOutputType( linker_arg[0] == '-' and linker_arg[2] != '-') { - if (mem.indexOfScalar(u8, linker_arg, '=')) |equals_pos| { + if (mem.findScalar(u8, linker_arg, '=')) |equals_pos| { const key = linker_arg[0..equals_pos]; const value = linker_arg[equals_pos + 1 ..]; @@ -2271,18 +2256,18 @@ fn buildOutputType( if (mem.eql(u8, level, "s") or mem.eql(u8, level, "z")) { - mod_opts.optimize_mode = .ReleaseSmall; + mod_opts.optimize_mode = .small; } else if (mem.eql(u8, level, "1") or mem.eql(u8, level, "2") or mem.eql(u8, level, "3") or mem.eql(u8, level, "4") or mem.eql(u8, level, "fast")) { - mod_opts.optimize_mode = .ReleaseFast; + mod_opts.optimize_mode = .fast; } else if (mem.eql(u8, level, "g") or mem.eql(u8, level, "0")) { - mod_opts.optimize_mode = .Debug; + mod_opts.optimize_mode = .debug; } else { try cc_argv.appendSlice(arena, it.other_args); } @@ -2356,9 +2341,9 @@ fn buildOutputType( // `sanitize_c` will resolve to! So we either have to pick `off` or `full`. // // `full` has the potential to be problematic if `optimize_mode` turns out to - // be `ReleaseFast`/`ReleaseSmall` because the user will get a slower and larger + // be `fast`/`small` because the user will get a slower and larger // binary than expected. On the other hand, if `optimize_mode` turns out to be - // `Debug`/`ReleaseSafe`, `off` would mean UBSan would unexpectedly be disabled. + // `debug`/`safe`, `off` would mean UBSan would unexpectedly be disabled. // // `off` seems very slightly less bad, so let's go with that. mod_opts.sanitize_c = .off; @@ -2392,7 +2377,7 @@ fn buildOutputType( // Handle joined args like `--dependency-file=foo.d`. // Must be prefixed with 1 or 2 dashes. if (it.only_arg.len >= 3 and it.only_arg[0] == '-' and it.only_arg[2] != '-') { - if (mem.indexOfScalar(u8, it.only_arg, '=')) |equals_pos| { + if (mem.findScalar(u8, it.only_arg, '=')) |equals_pos| { const key = it.only_arg[0..equals_pos]; const value = it.only_arg[equals_pos + 1 ..]; @@ -2972,8 +2957,8 @@ fn buildOutputType( } if (mod_opts.sanitize_c) |wsc| { - if (wsc != .off and mod_opts.optimize_mode == .ReleaseFast) { - mod_opts.optimize_mode = .ReleaseSafe; + if (wsc != .off and mod_opts.optimize_mode == .fast) { + mod_opts.optimize_mode = .safe; } } @@ -3835,11 +3820,17 @@ fn buildOutputType( var prev_has_cflags = false; var prev_has_rcflags = false; - if (dirs.zig_lib.path) |zig_lib_path| { - try test_exec_args.appendSlice(arena, &.{ "-cflags", "-I", zig_lib_path, "--" }); - prev_has_cflags = true; + { + if (dirs.zig_lib.path) |zig_lib_path| { + try test_exec_args.appendSlice(arena, &.{ "-cflags", "-I", zig_lib_path, "--" }); + prev_has_cflags = true; + } + const emit_ext: Compilation.FileExt = .c; + const need_lang = if (comp.emit_bin) |comp_emit_bin| Compilation.classifyFileExt(comp_emit_bin) != emit_ext else true; + if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", emit_ext.toLang() }); + try test_exec_args.append(arena, null); + if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", "none" }); } - try test_exec_args.append(arena, null); for (create_module.modules.keys(), create_module.modules.values()) |mod_name, mod| { for (create_module.c_source_files.items[mod.c_source_files_start..mod.c_source_files_end]) |c_source_file| { const cflags_len = c_source_file.extra_flags.len + c_source_file.cache_exempt_flags.len; @@ -4305,11 +4296,8 @@ fn serve( const gpa = comp.gpa; const io = comp.io; - var server = try Server.init(.{ - .in = in, - .out = out, - .zig_version = build_options.version, - }); + var server: Server = .{ .in = in, .out = out }; + try server.serveStringMessage(.zig_version, build_options.version); var child_pid: ?std.process.Child.Id = null; @@ -4874,8 +4862,7 @@ const JitCmdOptions = struct { capture: ?*[]u8 = null, /// Send error bundles via std.zig.Server over stdout server: bool = false, - debug_env_var: EnvVar = .ZIG_DEBUG_CMD, - release_mode: std.lang.OptimizeMode = .ReleaseFast, + release_mode: std.lang.Optimize = .fast, }; fn jitCmd( @@ -4926,11 +4913,11 @@ fn jitCmdInner( const self_exe_path = process.executablePathAlloc(io, arena) catch |err| fatal("unable to find self exe path: {t}", .{err}); - const optimize_mode: std.lang.OptimizeMode = if (options.debug_env_var.isSet(environ_map)) - .Debug + const optimize_mode: std.lang.Optimize = if (EnvVar.ZIG_DEBUG_CMD.isSet(environ_map)) + .debug else options.release_mode; - const strip = optimize_mode != .Debug; + const strip = optimize_mode != .debug; var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map); const override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map); @@ -6008,9 +5995,8 @@ fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes { fatal("unsupported rc includes type: {q}", .{arg}); } -fn parseOptimizeMode(s: []const u8) std.lang.OptimizeMode { - return stringToEnum(std.lang.OptimizeMode, s) orelse - fatal("unrecognized optimization mode: {q}", .{s}); +fn parseOptimizeMode(s: []const u8) std.lang.Optimize { + return std.lang.Optimize.fromString(s) orelse fatal("unrecognized optimization mode: {q}", .{s}); } fn parseWasiExecModel(s: []const u8) std.lang.WasiExecModel { diff --git a/src/print_targets.zig b/src/print_targets.zig index 702a684de3e829b8e7d475c265a5ed2e584caa1e..695a9a5ef4dc168b85d479f691073d4008efa3a8 100644 --- a/src/print_targets.zig +++ b/src/print_targets.zig @@ -43,9 +43,9 @@ pub fn cmdTargets( { var root_obj = try serializer.beginStruct(.{}); - try root_obj.field("arch", meta.fieldNames(Target.Cpu.Arch), .{}); - try root_obj.field("os", meta.fieldNames(Target.Os.Tag), .{}); - try root_obj.field("abi", meta.fieldNames(Target.Abi), .{}); + try root_obj.field("arch", @typeInfo(Target.Cpu.Arch).@"enum".field_names, .{}); + try root_obj.field("os", @typeInfo(Target.Os.Tag).@"enum".field_names, .{}); + try root_obj.field("abi", @typeInfo(Target.Abi).@"enum".field_names, .{}); { var libc_obj = try root_obj.beginTupleField("libc", .{}); diff --git a/src/target.zig b/src/target.zig index ca3b3d93de1a74114d621c8065e96d561e413dc8..4bc3853ae75c593ab39cf0ccd276cba2dac0fca1 100644 --- a/src/target.zig +++ b/src/target.zig @@ -12,7 +12,6 @@ pub const default_stack_protector_buffer_size = 4; pub fn canDynamicLink(target: *const std.Target) bool { return switch (target.cpu.arch) { - .amdgcn, .bpfeb, .bpfel, .nvptx, @@ -119,10 +118,6 @@ pub fn defaultSingleThreaded(target: *const std.Target) bool { .wasm32, .wasm64 => return true, else => {}, } - switch (target.os.tag) { - .haiku => return true, - else => {}, - } return false; } @@ -357,12 +352,12 @@ pub fn libcProvidesStackProtector(target: *const std.Target) bool { /// Returns true if `@returnAddress()` is supported by the target and has a /// reasonably performant implementation for the requested optimization mode. -pub fn supportsReturnAddress(target: *const std.Target, optimize: std.lang.OptimizeMode) bool { +pub fn supportsReturnAddress(target: *const std.Target, optimize: std.lang.Optimize) bool { return switch (target.cpu.arch) { // Emscripten currently implements `emscripten_return_address()` by calling // out into JavaScript and parsing a stack trace, which introduces significant // overhead that we would prefer to avoid in release builds. - .wasm32, .wasm64 => target.os.tag == .emscripten and optimize == .Debug, + .wasm32, .wasm64 => target.os.tag == .emscripten and optimize == .debug, .bpfel, .bpfeb => false, .spirv32, .spirv64 => false, else => true, @@ -417,11 +412,11 @@ pub fn hasDebugInfo(target: *const std.Target) bool { }; } -pub fn defaultCompilerRtOptimizeMode(target: *const std.Target) std.lang.OptimizeMode { +pub fn defaultCompilerRtOptimizeMode(target: *const std.Target) std.lang.Optimize { if (target.cpu.arch.isWasm() and target.os.tag == .freestanding) { - return .ReleaseSmall; + return .small; } else { - return .ReleaseFast; + return .fast; } } @@ -437,7 +432,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl else => {}, } return switch (zigBackend(target, false)) { - .stage2_aarch64, .stage2_x86_64 => .yes, + .stage2_aarch64, .stage2_wasm, .stage2_x86_64 => .yes, else => .llvm_only, }; } @@ -450,7 +445,7 @@ pub fn canBuildLibUbsanRt(target: *const std.Target) enum { no, yes, llvm_only, else => {}, } return switch (zigBackend(target, false)) { - .stage2_wasm => .llvm_lld_only, + .stage2_wasm => .yes, .stage2_x86_64 => .yes, else => .llvm_only, }; @@ -681,14 +676,14 @@ pub fn isDynamicAMDGCNFeature(target: *const std.Target, feature: std.Target.Cpu const feature_tag: std.Target.amdgcn.Feature = @fromBackingInt(@intCast(feature.index)); if (feature_tag == .sramecc) { - if (std.mem.indexOfScalar( + if (std.mem.findScalar( *const std.Target.Cpu.Model, sramecc_only ++ xnack_or_sramecc, target.cpu.model, )) |_| return true; } if (feature_tag == .xnack) { - if (std.mem.indexOfScalar( + if (std.mem.findScalar( *const std.Target.Cpu.Model, xnack_or_sramecc, target.cpu.model, @@ -876,18 +871,18 @@ pub fn libcFloatSuffix(float_bits: u16) []const u8 { 32 => "f", 64 => "", 80 => "x", // Non-standard - 128 => "q", // Non-standard (mimics convention in GCC libquadmath) + 128 => "f128", else => unreachable, }; } -pub fn compilerRtFloatAbbrev(float_bits: u16) []const u8 { +pub fn compilerRtFloatAbbrev(target: *const std.Target, float_bits: u16) []const u8 { return switch (float_bits) { 16 => "h", 32 => "s", 64 => "d", 80 => "x", - 128 => "t", + 128 => if (target.cpu.arch.isPowerPC()) "k" else "t", else => unreachable, }; } diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 9bba8e96d5107c6bf20ea2fd7f15e3df243d5bac..6b3ff4a5fbe626b37c0a49f7b734564c6563201e 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -473,19 +473,32 @@ void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) { } bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, - ZigLLVMArchiveKind archive_kind) + ZigLLVMArchiveKind archive_kind, size_t *err_file_index_out, char **err_msg_out) { SmallVector new_members; for (size_t i = 0; i < file_name_count; i += 1) { Expected new_member = NewArchiveMember::getFile(file_names[i], true); Error err = new_member.takeError(); - if (err) return true; + if (err) { + *err_file_index_out = i; + const std::string msg = toString(std::move(err)); + *err_msg_out = (char *)malloc(msg.length() + 1); + strcpy(*err_msg_out, msg.c_str()); + return true; + } new_members.push_back(std::move(*new_member)); } Error err = writeArchive(archive_name, new_members, SymtabWritingMode::NormalSymtab, static_cast(archive_kind), true, false, nullptr); - if (err) return true; + if (err) { + *err_file_index_out = file_name_count; + const std::string msg = toString(std::move(err)); + *err_msg_out = (char *)malloc(msg.length() + 1); + strcpy(*err_msg_out, msg.c_str()); + return true; + } + return false; } diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 64da388d477bfed46e0c4ae2e7da1cd16c73ce57..79ba0272df2f73743705ac832f5d508b5099542d 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -121,7 +121,12 @@ ZIG_EXTERN_C bool ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_earl ZIG_EXTERN_C bool ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early, bool disable_output); ZIG_EXTERN_C bool ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early, bool disable_output); +// On error, populates `*err_file_index_out` and `*err_msg_out` and returns `true`. The caller is +// responsible for freeing `*err_msg_out` using `free`. +// +// If an error occurs reading an input file, `*err_file_index_out` is set to the index of that input +// file in `file_names`. Otherwise, `*err_file_index_out` is set to `file_name_count`. ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, - ZigLLVMArchiveKind archive_kind); + ZigLLVMArchiveKind archive_kind, size_t *err_file_index_out, char **err_msg_out); #endif diff --git a/stage1/FuncGen.h b/stage1/FuncGen.h index 494dd202b224fdb927efc3119f670fafa1def207..5f62b249862ac29656d7d1231d55504b93746fd4 100644 --- a/stage1/FuncGen.h +++ b/stage1/FuncGen.h @@ -52,17 +52,17 @@ static void FuncGen_free(struct FuncGen *self) { } static void FuncGen_outdent(struct FuncGen *self, FILE *out) { - for (uint32_t i = 0; i < self->block_i; i += 1) fputs(" ", out); + for (uint32_t i = 0; i < self->block_i; i += 1) fputs(" ", out); } static void FuncGen_indent(struct FuncGen *self, FILE *out) { FuncGen_outdent(self, out); - fputs(" ", out); + fputs(" ", out); } static void FuncGen_cont(struct FuncGen *self, FILE *out) { FuncGen_indent(self, out); - fputs(" ", out); + fputs(" ", out); } static uint32_t FuncGen_localAlloc(struct FuncGen *self, int8_t type) { diff --git a/stage1/wasm2c.c b/stage1/wasm2c.c index adbf8667e5fbc8d6a4a0c56c26d78ea2185543bb..8363a332b4063ae37bafa10f53832aea91e56c03 100644 --- a/stage1/wasm2c.c +++ b/stage1/wasm2c.c @@ -518,8 +518,8 @@ int main(int argc, char **argv) { } fprintf(out, ") {\n" - " init();\n" - " %sf%" PRIu32 "(", + " init();\n" + " %sf%" PRIu32 "(", func_type->result->len > 0 ? "return " : "", idx - imports_len); for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { if (param_i > 0) fputs(", ", out); @@ -552,7 +552,7 @@ int main(int argc, char **argv) { uint32_t segment_len = InputStream_readLeb128_u32(&in); for (uint32_t i = 0; i < segment_len; i += 1) { uint32_t func_id = InputStream_readLeb128_u32(&in); - fprintf(out, " t%" PRIu32 "[UINT32_C(%" PRIu32 ")] = (void (*)(void))&", + fprintf(out, " t%" PRIu32 "[UINT32_C(%" PRIu32 ")] = (void (*)(void))&", table_idx, offset + i); if (func_id < imports_len) fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name); @@ -2260,9 +2260,9 @@ int main(int argc, char **argv) { uint32_t len = InputStream_readLeb128_u32(&in); fputs("static void init_data(void) {\n", out); for (uint32_t i = 0; i < mems_len; i += 1) - fprintf(out, " p%" PRIu32 " = UINT32_C(%" PRIu32 ");\n" - " c%" PRIu32 " = p%" PRIu32 ";\n" - " m%" PRIu32 " = calloc(c%" PRIu32 ", UINT32_C(1) << 16);\n", + fprintf(out, " p%" PRIu32 " = UINT32_C(%" PRIu32 ");\n" + " c%" PRIu32 " = p%" PRIu32 ";\n" + " m%" PRIu32 " = calloc(c%" PRIu32 ", UINT32_C(1) << 16);\n", i, mems[i].limits.min, i, i, i, i); for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) { uint32_t mem_idx; @@ -2280,15 +2280,15 @@ int main(int argc, char **argv) { uint32_t offset = evalExpr(&in); uint32_t segment_len = InputStream_readLeb128_u32(&in); fputc('\n', out); - fprintf(out, " static const uint8_t s%" PRIu32 "[UINT32_C(%" PRIu32 ")] = {", + fprintf(out, " static const uint8_t s%" PRIu32 "[UINT32_C(%" PRIu32 ")] = {", segment_i, segment_len); for (uint32_t i = 0; i < segment_len; i += 1) { if (i % 32 == 0) fputs("\n ", out); fprintf(out, " 0x%02hhX,", InputStream_readByte(&in)); } fprintf(out, "\n" - " };\n" - " memcpy(&m%" PRIu32 "[UINT32_C(0x%" PRIX32 ")], s%" PRIu32 ", UINT32_C(%" PRIu32 "));\n", + " };\n" + " memcpy(&m%" PRIu32 "[UINT32_C(0x%" PRIX32 ")], s%" PRIu32 ", UINT32_C(%" PRIu32 "));\n", mem_idx, offset, segment_i, segment_len); } fputs("}\n", out); diff --git a/stage1/zig.h b/stage1/zig.h index fbc924ca334e99eb12d2f37e3ebffa970ced7b9d..30e6f3f96a97f47b6648db1d1587bc75c88b6c3f 100644 --- a/stage1/zig.h +++ b/stage1/zig.h @@ -166,6 +166,12 @@ #endif #define zig_expand_has_builtin(b) zig_has_builtin(b) +#if defined(__has_feature) +#define zig_has_feature(feature) __has_feature(feature) +#else +#define zig_has_feature(feature) 0 +#endif + #if defined(__has_attribute) #define zig_has_attribute(attribute) __has_attribute(attribute) #else @@ -175,9 +181,9 @@ #if __STDC_VERSION__ >= 201112L #define zig_static_assert(cond, msg) _Static_assert(cond, msg) #elif zig_has_attribute(unused) -#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] __attribute__((unused)) +#define zig_static_assert(cond, msg) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[(cond) ? 1 : -1] __attribute__((unused)) #else -#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] +#define zig_static_assert(cond, msg) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[(cond) ? 1 : -1] #endif #if __STDC_VERSION__ >= 202311L @@ -193,10 +199,8 @@ #endif #if defined(zig_msvc) -#define zig_const_arr #define zig_callconv(c) __##c #else -#define zig_const_arr static const #define zig_callconv(c) __attribute__((c)) #endif @@ -267,12 +271,20 @@ #if __STDC_VERSION__ >= 202311L #define zig_align(alignment) alignas(alignment) -#elif __STDC_VERSION__ >= 201112L +#elif __STDC_VERSION__ >= 201112L || zig_has_feature(c_alignas) #define zig_align(alignment) _Alignas(alignment) #else #define zig_align(alignment) zig_under_align(alignment) #endif +#if __STDC_VERSION__ >= 202311L +#define zig_alignOf(Type) alignof(Type) +#elif __STDC_VERSION__ >= 201112L || zig_has_feature(c_alignof) +#define zig_alignOf(Type) _Alignof(Type) +#else +#define zig_alignOf(Type) (sizeof(struct { char c; Type t; }) - sizeof(Type)) +#endif + #if zig_has_attribute(aligned) || defined(zig_tinyc) #define zig_align_fn(alignment) __attribute__((aligned(alignment))) #elif defined(zig_msvc) @@ -350,11 +362,9 @@ #define zig_export(symbol, name) __attribute__((alias(symbol))) #else #define zig_export(symbol, name) ; \ - __asm(zig_mangle_c(name) " = " zig_mangle_c(symbol)) + __asm("\t.globl\t" zig_mangle_c(name) "\n" zig_mangle_c(name) " = " zig_mangle_c(symbol)) #endif -#define zig_mangled_tentative zig_mangled -#define zig_mangled_final zig_mangled #if defined(zig_msvc) #define zig_mangled(mangled, unmangled) ; \ zig_export(#mangled, unmangled) @@ -364,7 +374,7 @@ #else /* zig_msvc */ #define zig_mangled(mangled, unmangled) __asm(zig_mangle_c(unmangled)) #define zig_mangled_export(mangled, unmangled, symbol) \ - zig_mangled_final(mangled, unmangled) \ + zig_mangled(mangled, unmangled) \ zig_export(symbol, unmangled) #endif /* zig_msvc */ @@ -550,6 +560,9 @@ #define zig_noreturn #endif +#define zig_has_always 1 +#define zig_has_never 0 + #define zig_compiler_rt_abbrev_uint32_t si #define zig_compiler_rt_abbrev_int32_t si #define zig_compiler_rt_abbrev_uint64_t di @@ -560,7 +573,11 @@ #define zig_compiler_rt_abbrev_zig_f32 sf #define zig_compiler_rt_abbrev_zig_f64 df #define zig_compiler_rt_abbrev_zig_f80 xf +#ifdef zig_powerpc +#define zig_compiler_rt_abbrev_zig_f128 kf +#else #define zig_compiler_rt_abbrev_zig_f128 tf +#endif zig_extern void *memcpy (void *zig_restrict, void const *zig_restrict, size_t); zig_extern void *memset (void *, int, size_t); @@ -645,16 +662,6 @@ typedef signed long long int16_t; #define INT16_MAX ( INT16_C(0x7FFF)) #define UINT16_MAX ( INT16_C(0xFFFF)) -#if defined(zig_ez80) -typedef unsigned int uint24_t; -typedef signed int int24_t; -#define INT24_C(c) c -#define UINT24_C(c) c##U -#endif -#define INT24_MIN (~INT24_C(0x7FFF)) -#define INT24_MAX ( INT24_C(0x7FFF)) -#define UINT24_MAX ( INT24_C(0xFFFF)) - #if SCHAR_MIN == ~0x7FFFFFFF && SCHAR_MAX == 0x7FFFFFFF && UCHAR_MAX == 0xFFFFFFFF typedef unsigned char uint32_t; typedef signed char int32_t; @@ -685,17 +692,6 @@ typedef signed long long int32_t; #define INT32_MAX ( INT32_C(0x7FFFFFFF)) #define UINT32_MAX ( INT32_C(0xFFFFFFFF)) -#if defined(zig_ez80) -typedef unsigned __int48 uint48_t; -typedef signed __int48 int48_t; -#define INT48_C(c) c -/* no suffix */ -#define UINT48_C(c) ((uint48_t)(c)) -#endif -#define INT48_MIN (~INT48_C(0x7FFFFFFFFFFF)) -#define INT48_MAX ( INT48_C(0x7FFFFFFFFFFF)) -#define UINT48_MAX ( INT48_C(0xFFFFFFFFFFFF)) - #if SCHAR_MIN == ~0x7FFFFFFFFFFFFFFF && SCHAR_MAX == 0x7FFFFFFFFFFFFFFF && UCHAR_MAX == 0xFFFFFFFFFFFFFFFF typedef unsigned char uint64_t; typedef signed char int64_t; @@ -726,6 +722,27 @@ typedef signed long long int64_t; #define INT64_MAX ( INT64_C(0x7FFFFFFFFFFFFFFF)) #define UINT64_MAX ( INT64_C(0xFFFFFFFFFFFFFFFF)) +#if defined(zig_ez80) + +typedef unsigned int uint24_t; +typedef signed int int24_t; +#define INT24_C(c) c +#define UINT24_C(c) c##U +#define INT24_MIN (~INT24_C(0x7FFF)) +#define INT24_MAX ( INT24_C(0x7FFF)) +#define UINT24_MAX ( INT24_C(0xFFFF)) + +typedef unsigned __int48 uint48_t; +typedef signed __int48 int48_t; +#define INT48_C(c) c +/* no suffix */ +#define UINT48_C(c) ((uint48_t)(c)) +#define INT48_MIN (~INT48_C(0x7FFFFFFFFFFF)) +#define INT48_MAX ( INT48_C(0x7FFFFFFFFFFF)) +#define UINT48_MAX ( INT48_C(0xFFFFFFFFFFFF)) + +#endif + typedef size_t uintptr_t; typedef ptrdiff_t intptr_t; @@ -739,23 +756,145 @@ typedef ptrdiff_t intptr_t; #define zig_maxInt_i16 INT16_MAX #define zig_minInt_u16 UINT16_C(0) #define zig_maxInt_u16 UINT16_MAX -#define zig_minInt_i24 INT24_MIN -#define zig_maxInt_i24 INT24_MAX -#define zig_minInt_u24 UINT24_C(0) -#define zig_maxInt_u24 UINT24_MAX #define zig_minInt_i32 INT32_MIN #define zig_maxInt_i32 INT32_MAX #define zig_minInt_u32 UINT32_C(0) #define zig_maxInt_u32 UINT32_MAX -#define zig_minInt_i48 INT48_MIN -#define zig_maxInt_i48 INT48_MAX -#define zig_minInt_u48 UINT48_C(0) -#define zig_maxInt_u48 UINT48_MAX #define zig_minInt_i64 INT64_MIN #define zig_maxInt_i64 INT64_MAX #define zig_minInt_u64 UINT64_C(0) #define zig_maxInt_u64 UINT64_MAX +// zig_promoted_T implements C integral promotions except with signedness preserved, which +// allows wrapping operations to avoid the ub that would be caused by the normal promotion. + +#if INT8_MAX <= INT_MAX +typedef unsigned int zig_promoted_i8; +#elif INT8_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i8; +#elif INT8_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i8; +#else +typedef int8_t zig_promoted_i8; +#endif +#if UINT8_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u8; +#elif UINT8_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u8; +#elif UINT8_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u8; +#else +typedef uint8_t zig_promoted_u8; +#endif + +#if INT16_MAX <= INT_MAX +typedef unsigned int zig_promoted_i16; +#elif INT16_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i16; +#elif INT16_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i16; +#else +typedef int16_t zig_promoted_i16; +#endif +#if UINT16_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u16; +#elif UINT16_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u16; +#elif UINT16_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u16; +#else +typedef uint16_t zig_promoted_u16; +#endif + +#if INT32_MAX <= INT_MAX +typedef unsigned int zig_promoted_i32; +#elif INT32_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i32; +#elif INT32_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i32; +#else +typedef int32_t zig_promoted_i32; +#endif +#if UINT32_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u32; +#elif UINT32_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u32; +#elif UINT32_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u32; +#else +typedef uint32_t zig_promoted_u32; +#endif + +#if INT64_MAX <= INT_MAX +typedef unsigned int zig_promoted_i64; +#elif INT64_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i64; +#elif INT64_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i64; +#else +typedef int64_t zig_promoted_i64; +#endif +#if UINT64_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u64; +#elif UINT64_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u64; +#elif UINT64_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u64; +#else +typedef uint64_t zig_promoted_u64; +#endif + +#ifdef zig_ez80 + +#define zig_minInt_i24 INT24_MIN +#define zig_maxInt_i24 INT24_MAX +#define zig_minInt_u24 UINT24_C(0) +#define zig_maxInt_u24 UINT24_MAX +#define zig_minInt_i48 INT48_MIN +#define zig_maxInt_i48 INT48_MAX +#define zig_minInt_u48 UINT48_C(0) +#define zig_maxInt_u48 UINT48_MAX + +#if INT24_MAX <= INT_MAX +typedef unsigned int zig_promoted_i24; +#elif INT24_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i24; +#elif INT24_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i24; +#else +typedef int24_t zig_promoted_i24; +#endif +#if UINT24_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u24; +#elif UINT24_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u24; +#elif UINT24_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u24; +#else +typedef uint24_t zig_promoted_u24; +#endif + +#if INT48_MAX <= INT_MAX +typedef unsigned int zig_promoted_i48; +#elif INT48_MAX <= LONG_MAX +typedef unsigned long zig_promoted_i48; +#elif INT48_MAX <= LLONG_MAX +typedef unsigned long long zig_promoted_i48; +#else +typedef int48_t zig_promoted_i48; +#endif +#if UINT48_MAX <= UINT_MAX +typedef unsigned int zig_promoted_u48; +#elif UINT48_MAX <= ULONG_MAX +typedef unsigned long zig_promoted_u48; +#elif UINT48_MAX <= ULLONG_MAX +typedef unsigned long long zig_promoted_u48; +#else +typedef uint48_t zig_promoted_u48; +#endif + +#endif + #define zig_intLimit(s, w, limit, bits) zig_shr_##s##w(zig_##limit##Int_##s##w, w - (bits)) #define zig_minInt_i(w, bits) zig_intLimit(i, w, min, bits) #define zig_maxInt_i(w, bits) zig_intLimit(i, w, max, bits) @@ -770,7 +909,33 @@ typedef ptrdiff_t intptr_t; zig_operator(Type, Type, operation, operator) #define zig_shift_operator(Type, operation, operator) \ zig_operator(Type, uint8_t, operation, operator) -#define zig_int_helpers(w, PromotedUnsigned) \ + +#define zig_int_casts_common(bw, sw) \ + static inline uint##bw##_t zig_u##bw##_intCast_u##sw(uint##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline uint##bw##_t zig_u##bw##_intCast_i##sw(int##sw##_t arg) { \ + return (uint##bw##_t)arg; \ + } \ +\ + static inline int##bw##_t zig_i##bw##_intCast_u##sw(uint##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline int##bw##_t zig_i##bw##_intCast_i##sw(int##sw##_t arg) { \ + return arg; \ + } \ +\ + static inline uint##sw##_t zig_u##sw##_truncate_u##bw(uint##bw##_t arg, uint8_t bits) { \ + return (uint##sw##_t)arg & zig_maxInt_u(sw, bits); \ + } \ +\ + static inline int##sw##_t zig_i##sw##_truncate_i##bw(int##bw##_t arg, uint8_t bits) { \ + return ((uint##sw##_t)arg & UINT##sw##_C(1) << (bits - UINT8_C(1))) != UINT##sw##_C(0) \ + ? (int##sw##_t)arg | zig_minInt_i(sw, bits) : (int##sw##_t)arg & zig_maxInt_i(sw, bits); \ + } +#define zig_int_operators(w) \ zig_basic_operator(uint##w##_t, and_u##w, &) \ zig_basic_operator( int##w##_t, and_i##w, &) \ zig_basic_operator(uint##w##_t, or_u##w, |) \ @@ -786,44 +951,48 @@ typedef ptrdiff_t intptr_t; return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \ } \ \ - static inline uint##w##_t zig_not_u##w(uint##w##_t val, uint8_t bits) { \ - return val ^ zig_maxInt_u(w, bits); \ + static inline uint##w##_t zig_not_u##w(uint##w##_t arg, uint8_t bits) { \ + return arg ^ zig_maxInt_u(w, bits); \ } \ \ - static inline int##w##_t zig_not_i##w(int##w##_t val, uint8_t bits) { \ + static inline int##w##_t zig_not_i##w(int##w##_t arg, uint8_t bits) { \ (void)bits; \ - return ~val; \ + return ~arg; \ } \ \ - static inline uint##w##_t zig_wrap_u##w(uint##w##_t val, uint8_t bits) { \ - return val & zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_wrap_i##w(int##w##_t val, uint8_t bits) { \ - return (val & UINT##w##_C(1) << (bits - UINT8_C(1))) != 0 \ - ? val | zig_minInt_i(w, bits) : val & zig_maxInt_i(w, bits); \ - } \ -\ - static inline uint##w##_t zig_abs_i##w(int##w##_t val) { \ - return (val < 0) ? -(uint##w##_t)val : (uint##w##_t)val; \ - } \ -\ - zig_basic_operator(uint##w##_t, div_floor_u##w, /) \ + zig_basic_operator(uint##w##_t, divFloor_u##w, /) \ \ - static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \ + static inline int##w##_t zig_divFloor_i##w(int##w##_t lhs, int##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != INT##w##_C(0) ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ } \ \ - static inline uint##w##_t zig_div_ceil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + static inline uint##w##_t zig_divCeil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != UINT##w##_C(0) ? UINT##w##_C(1) : UINT##w##_C(0)); \ } \ \ - static inline int##w##_t zig_div_ceil_i##w(int##w##_t lhs, int##w##_t rhs) { \ + static inline int##w##_t zig_divCeil_i##w(int##w##_t lhs, int##w##_t rhs) { \ return lhs / rhs + (lhs % rhs != INT##w##_C(0) \ ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) + INT##w##_C(1) : INT##w##_C(0)); \ } \ \ zig_basic_operator(uint##w##_t, mod_u##w, %) \ + zig_int_casts_common(w, w) \ +\ + static inline uint##w##_t zig_u##w##_bitCast_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_u##w##_truncate_u##w(arg, bits); \ + } \ +\ + static inline uint##w##_t zig_u##w##_bitCast_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_u##w##_bitCast_u##w((uint##w##_t)arg, bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_bitCast_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_i##w##_truncate_i##w(arg, bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_bitCast_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_i##w##_bitCast_i##w((int##w##_t)arg, bits); \ + } \ \ static inline int##w##_t zig_mod_i##w(int##w##_t lhs, int##w##_t rhs) { \ int##w##_t rem = lhs % rhs; \ @@ -831,100 +1000,102 @@ typedef ptrdiff_t intptr_t; } \ \ static inline uint##w##_t zig_shlw_u##w(uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \ + return zig_u##w##_truncate_u##w(zig_shl_u##w(lhs, rhs), bits); \ } \ \ static inline int##w##_t zig_shlw_i##w(int##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)zig_shl_u##w((uint##w##_t)lhs, rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_shl_u##w(zig_u##w##_bitCast_i##w(lhs, bits), rhs), bits); \ } \ \ static inline uint##w##_t zig_addw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs + rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs + rhs, bits); \ } \ \ static inline int##w##_t zig_addw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs + (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_addw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ } \ \ static inline uint##w##_t zig_subw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs - rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs - rhs, bits); \ } \ \ static inline int##w##_t zig_subw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs - (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_subw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ } \ \ static inline uint##w##_t zig_mulw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w((PromotedUnsigned)lhs * rhs, bits); \ + return zig_u##w##_truncate_u##w((zig_promoted_u##w)lhs * rhs, bits); \ } \ \ static inline int##w##_t zig_mulw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs * (uint##w##_t)rhs), bits); \ + return zig_i##w##_bitCast_u##w(zig_mulw_u##w(zig_u##w##_bitCast_i##w(lhs, bits), zig_u##w##_bitCast_i##w(rhs, bits), bits), bits); \ + } \ +\ + static inline uint##w##_t zig_abs_i##w(int##w##_t arg) { \ + int##w##_t tmp = zig_shr_i##w(arg, UINT8_C(w) - UINT8_C(1)); \ + return zig_u##w##_bitCast_i##w(zig_subw_i##w(zig_xor_i##w(arg, tmp), tmp, UINT8_C(w)), UINT8_C(w)); \ + } \ +\ + static inline uint##w##_t zig_min_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + return lhs < rhs ? lhs : rhs; \ + } \ +\ + static inline int##w##_t zig_min_i##w(int##w##_t lhs, int##w##_t rhs) { \ + return lhs < rhs ? lhs : rhs; \ + } \ +\ + static inline uint##w##_t zig_max_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ + return lhs >= rhs ? lhs : rhs; \ + } \ +\ + static inline int##w##_t zig_max_i##w(int##w##_t lhs, int##w##_t rhs) { \ + return lhs >= rhs ? lhs : rhs; \ } -#if UINT8_MAX <= UINT_MAX -zig_int_helpers(8, unsigned int) -#elif UINT8_MAX <= ULONG_MAX -zig_int_helpers(8, unsigned long) -#elif UINT8_MAX <= ULLONG_MAX -zig_int_helpers(8, unsigned long long) -#else -zig_int_helpers(8, uint8_t) +zig_int_operators(8) +zig_int_operators(16) +zig_int_operators(32) +zig_int_operators(64) +#ifdef zig_ez80 +zig_int_operators(24) +zig_int_operators(48) #endif -#if UINT16_MAX <= UINT_MAX -zig_int_helpers(16, unsigned int) -#elif UINT16_MAX <= ULONG_MAX -zig_int_helpers(16, unsigned long) -#elif UINT16_MAX <= ULLONG_MAX -zig_int_helpers(16, unsigned long long) -#else -zig_int_helpers(16, uint16_t) -#endif -#if defined(zig_ez80) -#if UINT24_MAX <= UINT_MAX -zig_int_helpers(24, unsigned int) -#elif UINT24_MAX <= ULONG_MAX -zig_int_helpers(24, unsigned long) -#elif UINT24_MAX <= ULLONG_MAX -zig_int_helpers(24, unsigned long long) -#else -zig_int_helpers(24, uint24_t) -#endif -#endif -#if UINT32_MAX <= UINT_MAX -zig_int_helpers(32, unsigned int) -#elif UINT32_MAX <= ULONG_MAX -zig_int_helpers(32, unsigned long) -#elif UINT32_MAX <= ULLONG_MAX -zig_int_helpers(32, unsigned long long) -#else -zig_int_helpers(32, uint32_t) -#endif -#if defined(zig_ez80) -#if UINT24_MAX <= UINT_MAX -zig_int_helpers(48, unsigned int) -#elif UINT24_MAX <= ULONG_MAX -zig_int_helpers(48, unsigned long) -#elif UINT24_MAX <= ULLONG_MAX -zig_int_helpers(48, unsigned long long) -#else -zig_int_helpers(48, uint48_t) -#endif -#endif -#if UINT64_MAX <= UINT_MAX -zig_int_helpers(64, unsigned int) -#elif UINT64_MAX <= ULONG_MAX -zig_int_helpers(64, unsigned long) -#elif UINT64_MAX <= ULLONG_MAX -zig_int_helpers(64, unsigned long long) -#else -zig_int_helpers(64, uint64_t) + +#define zig_int_casts(bw, sw) \ + static inline uint##sw##_t zig_u##sw##_intCast_u##bw(uint##bw##_t arg) { \ + return (uint##sw##_t)arg; \ + } \ +\ + static inline uint##sw##_t zig_u##sw##_intCast_i##bw(int##bw##_t arg) { \ + return (uint##sw##_t)arg; \ + } \ +\ + static inline int##sw##_t zig_i##sw##_intCast_u##bw(uint##bw##_t arg) { \ + return (int##sw##_t)arg; \ + } \ +\ + static inline int##sw##_t zig_i##sw##_intCast_i##bw(int##bw##_t arg) { \ + return (int##sw##_t)arg; \ + } \ +\ + zig_int_casts_common(bw, sw) +zig_int_casts(16, 8) +zig_int_casts(32, 8) +zig_int_casts(64, 8) +zig_int_casts(32, 16) +zig_int_casts(64, 16) +zig_int_casts(64, 32) +#ifdef zig_ez80 +zig_int_casts(32, 24) +zig_int_casts(48, 24) +zig_int_casts(64, 24) +zig_int_casts(64, 48) #endif static inline bool zig_addo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_addw_u32(lhs, rhs, bits); @@ -936,19 +1107,19 @@ static inline bool zig_addo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_i32_truncate_i32(full_res, bits); + return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); #else - int32_t full_res = (int32_t)((uint32_t)lhs + (uint32_t)rhs); - bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; + *res = zig_addw_i32(lhs, rhs, bits); + return ((*res ^ lhs) & (*res ^ rhs)) < INT32_C(0); #endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } static inline bool zig_addo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_addw_u64(lhs, rhs, bits); @@ -960,24 +1131,24 @@ static inline bool zig_addo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_i64_truncate_i64(full_res, bits); + return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); #else - int64_t full_res = (int64_t)((uint64_t)lhs + (uint64_t)rhs); - bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; + *res = zig_addw_i64(lhs, rhs, bits); + return ((*res ^ lhs) & (*res ^ rhs)) < INT64_C(0); #endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } static inline bool zig_addo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -986,12 +1157,12 @@ static inline bool zig_addo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(add_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1000,12 +1171,12 @@ static inline bool zig_addo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1014,27 +1185,28 @@ static inline bool zig_addo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_addo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1043,28 +1215,26 @@ static inline bool zig_addo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_addo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(add_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_addo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1073,22 +1243,23 @@ static inline bool zig_addo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(add_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_addo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif static inline bool zig_subo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_subw_u32(lhs, rhs, bits); @@ -1100,20 +1271,19 @@ static inline bool zig_subo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_i32_truncate_i32(full_res, bits); + return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); #else - int32_t full_res = (int32_t)((uint32_t)lhs - (uint32_t)rhs); - bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; + *res = zig_subw_i32(lhs, rhs, bits); + return ((lhs ^ rhs) & (*res ^ lhs)) < INT32_C(0); #endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } - static inline bool zig_subo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_subw_u64(lhs, rhs, bits); @@ -1125,24 +1295,24 @@ static inline bool zig_subo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_i64_truncate_i64(full_res, bits); + return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); #else - int64_t full_res = (int64_t)((uint64_t)lhs - (uint64_t)rhs); - bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; + *res = zig_subw_i64(lhs, rhs, bits); + return ((lhs ^ rhs) & (*res ^ lhs)) < INT64_C(0); #endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } static inline bool zig_subo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -1151,12 +1321,12 @@ static inline bool zig_subo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1165,12 +1335,12 @@ static inline bool zig_subo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1179,27 +1349,28 @@ static inline bool zig_subo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_subo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1208,28 +1379,26 @@ static inline bool zig_subo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_subo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(sub_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_subo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1238,22 +1407,23 @@ static inline bool zig_subo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(sub_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_subo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint32_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); + *res = zig_u32_truncate_u32(full_res, bits); return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); #else *res = zig_mulw_u32(lhs, rhs, bits); @@ -1261,8 +1431,8 @@ static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8 #endif } -zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow); static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) { + zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow); #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int32_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -1271,7 +1441,7 @@ static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t int32_t full_res = __mulosi4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i32(full_res, bits); + *res = zig_i32_truncate_i32(full_res, bits); return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); } @@ -1279,7 +1449,7 @@ static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8 #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint64_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); + *res = zig_u64_truncate_u64(full_res, bits); return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); #else *res = zig_mulw_u64(lhs, rhs, bits); @@ -1287,8 +1457,8 @@ static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8 #endif } -zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) { + zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int64_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -1297,7 +1467,7 @@ static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t int64_t full_res = __mulodi4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i64(full_res, bits); + *res = zig_i64_truncate_i64(full_res, bits); return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); } @@ -1305,12 +1475,12 @@ static inline bool zig_mulo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t b #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint8_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); + *res = zig_u8_truncate_u8(full_res, bits); return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; + *res = zig_u8_intCast_u32(full_res); return overflow; #endif } @@ -1319,12 +1489,12 @@ static inline bool zig_mulo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int8_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); + *res = zig_i8_truncate_i8(full_res, bits); return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; + *res = zig_i8_intCast_i32(full_res); return overflow; #endif } @@ -1333,12 +1503,12 @@ static inline bool zig_mulo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8 #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint16_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); + *res = zig_u16_truncate_u16(full_res, bits); return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; + *res = zig_u16_intCast_u32(full_res); return overflow; #endif } @@ -1347,27 +1517,28 @@ static inline bool zig_mulo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int16_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); + *res = zig_i16_truncate_i16(full_res, bits); return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; + *res = zig_i16_intCast_i32(full_res); return overflow; #endif } #if defined(zig_ez80) + static inline bool zig_mulo_u24(uint24_t *res, uint24_t lhs, uint24_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint24_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u24(full_res, bits); + *res = zig_u24_truncate_u24(full_res, bits); return overflow || full_res < zig_minInt_u(24, bits) || full_res > zig_maxInt_u(24, bits); #else uint32_t full_res; bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint24_t)full_res; + *res = zig_u24_intCast_u32(full_res); return overflow; #endif } @@ -1376,28 +1547,26 @@ static inline bool zig_mulo_i24(int24_t *res, int24_t lhs, int24_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int24_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i24(full_res, bits); + *res = zig_i24_truncate_i24(full_res, bits); return overflow || full_res < zig_minInt_i(24, bits) || full_res > zig_maxInt_i(24, bits); #else int32_t full_res; bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int24_t)full_res; + *res = zig_i24_intCast_i32(full_res); return overflow; #endif } -#endif -#if defined(zig_ez80) static inline bool zig_mulo_u48(uint48_t *res, uint48_t lhs, uint48_t rhs, uint8_t bits) { #if zig_has_builtin(mul_overflow) || defined(zig_gcc) uint48_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u48(full_res, bits); + *res = zig_u48_truncate_u48(full_res, bits); return overflow || full_res < zig_minInt_u(48, bits) || full_res > zig_maxInt_u(48, bits); #else uint64_t full_res; bool overflow = zig_mulo_u64(&full_res, lhs, rhs, bits); - *res = (uint48_t)full_res; + *res = zig_u48_intCast_u64(full_res); return overflow; #endif } @@ -1406,18 +1575,32 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t #if zig_has_builtin(mul_overflow) || defined(zig_gcc) int48_t full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i48(full_res, bits); + *res = zig_i48_truncate_i48(full_res, bits); return overflow || full_res < zig_minInt_i(48, bits) || full_res > zig_maxInt_i(48, bits); #else int64_t full_res; bool overflow = zig_mulo_i64(&full_res, lhs, rhs, bits); - *res = (int48_t)full_res; + *res = zig_i48_intCast_i64(full_res); return overflow; #endif } + #endif -#define zig_int_builtins(w) \ +#define zig_shls_builtins(lw, rw) \ + static inline uint##lw##_t zig_shls_u##lw##_u##rw(uint##lw##_t lhs, uint##rw##_t rhs, uint8_t bits) { \ + uint##lw##_t res; \ + if (rhs < bits && !zig_shlo_u##lw(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + return lhs == INT##lw##_C(0) ? zig_minInt_u(lw, bits) : zig_maxInt_u(lw, bits); \ + } \ +\ + static inline int##lw##_t zig_shls_i##lw##_u##rw(int##lw##_t lhs, uint##rw##_t rhs, uint8_t bits) { \ + int##lw##_t res; \ + if (rhs < bits && !zig_shlo_i##lw(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + return lhs == INT##lw##_C(0) ? INT##lw##_C(0) : \ + lhs < INT##lw##_C(0) ? zig_minInt_i(lw, bits) : zig_maxInt_i(lw, bits); \ + } +#define zig_int_sat_builtins(w) \ static inline bool zig_shlo_u##w(uint##w##_t *res, uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ *res = zig_shlw_u##w(lhs, rhs, bits); \ return lhs > zig_maxInt_u(w, bits) >> rhs; \ @@ -1429,18 +1612,10 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t return (lhs & mask) != INT##w##_C(0) && (lhs & mask) != mask; \ } \ \ - static inline uint##w##_t zig_shls_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - uint##w##_t res; \ - if (rhs < bits && !zig_shlo_u##w(&res, lhs, rhs, bits)) return res; \ - return lhs == INT##w##_C(0) ? INT##w##_C(0) : zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_shls_i##w(int##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - int##w##_t res; \ - if (rhs < bits && !zig_shlo_i##w(&res, lhs, rhs, bits)) return res; \ - return lhs == INT##w##_C(0) ? INT##w##_C(0) : \ - lhs < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ - } \ + zig_shls_builtins(w, 8) \ + zig_shls_builtins(w, 16) \ + zig_shls_builtins(w, 32) \ + zig_shls_builtins(w, 64) \ \ static inline uint##w##_t zig_adds_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ uint##w##_t res; \ @@ -1474,332 +1649,321 @@ static inline bool zig_mulo_i48(int48_t *res, int48_t lhs, int48_t rhs, uint8_t if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \ return (lhs ^ rhs) < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ } -zig_int_builtins(8) -zig_int_builtins(16) +zig_int_sat_builtins(8) +zig_int_sat_builtins(16) +zig_int_sat_builtins(32) +zig_int_sat_builtins(64) #if defined(zig_ez80) -zig_int_builtins(24) +zig_int_sat_builtins(24) +zig_int_sat_builtins(48) #endif -zig_int_builtins(32) -#if defined(zig_ez80) -zig_int_builtins(48) -#endif -zig_int_builtins(64) -#define zig_builtin8(name, val) __builtin_##name(val) +#define zig_builtin8(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin8; -#define zig_builtin16(name, val) __builtin_##name(val) +#define zig_builtin16(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin16; -#if defined(zig_ez80) -#define zig_builtin24(name, val) __builtin_##name(val) -typedef unsigned int zig_Builtin24; -#endif - #if INT_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name(val) +#define zig_builtin32(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin32; #elif LONG_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name##l(val) +#define zig_builtin32(name, arg) __builtin_##name##l(arg) typedef unsigned long zig_Builtin32; #endif -#if defined(zig_ez80) -#define zig_builtin48(name, val) __builtin_##name(val) -typedef unsigned long long zig_Builtin48; -#endif - #if INT_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name(val) +#define zig_builtin64(name, arg) __builtin_##name(arg) typedef unsigned int zig_Builtin64; #elif LONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##l(val) +#define zig_builtin64(name, arg) __builtin_##name##l(arg) typedef unsigned long zig_Builtin64; #elif LLONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##ll(val) +#define zig_builtin64(name, arg) __builtin_##name##ll(arg) typedef unsigned long long zig_Builtin64; #endif -static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) { - return zig_wrap_u8(val >> (8 - bits), bits); +#if defined(zig_ez80) +#define zig_builtin24(name, arg) __builtin_##name(arg) +typedef unsigned int zig_Builtin24; +#define zig_builtin48(name, arg) __builtin_##name(arg) +typedef unsigned long long zig_Builtin48; +#endif + +static inline uint8_t zig_byteSwap_u8(uint8_t arg, uint8_t bits) { + return zig_u8_truncate_u8(arg >> (8 - bits), bits); } -static inline int8_t zig_byte_swap_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_byte_swap_u8((uint8_t)val, bits), bits); +static inline int8_t zig_byteSwap_i8(int8_t arg, uint8_t bits) { + return zig_i8_truncate_i8((int8_t)zig_byteSwap_u8((uint8_t)arg, bits), bits); } -static inline uint16_t zig_byte_swap_u16(uint16_t val, uint8_t bits) { +static inline uint16_t zig_byteSwap_u16(uint16_t arg, uint8_t bits) { uint16_t full_res; #if zig_has_builtin(bswap16) || defined(zig_gcc) - full_res = __builtin_bswap16(val); + full_res = __builtin_bswap16(arg); #else - full_res = (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 8), 8) >> 0; + full_res = (uint16_t)zig_byteSwap_u8((uint8_t)(arg >> 0), 8) << 8 | + (uint16_t)zig_byteSwap_u8((uint8_t)(arg >> 8), 8) >> 0; #endif - return zig_wrap_u16(full_res >> (16 - bits), bits); + return zig_u16_truncate_u16(full_res >> (16 - bits), bits); } -static inline int16_t zig_byte_swap_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_byte_swap_u16((uint16_t)val, bits), bits); +static inline int16_t zig_byteSwap_i16(int16_t arg, uint8_t bits) { + return zig_i16_truncate_i16((int16_t)zig_byteSwap_u16((uint16_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint16_t zig_byte_swap_u24(uint24_t val, uint8_t bits) { +static inline uint16_t zig_byteSwap_u24(uint24_t arg, uint8_t bits) { uint24_t full_res; #if zig_has_builtin(bswap24) || defined(zig_gcc) - full_res = __builtin_bswap24(val); + full_res = __builtin_bswap24(arg); #else - full_res = (uint24_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 16 | - (uint24_t)zig_byte_swap_u16((uint16_t)(val >> 8), 16) >> 0; + full_res = (uint24_t)zig_byteSwap_u8((uint8_t)(arg >> 0), 8) << 16 | + (uint24_t)zig_byteSwap_u16((uint16_t)(arg >> 8), 16) >> 0; #endif - return zig_wrap_u24(full_res >> (24 - bits), bits); + return zig_u24_truncate_u24(full_res >> (24 - bits), bits); } -static inline int16_t zig_byte_swap_i24(int24_t val, uint8_t bits) { - return zig_wrap_i24((int24_t)zig_byte_swap_u24((uint24_t)val, bits), bits); +static inline int16_t zig_byteSwap_i24(int24_t arg, uint8_t bits) { + return zig_i24_truncate_i24((int24_t)zig_byteSwap_u24((uint24_t)arg, bits), bits); } #endif -static inline uint32_t zig_byte_swap_u32(uint32_t val, uint8_t bits) { +static inline uint32_t zig_byteSwap_u32(uint32_t arg, uint8_t bits) { uint32_t full_res; #if zig_has_builtin(bswap32) || defined(zig_gcc) - full_res = __builtin_bswap32(val); + full_res = __builtin_bswap32(arg); #else - full_res = (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 16), 16) >> 0; + full_res = (uint32_t)zig_byteSwap_u16((uint16_t)(arg >> 0), 16) << 16 | + (uint32_t)zig_byteSwap_u16((uint16_t)(arg >> 16), 16) >> 0; #endif - return zig_wrap_u32(full_res >> (32 - bits), bits); + return zig_u32_truncate_u32(full_res >> (32 - bits), bits); } -static inline int32_t zig_byte_swap_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_byte_swap_u32((uint32_t)val, bits), bits); +static inline int32_t zig_byteSwap_i32(int32_t arg, uint8_t bits) { + return zig_i32_truncate_i32((int32_t)zig_byteSwap_u32((uint32_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint32_t zig_byte_swap_u48(uint48_t val, uint8_t bits) { +static inline uint32_t zig_byteSwap_u48(uint48_t arg, uint8_t bits) { uint48_t full_res; #if zig_has_builtin(bswap48) || defined(zig_gcc) - full_res = __builtin_bswap48(val); + full_res = __builtin_bswap48(arg); #else - full_res = (uint48_t)zig_byte_swap_u24((uint24_t)(val >> 0), 24) << 24 | - (uint48_t)zig_byte_swap_u24((uint24_t)(val >> 24), 24) >> 0; + full_res = (uint48_t)zig_byteSwap_u24((uint24_t)(arg >> 0), 24) << 24 | + (uint48_t)zig_byteSwap_u24((uint24_t)(arg >> 24), 24) >> 0; #endif - return zig_wrap_u48(full_res >> (48 - bits), bits); + return zig_u48_truncate_u48(full_res >> (48 - bits), bits); } -static inline int32_t zig_byte_swap_i48(int48_t val, uint8_t bits) { - return zig_wrap_i48((int48_t)zig_byte_swap_u48((uint48_t)val, bits), bits); +static inline int32_t zig_byteSwap_i48(int48_t arg, uint8_t bits) { + return zig_i48_truncate_i48((int48_t)zig_byteSwap_u48((uint48_t)arg, bits), bits); } #endif -static inline uint64_t zig_byte_swap_u64(uint64_t val, uint8_t bits) { +static inline uint64_t zig_byteSwap_u64(uint64_t arg, uint8_t bits) { uint64_t full_res; #if zig_has_builtin(bswap64) || defined(zig_gcc) - full_res = __builtin_bswap64(val); + full_res = __builtin_bswap64(arg); #else - full_res = (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 32), 32) >> 0; + full_res = (uint64_t)zig_byteSwap_u32((uint32_t)(arg >> 0), 32) << 32 | + (uint64_t)zig_byteSwap_u32((uint32_t)(arg >> 32), 32) >> 0; #endif - return zig_wrap_u64(full_res >> (64 - bits), bits); + return zig_u64_truncate_u64(full_res >> (64 - bits), bits); } -static inline int64_t zig_byte_swap_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_byte_swap_u64((uint64_t)val, bits), bits); +static inline int64_t zig_byteSwap_i64(int64_t arg, uint8_t bits) { + return zig_i64_truncate_i64((int64_t)zig_byteSwap_u64((uint64_t)arg, bits), bits); } -static inline uint8_t zig_bit_reverse_u8(uint8_t val, uint8_t bits) { +static inline uint8_t zig_bitReverse_u8(uint8_t arg, uint8_t bits) { uint8_t full_res; #if zig_has_builtin(bitreverse8) - full_res = __builtin_bitreverse8(val); + full_res = __builtin_bitreverse8(arg); #else static uint8_t const lut[0x10] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; - full_res = lut[val >> 0 & 0xF] << 4 | lut[val >> 4 & 0xF] << 0; + full_res = lut[arg >> 0 & 0xF] << 4 | lut[arg >> 4 & 0xF] << 0; #endif - return zig_wrap_u8(full_res >> (8 - bits), bits); + return zig_u8_truncate_u8(full_res >> (8 - bits), bits); } -static inline int8_t zig_bit_reverse_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_bit_reverse_u8((uint8_t)val, bits), bits); +static inline int8_t zig_bitReverse_i8(int8_t arg, uint8_t bits) { + return zig_i8_truncate_i8((int8_t)zig_bitReverse_u8((uint8_t)arg, bits), bits); } -static inline uint16_t zig_bit_reverse_u16(uint16_t val, uint8_t bits) { +static inline uint16_t zig_bitReverse_u16(uint16_t arg, uint8_t bits) { uint16_t full_res; #if zig_has_builtin(bitreverse16) - full_res = __builtin_bitreverse16(val); + full_res = __builtin_bitreverse16(arg); #else - full_res = (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 8), 8) >> 0; + full_res = (uint16_t)zig_bitReverse_u8((uint8_t)(arg >> 0), 8) << 8 | + (uint16_t)zig_bitReverse_u8((uint8_t)(arg >> 8), 8) >> 0; #endif - return zig_wrap_u16(full_res >> (16 - bits), bits); + return zig_u16_truncate_u16(full_res >> (16 - bits), bits); } -static inline int16_t zig_bit_reverse_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_bit_reverse_u16((uint16_t)val, bits), bits); +static inline int16_t zig_bitReverse_i16(int16_t arg, uint8_t bits) { + return zig_i16_truncate_i16((int16_t)zig_bitReverse_u16((uint16_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint24_t zig_bit_reverse_u24(uint24_t val, uint8_t bits) { +static inline uint24_t zig_bitReverse_u24(uint24_t arg, uint8_t bits) { uint24_t full_res; #if zig_has_builtin(bitreverse24) - full_res = __builtin_bitreverse24(val); + full_res = __builtin_bitreverse24(arg); #else - full_res = (uint24_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 16 | - (uint24_t)zig_bit_reverse_u16((uint16_t)(val >> 8), 16) >> 0; + full_res = (uint24_t)zig_bitReverse_u8((uint8_t)(arg >> 0), 8) << 16 | + (uint24_t)zig_bitReverse_u16((uint16_t)(arg >> 8), 16) >> 0; #endif - return zig_wrap_u24(full_res >> (24 - bits), bits); + return zig_u24_truncate_u24(full_res >> (24 - bits), bits); } -static inline int24_t zig_bit_reverse_i24(int24_t val, uint8_t bits) { - return zig_wrap_i24((int24_t)zig_bit_reverse_u24((uint24_t)val, bits), bits); +static inline int24_t zig_bitReverse_i24(int24_t arg, uint8_t bits) { + return zig_i24_truncate_i24((int24_t)zig_bitReverse_u24((uint24_t)arg, bits), bits); } #endif -static inline uint32_t zig_bit_reverse_u32(uint32_t val, uint8_t bits) { +static inline uint32_t zig_bitReverse_u32(uint32_t arg, uint8_t bits) { uint32_t full_res; #if zig_has_builtin(bitreverse32) - full_res = __builtin_bitreverse32(val); + full_res = __builtin_bitreverse32(arg); #else - full_res = (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 16), 16) >> 0; + full_res = (uint32_t)zig_bitReverse_u16((uint16_t)(arg >> 0), 16) << 16 | + (uint32_t)zig_bitReverse_u16((uint16_t)(arg >> 16), 16) >> 0; #endif - return zig_wrap_u32(full_res >> (32 - bits), bits); + return zig_u32_truncate_u32(full_res >> (32 - bits), bits); } -static inline int32_t zig_bit_reverse_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_bit_reverse_u32((uint32_t)val, bits), bits); +static inline int32_t zig_bitReverse_i32(int32_t arg, uint8_t bits) { + return zig_i32_truncate_i32((int32_t)zig_bitReverse_u32((uint32_t)arg, bits), bits); } #if defined(zig_ez80) -static inline uint32_t zig_bit_reverse_u48(uint48_t val, uint8_t bits) { +static inline uint32_t zig_bitReverse_u48(uint48_t arg, uint8_t bits) { uint48_t full_res; #if zig_has_builtin(bitreverse48) - full_res = __builtin_bitreverse48(val); + full_res = __builtin_bitreverse48(arg); #else - full_res = (uint48_t)zig_bit_reverse_u24((uint24_t)(val >> 0), 24) << 24 | - (uint48_t)zig_bit_reverse_u24((uint24_t)(val >> 24), 24) >> 0; + full_res = (uint48_t)zig_bitReverse_u24((uint24_t)(arg >> 0), 24) << 24 | + (uint48_t)zig_bitReverse_u24((uint24_t)(arg >> 24), 24) >> 0; #endif - return zig_wrap_u32(full_res >> (48 - bits), bits); + return zig_u48_truncate_u48(full_res >> (48 - bits), bits); } -static inline int32_t zig_bit_reverse_i48(int48_t val, uint8_t bits) { - return zig_wrap_i48((int48_t)zig_bit_reverse_u48((uint48_t)val, bits), bits); +static inline int32_t zig_bitReverse_i48(int48_t arg, uint8_t bits) { + return zig_i48_truncate_i48((int48_t)zig_bitReverse_u48((uint48_t)arg, bits), bits); } #endif -static inline uint64_t zig_bit_reverse_u64(uint64_t val, uint8_t bits) { +static inline uint64_t zig_bitReverse_u64(uint64_t arg, uint8_t bits) { uint64_t full_res; #if zig_has_builtin(bitreverse64) - full_res = __builtin_bitreverse64(val); + full_res = __builtin_bitreverse64(arg); #else - full_res = (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 32), 32) >> 0; + full_res = (uint64_t)zig_bitReverse_u32((uint32_t)(arg >> 0), 32) << 32 | + (uint64_t)zig_bitReverse_u32((uint32_t)(arg >> 32), 32) >> 0; #endif - return zig_wrap_u64(full_res >> (64 - bits), bits); + return zig_u64_truncate_u64(full_res >> (64 - bits), bits); } -static inline int64_t zig_bit_reverse_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_bit_reverse_u64((uint64_t)val, bits), bits); +static inline int64_t zig_bitReverse_i64(int64_t arg, uint8_t bits) { + return zig_i64_truncate_i64((int64_t)zig_bitReverse_u64((uint64_t)arg, bits), bits); } -#define zig_builtin_popcount_common(w) \ - static inline uint8_t zig_popcount_i##w(int##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w((uint##w##_t)val, bits); \ +#define zig_builtin_popCount_common(w) \ + static inline uint8_t zig_popCount_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_popCount_u##w((uint##w##_t)arg, bits); \ } -#if zig_has_builtin(popcount) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ +#if zig_has_builtin(popCount) || defined(zig_gcc) || defined(zig_tinyc) +#define zig_builtin_popCount(w) \ + static inline uint8_t zig_popCount_u##w(uint##w##_t arg, uint8_t bits) { \ (void)bits; \ - return zig_builtin##w(popcount, val); \ + return zig_builtin##w(popcount, arg); \ } \ \ - zig_builtin_popcount_common(w) + zig_builtin_popCount_common(w) #else -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ +#define zig_builtin_popCount(w) \ + static inline uint8_t zig_popCount_u##w(uint##w##_t arg, uint8_t bits) { \ (void)bits; \ - uint##w##_t temp = val - ((val >> 1) & (UINT##w##_MAX / 3)); \ + uint##w##_t temp = arg - ((arg >> 1) & (UINT##w##_MAX / 3)); \ temp = (temp & (UINT##w##_MAX / 5)) + ((temp >> 2) & (UINT##w##_MAX / 5)); \ temp = (temp + (temp >> 4)) & (UINT##w##_MAX / 17); \ return temp * (UINT##w##_MAX / 255) >> (UINT8_C(w) - UINT8_C(8)); \ } \ \ - zig_builtin_popcount_common(w) + zig_builtin_popCount_common(w) #endif -zig_builtin_popcount(8) -zig_builtin_popcount(16) +zig_builtin_popCount(8) +zig_builtin_popCount(16) +zig_builtin_popCount(32) +zig_builtin_popCount(64) #if defined(zig_ez80) -zig_builtin_popcount(24) +zig_builtin_popCount(24) +zig_builtin_popCount(48) #endif -zig_builtin_popcount(32) -#if defined(zig_ez80) -zig_builtin_popcount(48) -#endif -zig_builtin_popcount(64) #define zig_builtin_ctz_common(w) \ - static inline uint8_t zig_ctz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w((uint##w##_t)val, bits); \ + static inline uint8_t zig_ctz_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_ctz_u##w((uint##w##_t)arg, bits); \ } #if zig_has_builtin(ctz) || defined(zig_gcc) || defined(zig_tinyc) #define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(ctz, val); \ + static inline uint8_t zig_ctz_u##w(uint##w##_t arg, uint8_t bits) { \ + if (arg == 0) return bits; \ + return zig_builtin##w(ctz, arg); \ } \ \ zig_builtin_ctz_common(w) #else #define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w(zig_not_u##w(val, bits) & zig_subw_u##w(val, 1, bits), bits); \ + static inline uint8_t zig_ctz_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_popCount_u##w(zig_not_u##w(arg, bits) & zig_subw_u##w(arg, 1, bits), bits); \ } \ \ zig_builtin_ctz_common(w) #endif zig_builtin_ctz(8) zig_builtin_ctz(16) -#if defined(zig_ez80) -zig_builtin_ctz(24) -#endif zig_builtin_ctz(32) -#if defined(zig_ez80) -zig_builtin_ctz(48) -#endif zig_builtin_ctz(64) +#if defined(zig_ez80) +zig_builtin_ctz(24) +zig_builtin_ctz(48) +#endif #define zig_builtin_clz_common(w) \ - static inline uint8_t zig_clz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_clz_u##w((uint##w##_t)val, bits); \ + static inline uint8_t zig_clz_i##w(int##w##_t arg, uint8_t bits) { \ + return zig_clz_u##w((uint##w##_t)arg, bits); \ } #if zig_has_builtin(clz) || defined(zig_gcc) || defined(zig_tinyc) #define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ + static inline uint8_t zig_clz_u##w(uint##w##_t arg, uint8_t bits) { \ + if (arg == 0) return bits; \ + return zig_builtin##w(clz, arg) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ } \ \ zig_builtin_clz_common(w) #else #define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w(zig_bit_reverse_u##w(val, bits), bits); \ + static inline uint8_t zig_clz_u##w(uint##w##_t arg, uint8_t bits) { \ + return zig_ctz_u##w(zig_bitReverse_u##w(arg, bits), bits); \ } \ \ zig_builtin_clz_common(w) #endif zig_builtin_clz(8) zig_builtin_clz(16) -#if defined(zig_ez80) -zig_builtin_clz(24) -#endif zig_builtin_clz(32) -#if defined(zig_ez80) -zig_builtin_clz(48) -#endif zig_builtin_clz(64) +#if defined(zig_ez80) +zig_builtin_clz(24) +zig_builtin_clz(48) +#endif /* ======================== 128-bit Integer Support ========================= */ @@ -1816,16 +1980,14 @@ zig_builtin_clz(64) typedef unsigned __int128 zig_u128; typedef signed __int128 zig_i128; -#define zig_make_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) -#define zig_make_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo)) -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#define zig_hi_u128(val) ((uint64_t)((val) >> 64)) -#define zig_lo_u128(val) ((uint64_t)((val) >> 0)) -#define zig_hi_i128(val) (( int64_t)((val) >> 64)) -#define zig_lo_i128(val) ((uint64_t)((val) >> 0)) -#define zig_bitCast_u128(val) ((zig_u128)(val)) -#define zig_bitCast_i128(val) ((zig_i128)(val)) +#define zig_init_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) +#define zig_init_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo)) +#define zig_make_u128(hi, lo) zig_init_u128(hi, lo) +#define zig_make_i128(hi, lo) zig_init_i128(hi, lo) +#define zig_hi_u128(arg) ((uint64_t)((arg) >> 64)) +#define zig_lo_u128(arg) ((uint64_t)((arg) >> 0)) +#define zig_hi_i128(arg) (( int64_t)((arg) >> 64)) +#define zig_lo_i128(arg) ((uint64_t)((arg) >> 0)) #define zig_cmp_int128(Type) \ static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ return (lhs > rhs) - (lhs < rhs); \ @@ -1835,32 +1997,49 @@ typedef signed __int128 zig_i128; return lhs operator rhs; \ } +static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { + return lhs << rhs; +} + +static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { + return lhs >> rhs; +} + +static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { + return lhs << rhs; +} + +static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { + // This works around a GCC miscompilation, but it has the side benefit of + // emitting better code. It is behind the `#if` because it depends on + // arithmetic right shift, which is implementation-defined in C, but should + // be guaranteed on any GCC-compatible compiler. +#if defined(zig_gnuc) + return lhs >> rhs; +#else + zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0); + return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; +#endif +} + #else /* zig_has_int128 */ #if zig_little_endian -typedef struct { zig_align(16) uint64_t lo; uint64_t hi; } zig_u128; -typedef struct { zig_align(16) uint64_t lo; int64_t hi; } zig_i128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t lo; uint64_t hi; } zig_u128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t lo; int64_t hi; } zig_i128; #else -typedef struct { zig_align(16) uint64_t hi; uint64_t lo; } zig_u128; -typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) uint64_t hi; uint64_t lo; } zig_u128; +typedef struct { zig_align(ZIG_TARGET_MAX_INT_ALIGNMENT) int64_t hi; uint64_t lo; } zig_i128; #endif -#define zig_make_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) }) -#define zig_make_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) }) - -#if defined(zig_msvc) /* MSVC doesn't allow struct literals in constant expressions */ -#define zig_init_u128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#define zig_init_i128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#else /* But non-MSVC doesn't like the unprotected commas */ -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#endif -#define zig_hi_u128(val) ((val).hi) -#define zig_lo_u128(val) ((val).lo) -#define zig_hi_i128(val) ((val).hi) -#define zig_lo_i128(val) ((val).lo) -#define zig_bitCast_u128(val) zig_make_u128((uint64_t)(val).hi, (val).lo) -#define zig_bitCast_i128(val) zig_make_i128(( int64_t)(val).hi, (val).lo) +#define zig_init_u128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_init_i128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_make_u128(hi, lo) (zig_u128)zig_init_u128(hi, lo) +#define zig_make_i128(hi, lo) (zig_i128)zig_init_i128(hi, lo) +#define zig_hi_u128(arg) (arg).hi +#define zig_lo_u128(arg) (arg).lo +#define zig_hi_i128(arg) (arg).hi +#define zig_lo_i128(arg) (arg).lo #define zig_cmp_int128(Type) \ static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ return (lhs.hi == rhs.hi) \ @@ -1872,6 +2051,30 @@ typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128; return (zig_##Type){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \ } +static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; + return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +} + +static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) }; + return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs }; +} + +static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; + return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +} + +static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { + if (rhs == UINT8_C(0)) return lhs; + if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) }; + return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) }; +} + #endif /* zig_has_int128 */ #define zig_minInt_u128 zig_make_u128(zig_minInt_u64, zig_minInt_u64) @@ -1891,42 +2094,177 @@ zig_bit_int128(i128, or, |) zig_bit_int128(u128, xor, ^) zig_bit_int128(i128, xor, ^) -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs); +static inline uint8_t zig_u8_intCast_u128(zig_u128 arg) { + return (uint8_t)zig_lo_u128(arg); +} +static inline uint8_t zig_u8_intCast_i128(zig_i128 arg) { + return (uint8_t)zig_lo_i128(arg); +} +static inline int8_t zig_i8_intCast_i128(zig_i128 arg) { + return (int8_t)zig_lo_i128(arg); +} +static inline int8_t zig_i8_intCast_u128(zig_u128 arg) { + return (int8_t)zig_lo_u128(arg); +} -#if zig_has_int128 +static inline uint16_t zig_u16_intCast_u128(zig_u128 arg) { + return (uint16_t)zig_lo_u128(arg); +} +static inline uint16_t zig_u16_intCast_i128(zig_i128 arg) { + return (uint16_t)zig_lo_i128(arg); +} +static inline int16_t zig_i16_intCast_i128(zig_i128 arg) { + return (int16_t)zig_lo_i128(arg); +} +static inline int16_t zig_i16_intCast_u128(zig_u128 arg) { + return (int16_t)zig_lo_u128(arg); +} -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return val ^ zig_maxInt_u(128, bits); +static inline uint32_t zig_u32_intCast_u128(zig_u128 arg) { + return (uint32_t)zig_lo_u128(arg); +} +static inline uint32_t zig_u32_intCast_i128(zig_i128 arg) { + return (uint32_t)zig_lo_i128(arg); +} +static inline int32_t zig_i32_intCast_i128(zig_i128 arg) { + return (int32_t)zig_lo_i128(arg); +} +static inline int32_t zig_i32_intCast_u128(zig_u128 arg) { + return (int32_t)zig_lo_u128(arg); } -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - (void)bits; - return ~val; +static inline uint64_t zig_u64_intCast_u128(zig_u128 arg) { + return zig_lo_u128(arg); +} +static inline uint64_t zig_u64_intCast_i128(zig_i128 arg) { + return zig_lo_i128(arg); +} +static inline int64_t zig_i64_intCast_i128(zig_i128 arg) { + return (int64_t)zig_lo_i128(arg); +} +static inline int64_t zig_i64_intCast_u128(zig_u128 arg) { + return (int64_t)zig_lo_u128(arg); +} + +static inline zig_u128 zig_u128_intCast_u8(uint8_t arg) { + return zig_make_u128(UINT8_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i8(int8_t arg) { + return zig_make_u128(UINT8_C(0), (uint8_t)arg); +} +static inline zig_i128 zig_i128_intCast_i8(int8_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint8_t)arg); +} +static inline zig_i128 zig_i128_intCast_u8(uint8_t arg) { + return zig_make_i128(INT8_C(0), arg); } -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - return lhs >> rhs; +static inline zig_u128 zig_u128_intCast_u16(uint16_t arg) { + return zig_make_u128(UINT16_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i16(int16_t arg) { + return zig_make_u128(UINT16_C(0), (uint16_t)arg); +} +static inline zig_i128 zig_i128_intCast_i16(int16_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint16_t)arg); +} +static inline zig_i128 zig_i128_intCast_u16(uint16_t arg) { + return zig_make_i128(INT16_C(0), arg); } -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - return lhs << rhs; +static inline zig_u128 zig_u128_intCast_u32(uint32_t arg) { + return zig_make_u128(UINT32_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i32(int32_t arg) { + return zig_make_u128(UINT32_C(0), (uint32_t)arg); +} +static inline zig_i128 zig_i128_intCast_i32(int32_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint32_t)arg); +} +static inline zig_i128 zig_i128_intCast_u32(uint32_t arg) { + return zig_make_i128(INT32_C(0), arg); } -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - // This works around a GCC miscompilation, but it has the side benefit of - // emitting better code. It is behind the `#if` because it depends on - // arithmetic right shift, which is implementation-defined in C, but should - // be guaranteed on any GCC-compatible compiler. -#if defined(zig_gnuc) - return lhs >> rhs; +static inline zig_u128 zig_u128_intCast_u64(uint64_t arg) { + return zig_make_u128(UINT64_C(0), arg); +} +static inline zig_u128 zig_u128_intCast_i64(int64_t arg) { + return zig_make_u128(UINT64_C(0), (uint64_t)arg); +} +static inline zig_i128 zig_i128_intCast_i64(int64_t arg) { + return zig_make_i128(zig_shr_i64(arg, 63), (uint64_t)arg); +} +static inline zig_i128 zig_i128_intCast_u64(uint64_t arg) { + return zig_make_i128(INT64_C(0), arg); +} + +static inline zig_u128 zig_u128_intCast_u128(zig_u128 arg) { + return arg; +} +static inline zig_u128 zig_u128_intCast_i128(zig_i128 arg) { +#if zig_has_int128 + return (zig_u128)arg; +#else + return zig_make_u128(zig_u64_bitCast_i64(zig_hi_i128(arg), UINT8_C(64)), zig_lo_u128(arg)); +#endif +} +static inline zig_i128 zig_i128_intCast_i128(zig_i128 arg) { + return arg; +} +static inline zig_i128 zig_i128_intCast_u128(zig_u128 arg) { +#if zig_has_int128 + return (zig_i128)arg; #else - zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0); - return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; + return zig_make_i128(zig_i64_bitCast_u64(zig_hi_i128(arg), UINT8_C(64)), zig_lo_u128(arg)); #endif } -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - return lhs << rhs; +#define zig_int128_cast_builtins(w) \ + static inline uint##w##_t zig_u##w##_truncate_u128(zig_u128 arg, uint8_t bits) { \ + return zig_u##w##_truncate_u##w((uint##w##_t)zig_lo_u128(arg), bits); \ + } \ +\ + static inline int##w##_t zig_i##w##_truncate_i128(zig_i128 arg, uint8_t bits) { \ + return zig_i##w##_truncate_i##w((int##w##_t)zig_lo_i128(arg), bits); \ + } +zig_int128_cast_builtins(8) +zig_int128_cast_builtins(16) +zig_int128_cast_builtins(32) +zig_int128_cast_builtins(64) + +static inline zig_u128 zig_u128_truncate_u128(zig_u128 arg, uint8_t bits) { + return zig_and_u128(arg, zig_maxInt_u(128, bits)); +} +static inline zig_i128 zig_i128_truncate_i128(zig_i128 arg, uint8_t bits) { + if (bits > UINT8_C(64)) return zig_make_i128(zig_i64_truncate_i64(zig_hi_i128(arg), bits - UINT8_C(64)), zig_lo_i128(arg)); + int64_t lo = zig_i64_truncate_i128(arg, bits); + return zig_make_i128(zig_shr_i64(lo, 63), (uint64_t)lo); +} + +static inline zig_u128 zig_u128_bitCast_u128(zig_u128 arg, uint8_t bits) { + (void)bits; + return arg; +} +static inline zig_u128 zig_u128_bitCast_i128(zig_i128 arg, uint8_t bits) { + return zig_u128_truncate_u128(zig_u128_intCast_i128(arg), bits); +} +static inline zig_i128 zig_i128_bitCast_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return arg; +} +static inline zig_i128 zig_i128_bitCast_u128(zig_u128 arg, uint8_t bits) { + return zig_i128_truncate_i128(zig_i128_intCast_u128(arg), bits); +} + +#if zig_has_int128 + +static inline zig_u128 zig_not_u128(zig_u128 arg, uint8_t bits) { + return arg ^ zig_maxInt_u(128, bits); +} + +static inline zig_i128 zig_not_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return ~arg; } static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { @@ -1953,11 +2291,11 @@ static inline zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { return lhs * rhs; } -static inline zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { +static inline zig_u128 zig_divTrunc_u128(zig_u128 lhs, zig_u128 rhs) { return lhs / rhs; } -static inline zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divTrunc_i128(zig_i128 lhs, zig_i128 rhs) { return lhs / rhs; } @@ -1971,36 +2309,14 @@ static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { #else /* zig_has_int128 */ -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return (zig_u128){ .hi = zig_not_u64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; +static inline zig_u128 zig_not_u128(zig_u128 arg, uint8_t bits) { + if (bits <= UINT8_C(64)) return (zig_u128){ .hi = UINT64_C(0), .lo = zig_not_u64(arg.lo, bits) }; + return (zig_u128){ .hi = zig_not_u64(arg.hi, bits - UINT8_C(64)), .lo = zig_not_u64(arg.lo, UINT8_C(64)) }; } -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - return (zig_i128){ .hi = zig_not_i64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; -} - -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) }; - return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs }; -} - -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; -} - -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) }; - return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) }; -} - -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; +static inline zig_i128 zig_not_i128(zig_i128 arg, uint8_t bits) { + (void)bits; + return (zig_i128){ .hi = ~arg.hi, .lo = ~arg.lo }; } static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { @@ -2027,59 +2343,59 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { return res; } -zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); return __multi3(lhs, rhs); } static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) { - return zig_bitCast_u128(zig_mul_i128(zig_bitCast_i128(lhs), zig_bitCast_i128(rhs))); + return zig_u128_bitCast_i128(zig_mul_i128(zig_i128_bitCast_u128(lhs, UINT8_C(128)), zig_i128_bitCast_u128(rhs, UINT8_C(128))), UINT8_C(128)); } -zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); -static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { +static zig_u128 zig_divTrunc_u128(zig_u128 lhs, zig_u128 rhs) { + zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); return __udivti3(lhs, rhs); } -zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); -static zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { +static zig_i128 zig_divTrunc_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); return __divti3(lhs, rhs); } -zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); static zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) { + zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); return __umodti3(lhs, rhs); } -zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { + zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); return __modti3(lhs, rhs); } #endif /* zig_has_int128 */ -#define zig_div_floor_u128 zig_div_trunc_u128 +#define zig_divFloor_u128 zig_divTrunc_u128 -static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divFloor_i128(zig_i128 lhs, zig_i128 rhs) { zig_i128 rem = zig_rem_i128(lhs, rhs); int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) : INT64_C(0); - return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); + return zig_add_i128(zig_divTrunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); } -static inline zig_u128 zig_div_ceil_u128(zig_u128 lhs, zig_u128 rhs) { +static inline zig_u128 zig_divCeil_u128(zig_u128 lhs, zig_u128 rhs) { zig_u128 rem = zig_rem_u128(lhs, rhs); uint64_t mask = zig_or_u64(zig_hi_u128(rem), zig_lo_u128(rem)) != UINT64_C(0) ? UINT64_C(1) : UINT64_C(0); - return zig_add_u128(zig_div_trunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); + return zig_add_u128(zig_divTrunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); } -static inline zig_i128 zig_div_ceil_i128(zig_i128 lhs, zig_i128 rhs) { +static inline zig_i128 zig_divCeil_i128(zig_i128 lhs, zig_i128 rhs) { zig_i128 rem = zig_rem_i128(lhs, rhs); int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) + INT64_C(1) : INT64_C(0); - return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); + return zig_add_i128(zig_divTrunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); } #define zig_mod_u128 zig_rem_u128 @@ -2107,51 +2423,41 @@ static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) { return zig_cmp_i128(lhs, rhs) > INT32_C(0) ? lhs : rhs; } -static inline zig_u128 zig_wrap_u128(zig_u128 val, uint8_t bits) { - return zig_and_u128(val, zig_maxInt_u(128, bits)); -} - -static inline zig_i128 zig_wrap_i128(zig_i128 val, uint8_t bits) { - if (bits > UINT8_C(64)) return zig_make_i128(zig_wrap_i64(zig_hi_i128(val), bits - UINT8_C(64)), zig_lo_i128(val)); - int64_t lo = zig_wrap_i64((int64_t)zig_lo_i128(val), bits); - return zig_make_i128(zig_shr_i64(lo, 63), (uint64_t)lo); -} - static inline zig_u128 zig_shlw_u128(zig_u128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_shl_u128(lhs, rhs), bits); } static inline zig_i128 zig_shlw_i128(zig_i128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_shl_u128(zig_bitCast_u128(lhs), rhs)), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_shl_u128(zig_u128_bitCast_i128(lhs, bits), rhs), bits), bits); } static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_add_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_add_u128(lhs, rhs), bits); } static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_add_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_add_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_sub_u128(lhs, rhs), bits); } static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_sub_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_sub_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); + return zig_u128_truncate_u128(zig_mul_u128(lhs, rhs), bits); } static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); + return zig_i128_truncate_i128(zig_i128_bitCast_u128(zig_mul_u128(zig_u128_bitCast_i128(lhs, bits), zig_u128_bitCast_i128(rhs, bits)), bits), bits); } -static inline zig_u128 zig_abs_i128(zig_i128 val) { - zig_i128 tmp = zig_shr_i128(val, 127); - return zig_bitCast_u128(zig_sub_i128(zig_xor_i128(val, tmp), tmp)); +static inline zig_u128 zig_abs_i128(zig_i128 arg) { + zig_u128 tmp = zig_u128_bitCast_i128(zig_shr_i128(arg, 127), UINT8_C(128)); + return zig_sub_u128(zig_xor_u128(zig_u128_bitCast_i128(arg, UINT8_C(128)), tmp), tmp); } #if zig_has_int128 @@ -2160,7 +2466,7 @@ static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(add_overflow) zig_u128 full_res; bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_addw_u128(lhs, rhs, bits); @@ -2176,7 +2482,7 @@ static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = (zig_i128)((zig_u128)lhs + (zig_u128)rhs); bool overflow = ((full_res ^ lhs) & (full_res ^ rhs)) < 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } @@ -2184,7 +2490,7 @@ static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(sub_overflow) zig_u128 full_res; bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_subw_u128(lhs, rhs, bits); @@ -2200,7 +2506,7 @@ static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = (zig_i128)((zig_u128)lhs - (zig_u128)rhs); bool overflow = ((lhs ^ rhs) & (full_res ^ lhs)) < 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } @@ -2208,7 +2514,7 @@ static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #if zig_has_builtin(mul_overflow) zig_u128 full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); + *res = zig_u128_truncate_u128(full_res, bits); return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); #else *res = zig_mulw_u128(lhs, rhs, bits); @@ -2216,8 +2522,8 @@ static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint #endif } -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { + zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); #if zig_has_builtin(mul_overflow) zig_i128 full_res; bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); @@ -2226,50 +2532,78 @@ static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0; #endif - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); } #else /* zig_has_int128 */ static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + uint64_t lo; + bool overflow = zig_addo_u64(&lo, zig_u64_intCast_u128(lhs), zig_u64_intCast_u128(rhs), bits); + *res = zig_u128_intCast_u64(lo); + return overflow; + } else { + uint64_t hi; + bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + int64_t lo; + bool overflow = zig_addo_i64(&lo, zig_i64_intCast_i128(lhs), zig_i64_intCast_i128(rhs), bits); + *res = zig_i128_intCast_i64(lo); + return overflow; + } else { + int64_t hi; + bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + uint64_t lo; + bool overflow = zig_subo_u64(&lo, zig_u64_intCast_u128(lhs), zig_u64_intCast_u128(rhs), bits); + *res = zig_u128_intCast_u64(lo); + return overflow; + } else { + uint64_t hi; + bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); + if (bits <= UINT8_C(64)) { + int64_t lo; + bool overflow = zig_subo_i64(&lo, zig_i64_intCast_i128(lhs), zig_i64_intCast_i128(rhs), bits); + *res = zig_i128_intCast_i64(lo); + return overflow; + } else { + int64_t hi; + bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - UINT8_C(64)); + return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT8_C(64)), bits - UINT8_C(64)); + } } static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { *res = zig_mulw_u128(lhs, rhs, bits); - return zig_cmp_u128(*res, zig_make_u128(0, 0)) != INT32_C(0) && - zig_cmp_u128(lhs, zig_div_trunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); + return zig_cmp_u128(rhs, zig_make_u128(0, 0)) != INT32_C(0) && + zig_cmp_u128(lhs, zig_divTrunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); } -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { + zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); int overflow_int; zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); bool overflow = overflow_int != 0 || zig_cmp_i128(full_res, zig_minInt_i(128, bits)) < INT32_C(0) || zig_cmp_i128(full_res, zig_maxInt_i(128, bits)) > INT32_C(0); - *res = zig_wrap_i128(full_res, bits); + *res = zig_i128_truncate_i128(full_res, bits); return overflow; } @@ -2282,28 +2616,54 @@ static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, uint8_t rhs, uint8 static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, uint8_t rhs, uint8_t bits) { *res = zig_shlw_i128(lhs, rhs, bits); - zig_i128 mask = zig_bitCast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1))); + zig_i128 mask = zig_i128_bitCast_u128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1)), bits); return zig_cmp_i128(zig_and_i128(lhs, mask), zig_make_i128(0, 0)) != INT32_C(0) && zig_cmp_i128(zig_and_i128(lhs, mask), mask) != INT32_C(0); } -static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { +#define zig_int128_shls_builtins(rw) \ + static inline zig_u128 zig_shls_u128_u##rw(zig_u128 lhs, uint##rw##_t rhs, uint8_t bits) { \ + zig_u128 res; \ + if (rhs < bits && !zig_shlo_u128(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + switch (zig_cmp_u128(lhs, zig_make_u128(UINT64_C(0), UINT64_C(0)))) { \ + case 0: return zig_minInt_u(128, bits); \ + case 1: return zig_maxInt_u(128, bits); \ + default: zig_unreachable(); \ + } \ + } \ +\ + static inline zig_i128 zig_shls_i128_u##rw(zig_i128 lhs, uint##rw##_t rhs, uint8_t bits) { \ + zig_i128 res; \ + if (rhs < bits && !zig_shlo_i128(&res, lhs, zig_u8_intCast_u##rw(rhs), bits)) return res; \ + switch (zig_cmp_i128(lhs, zig_make_i128(INT64_C(0), UINT64_C(0)))) { \ + case -1: return zig_minInt_i(128, bits); \ + case 0: return zig_make_i128(INT64_C(0), UINT64_C(0)); \ + case 1: return zig_maxInt_i(128, bits); \ + default: zig_unreachable(); \ + } \ + } +zig_int128_shls_builtins(8) +zig_int128_shls_builtins(16) +zig_int128_shls_builtins(32) +zig_int128_shls_builtins(64) + +static inline zig_u128 zig_shls_u128_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { zig_u128 res; if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_u128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits)) return res; switch (zig_cmp_u128(lhs, zig_make_u128(0, 0))) { - case 0: return zig_make_u128(0, 0); - case 1: return zig_maxInt_u(128, bits); + case INT32_C(0): return zig_make_u128(0, 0); + case INT32_C(1): return zig_maxInt_u(128, bits); default: zig_unreachable(); } } -static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_u128 rhs, uint8_t bits) { +static inline zig_i128 zig_shls_i128_u128(zig_i128 lhs, zig_u128 rhs, uint8_t bits) { zig_i128 res; if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_i128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits)) return res; switch (zig_cmp_i128(lhs, zig_make_i128(0, 0))) { - case -1: return zig_minInt_i(128, bits); - case 0: return zig_make_i128(0, 0); - case 1: return zig_maxInt_i(128, bits); + case -INT32_C(1): return zig_minInt_i(128, bits); + case INT32_C(0): return zig_make_i128(0, 0); + case INT32_C(1): return zig_maxInt_i(128, bits); default: zig_unreachable(); } } @@ -2341,57 +2701,60 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_make_i128(0, 0)) < INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits); } -static inline uint8_t zig_clz_u128(zig_u128 val, uint8_t bits) { - if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(val), bits); - if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - UINT8_C(64)); - return zig_clz_u64(zig_lo_u128(val), UINT8_C(64)) + (bits - UINT8_C(64)); +static inline uint8_t zig_clz_u128(zig_u128 arg, uint8_t bits) { + if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(arg), bits); + if (zig_hi_u128(arg) != 0) return zig_clz_u64(zig_hi_u128(arg), bits - UINT8_C(64)); + return zig_clz_u64(zig_lo_u128(arg), UINT8_C(64)) + (bits - UINT8_C(64)); } -static inline uint8_t zig_clz_i128(zig_i128 val, uint8_t bits) { - return zig_clz_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_clz_i128(zig_i128 arg, uint8_t bits) { + return zig_clz_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline uint8_t zig_ctz_u128(zig_u128 val, uint8_t bits) { - if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), UINT8_C(64)); - return zig_ctz_u64(zig_hi_u128(val), bits - UINT8_C(64)) + UINT8_C(64); +static inline uint8_t zig_ctz_u128(zig_u128 arg, uint8_t bits) { + if (zig_lo_u128(arg) != 0) return zig_ctz_u64(zig_lo_u128(arg), UINT8_C(64)); + return zig_ctz_u64(zig_hi_u128(arg), bits - UINT8_C(64)) + UINT8_C(64); } -static inline uint8_t zig_ctz_i128(zig_i128 val, uint8_t bits) { - return zig_ctz_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_ctz_i128(zig_i128 arg, uint8_t bits) { + return zig_ctz_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline uint8_t zig_popcount_u128(zig_u128 val, uint8_t bits) { - return zig_popcount_u64(zig_hi_u128(val), bits - UINT8_C(64)) + - zig_popcount_u64(zig_lo_u128(val), UINT8_C(64)); +static inline uint8_t zig_popCount_u128(zig_u128 arg, uint8_t bits) { + return (bits > UINT8_C(64) ? zig_popCount_u64(zig_hi_u128(arg), bits - UINT8_C(64)) : UINT8_C(0)) + + zig_popCount_u64(zig_lo_u128(arg), UINT8_C(64)); } -static inline uint8_t zig_popcount_i128(zig_i128 val, uint8_t bits) { - return zig_popcount_u128(zig_bitCast_u128(val), bits); +static inline uint8_t zig_popCount_i128(zig_i128 arg, uint8_t bits) { + return zig_popCount_u128(zig_u128_bitCast_i128(arg, bits), bits); } -static inline zig_u128 zig_byte_swap_u128(zig_u128 val, uint8_t bits) { +static inline zig_u128 zig_byteSwap_u128(zig_u128 arg, uint8_t bits) { zig_u128 full_res; #if zig_has_builtin(bswap128) - full_res = __builtin_bswap128(val); + full_res = __builtin_bswap128(arg); #else - full_res = zig_make_u128(zig_byte_swap_u64(zig_lo_u128(val), UINT8_C(64)), - zig_byte_swap_u64(zig_hi_u128(val), UINT8_C(64))); + full_res = zig_make_u128( + zig_byteSwap_u64(zig_lo_u128(arg), UINT8_C(64)), + zig_byteSwap_u64(zig_hi_u128(arg), UINT8_C(64)) + ); #endif return zig_shr_u128(full_res, UINT8_C(128) - bits); } -static inline zig_i128 zig_byte_swap_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_byte_swap_u128(zig_bitCast_u128(val), bits)); +static inline zig_i128 zig_byteSwap_i128(zig_i128 arg, uint8_t bits) { + return zig_i128_bitCast_u128(zig_byteSwap_u128(zig_u128_bitCast_i128(arg, bits), bits), bits); } -static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, uint8_t bits) { - return zig_shr_u128(zig_make_u128(zig_bit_reverse_u64(zig_lo_u128(val), UINT8_C(64)), - zig_bit_reverse_u64(zig_hi_u128(val), UINT8_C(64))), - UINT8_C(128) - bits); +static inline zig_u128 zig_bitReverse_u128(zig_u128 arg, uint8_t bits) { + return zig_shr_u128(zig_make_u128( + zig_bitReverse_u64(zig_lo_u128(arg), UINT8_C(64)), + zig_bitReverse_u64(zig_hi_u128(arg), UINT8_C(64)) + ), UINT8_C(128) - bits); } -static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_bit_reverse_u128(zig_bitCast_u128(val), bits)); +static inline zig_i128 zig_bitReverse_i128(zig_i128 arg, uint8_t bits) { + return zig_i128_bitCast_u128(zig_bitReverse_u128(zig_u128_bitCast_i128(arg, bits), bits), bits); } #if zig_has_int128 @@ -2411,12 +2774,378 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { /* ========================== Big Integer Support =========================== */ static inline uint16_t zig_int_bytes(uint16_t bits) { - uint16_t bytes = (bits + CHAR_BIT - 1) / CHAR_BIT; + uint16_t bytes = (bits - UINT16_C(1)) / CHAR_BIT + UINT16_C(1); uint16_t alignment = ZIG_TARGET_MAX_INT_ALIGNMENT; + while (alignment / 2 >= bytes) alignment /= 2; return (bytes + alignment - 1) / alignment * alignment; } +static inline void zig_minInt_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + + if (is_signed) { + int8_t signed_sign_byte = zig_minInt_i(8, remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_minInt_u(8, remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memset(&res_bytes[0], zig_minInt_u8, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + byte_offset = size - UINT16_C(1) - byte_offset; + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], zig_minInt_u8, size - byte_offset); +#endif +} + +static inline void zig_maxInt_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + + if (is_signed) { + int8_t signed_sign_byte = zig_maxInt_i(8, remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_maxInt_u(8, remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memset(&res_bytes[0], zig_maxInt_u8, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + byte_offset = size - UINT16_C(1) - byte_offset; + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], zig_maxInt_u8, size - byte_offset); +#endif +} + +static inline int8_t zig_signFill_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + + if (!is_signed) return INT8_C(0); +#if zig_little_endian + byte_offset = zig_int_bytes(bits) - 1; +#endif + return zig_shr_i8(zig_i8_bitCast_u8(arg_bytes[byte_offset], UINT8_C(8)), UINT8_C(7)); +} + +static inline void zig_big_intCast_big(void *res, const void *arg, bool res_is_signed, uint16_t res_bits, bool arg_is_signed, uint16_t arg_bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_size = zig_int_bytes(res_bits); + uint16_t arg_size = zig_int_bytes(arg_bits); + uint16_t copy_size = zig_min_u16(res_size, arg_size); + uint8_t sign_fill = zig_u8_bitCast_i8(zig_signFill_big(arg, arg_is_signed, arg_bits), UINT8_C(8)); + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], copy_size); + memset(&res_bytes[copy_size], sign_fill, res_size - copy_size); +#else + memset(&res_bytes[0], sign_fill, res_size - copy_size); + memcpy(&res_bytes[res_size - copy_size], &arg_bytes[arg_size - copy_size], copy_size); +#endif +} + +static inline void zig_big_truncate_big(void *res, const void *arg, bool res_is_signed, uint16_t res_bits, bool arg_is_signed, uint16_t arg_bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_size = zig_int_bytes(res_bits); + + if (res_is_signed != arg_is_signed) zig_unreachable(); + if (res_bits > arg_bits) zig_unreachable(); + + if (res_is_signed) { + uint16_t arg_byte_offset = UINT16_C(0); + +#if zig_big_endian + arg_byte_offset = zig_int_bytes(arg_bits) - res_size; +#endif + + memcpy(&res_bytes[0], &arg_bytes[arg_byte_offset], res_size); + } else { + uint16_t res_byte_offset = zig_shr_u16(res_bits - UINT16_C(1), UINT8_C(3)); + uint16_t arg_byte_offset = res_byte_offset; + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], res_byte_offset); +#else + res_byte_offset = res_size - UINT16_C(1) - res_byte_offset; + arg_byte_offset = zig_int_bytes(arg_bits) - UINT16_C(1) - arg_byte_offset; + + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#endif + + res_bytes[res_byte_offset] = zig_u8_truncate_u8( + arg_bytes[arg_byte_offset], + zig_u8_truncate_u8(res_bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1) + ); + res_byte_offset += UINT16_C(1); + arg_byte_offset += UINT16_C(1); + +#if zig_little_endian + memset(&res_bytes[res_byte_offset], zig_minInt_u8, res_size - res_byte_offset); +#else + memcpy(&res_bytes[res_byte_offset], &arg_bytes[arg_byte_offset], res_size - res_byte_offset); +#endif + } +} + +#define zig_big_casts(is, s, w, IntType) \ + static inline IntType zig_##s##w##_intCast_big(const void *arg, bool arg_is_signed, uint16_t arg_bits) { \ + IntType res; \ + zig_big_intCast_big(&res, arg, is, w, arg_is_signed, arg_bits); \ + return res; \ + } \ +\ + static inline void zig_big_intCast_##s##w(void *res, IntType arg, bool res_is_signed, uint16_t res_bits) { \ + zig_big_intCast_big(res, &arg, res_is_signed, res_bits, is, w); \ + } \ +\ + static inline IntType zig_##s##w##_truncate_big(const void *arg, uint8_t res_bits, bool arg_is_signed, uint16_t arg_bits) { \ + IntType res; \ + zig_big_truncate_big(&res, arg, is, res_bits, arg_is_signed, arg_bits); \ + return res; \ + } \ +\ + static inline void zig_big_truncate_##s##w(void *res, IntType arg, bool res_is_signed, uint16_t res_bits) { \ + zig_big_truncate_big(res, &arg, res_is_signed, res_bits, is, w); \ + } +zig_big_casts(false, u, 8, uint8_t) +zig_big_casts(true , i, 8, int8_t) +zig_big_casts(false, u, 16, uint16_t) +zig_big_casts(true , i, 16, int16_t) +zig_big_casts(false, u, 32, uint32_t) +zig_big_casts(true , i, 32, int32_t) +zig_big_casts(false, u, 64, uint64_t) +zig_big_casts(true , i, 64, int64_t) +zig_big_casts(false, u, 128, zig_u128) +zig_big_casts(true , i, 128, zig_i128) + +static inline void zig_big_bitCast_big(void *res, const void *arg, bool res_is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t size = zig_int_bytes(bits); + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)); + uint16_t remainder_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1); + uint8_t sign_byte; + uint8_t fill_byte; + +#if zig_big_endian + byte_offset = size - UINT16_C(1) - byte_offset; +#endif + + if (res_is_signed) { + int8_t signed_sign_byte = zig_i8_bitCast_u8(arg_bytes[byte_offset], remainder_bits); + + sign_byte = zig_u8_bitCast_i8(signed_sign_byte, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(signed_sign_byte, UINT8_C(7)), UINT8_C(8)); + } else { + sign_byte = zig_u8_bitCast_u8(arg_bytes[byte_offset], remainder_bits); + fill_byte = UINT8_C(0); + } + +#if zig_little_endian + memcpy(&res_bytes[0], &arg_bytes[0], byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memset(&res_bytes[byte_offset], fill_byte, size - byte_offset); +#else + memset(&res_bytes[0], fill_byte, byte_offset); + res_bytes[byte_offset] = sign_byte; + byte_offset += UINT16_C(1); + memcpy(&res_bytes[byte_offset], &arg_bytes[byte_offset], size - byte_offset); +#endif +} + +static inline int32_t zig_cmp_big_u8(const void *lhs, uint8_t rhs, bool is_signed, uint16_t bits) { + const uint8_t *lhs_bytes = lhs; + uint16_t byte_offset = 0; + bool do_signed = is_signed; + uint16_t remaining_bytes = zig_int_bytes(bits); + +#if zig_little_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 128 / CHAR_BIT ? rhs : UINT8_C(0); + int32_t limb_cmp; + +#if zig_little_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + if (do_signed) { + zig_i128 lhs_limb; + zig_i128 rhs_limb = zig_i128_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + limb_cmp = zig_cmp_i128(lhs_limb, rhs_limb); + do_signed = false; + } else { + zig_u128 lhs_limb; + zig_u128 rhs_limb = zig_u128_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + limb_cmp = zig_cmp_u128(lhs_limb, rhs_limb); + } + + if (limb_cmp != 0) return limb_cmp; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 64 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + if (do_signed) { + int64_t lhs_limb; + int64_t rhs_limb = zig_i64_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint64_t lhs_limb; + uint64_t rhs_limb = zig_u64_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 32 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + if (do_signed) { + int32_t lhs_limb; + int32_t rhs_limb = zig_i32_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint32_t lhs_limb; + uint32_t rhs_limb = zig_u32_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 16 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + if (do_signed) { + int16_t lhs_limb; + int16_t rhs_limb = zig_i16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint16_t lhs_limb; + uint16_t rhs_limb = zig_u16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t rhs_byte = remaining_bytes == 16 / CHAR_BIT ? rhs : UINT8_C(0); + +#if zig_little_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + if (do_signed) { + int8_t lhs_limb; + int16_t lhs_cmp_limb; + int16_t rhs_cmp_limb = zig_i16_intCast_u8(rhs_byte); + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + lhs_cmp_limb = zig_i16_intCast_i8(lhs_limb); + if (lhs_cmp_limb != rhs_cmp_limb) return (lhs_cmp_limb > rhs_cmp_limb) - (lhs_cmp_limb < rhs_cmp_limb); + do_signed = false; + } else { + uint8_t lhs_limb; + uint8_t rhs_limb = rhs_byte; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return 0; +} + static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { const uint8_t *lhs_bytes = lhs; const uint8_t *rhs_bytes = rhs; @@ -2579,6 +3308,168 @@ static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_sign return 0; } +static inline void zig_not_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + if (remaining_bytes != 128 / CHAR_BIT || is_signed) { + zig_i128 res_limb; + zig_i128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i128(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + zig_u128 res_limb; + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u128(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + if (remaining_bytes != 64 / CHAR_BIT || is_signed) { + int64_t res_limb; + int64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i64(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint64_t res_limb; + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u64(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + if (remaining_bytes != 32 / CHAR_BIT || is_signed) { + int32_t res_limb; + int32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i32(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint32_t res_limb; + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u32(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + if (remaining_bytes != 16 / CHAR_BIT || is_signed) { + int16_t res_limb; + int16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i16(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint16_t res_limb; + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u16(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + if (remaining_bytes != 8 / CHAR_BIT || is_signed) { + int8_t res_limb; + int8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_i8(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } else { + uint8_t res_limb; + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + res_limb = zig_not_u8(arg_limb, limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + static inline void zig_and_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { uint8_t *res_bytes = res; const uint8_t *lhs_bytes = lhs; @@ -2816,13 +3707,415 @@ static inline void zig_xor_big(void *res, const void *lhs, const void *rhs, bool } } +static inline void zig_increment_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u128(&res_limb, res_limb, zig_make_u128(UINT64_C(0), UINT64_C(1)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u64(&res_limb, res_limb, UINT64_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u32(&res_limb, res_limb, UINT32_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u16(&res_limb, res_limb, UINT16_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_addo_u8(&res_limb, res_limb, UINT8_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_decrement_big(void *res, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u128(&res_limb, res_limb, zig_make_u128(UINT64_C(0), UINT64_C(1)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u64(&res_limb, res_limb, UINT64_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u32(&res_limb, res_limb, UINT32_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u16(&res_limb, res_limb, UINT16_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + bool limb_overflow; + + memcpy(&res_limb, &res_bytes[byte_offset], sizeof(res_limb)); + limb_overflow = zig_subo_u8(&res_limb, res_limb, UINT8_C(1), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + if (!limb_overflow) return; + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_abs_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = 0; + uint16_t remaining_bytes = zig_int_bytes(bits); + if (zig_signFill_big(arg, is_signed, bits) >= INT8_C(0)) { + memcpy(res, arg, remaining_bytes); + return; + } + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + bool overflow = true; + +#if zig_big_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 res_limb; + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u128(&res_limb, zig_not_u128(arg_limb, UINT8_C(128)), zig_make_u128(UINT64_C(0), overflow ? UINT64_C(1) : UINT64_C(0)), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t res_limb; + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u64(&res_limb, zig_not_u64(arg_limb, UINT8_C(64)), overflow ? UINT64_C(1) : UINT64_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t res_limb; + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u32(&res_limb, zig_not_u32(arg_limb, UINT8_C(32)), overflow ? UINT32_C(1) : UINT32_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t res_limb; + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u16(&res_limb, zig_not_u16(arg_limb, UINT8_C(16)), overflow ? UINT16_C(1) : UINT16_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t res_limb; + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + overflow = zig_addo_u8(&res_limb, zig_not_u8(arg_limb, UINT8_C(8)), overflow ? UINT8_C(1) : UINT8_C(0), limb_bits); + memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } +} + +static inline void zig_min_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + memcpy(res, zig_cmp_big(lhs, rhs, is_signed, bits) < INT32_C(0) ? lhs : rhs, zig_int_bytes(bits)); +} + +static inline void zig_max_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + memcpy(res, zig_cmp_big(lhs, rhs, is_signed, bits) >= INT32_C(0) ? lhs : rhs, zig_int_bytes(bits)); +} + static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { uint8_t *res_bytes = res; const uint8_t *lhs_bytes = lhs; const uint8_t *rhs_bytes = rhs; uint16_t byte_offset = 0; uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); bool overflow = false; #if zig_big_endian @@ -3038,7 +4331,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo const uint8_t *rhs_bytes = rhs; uint16_t byte_offset = 0; uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); bool overflow = false; #if zig_big_endian @@ -3248,323 +4541,755 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo return overflow; } +static inline void zig_add_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_addo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow +} + static inline void zig_addw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { (void)zig_addo_big(res, lhs, rhs, is_signed, bits); } +static inline void zig_adds_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = zig_signFill_big(lhs, is_signed, bits); + + if (!zig_addo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); + } +} + +static inline void zig_sub_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_subo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow +} + static inline void zig_subw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { (void)zig_subo_big(res, lhs, rhs, is_signed, bits); } -zig_extern void __udivei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_div_trunc_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __udivei4(res, lhs, rhs, bits); - return; - } +static inline void zig_subs_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = is_signed ? zig_signFill_big(lhs, is_signed, bits) : -INT8_C(1); - zig_trap(); + if (!zig_subo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); + } } -static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_div_trunc_big(res, lhs, rhs, is_signed, bits); - return; +static inline bool zig_mulo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + const uint8_t *rhs_bytes = rhs; + uint16_t size = zig_int_bytes(bits); + uint16_t sign_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t lhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(lhs, is_signed, bits), UINT8_C(8)); + uint8_t rhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(rhs, is_signed, bits), UINT8_C(8)); + uint16_t lhs_byte_offset = sign_byte_offset; + uint16_t lhs_end_byte_offset = UINT16_C(0); + bool overflow = false; + +#if zig_big_endian + lhs_byte_offset = size - lhs_byte_offset; + lhs_end_byte_offset = size - lhs_end_byte_offset; +#endif + + while (lhs_byte_offset != lhs_end_byte_offset) { + uint16_t rhs_byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint16_t res_byte_offset; + uint16_t lhs_byte; + uint8_t res_byte = UINT8_C(0); + uint16_t mul_res = UINT16_C(0); + uint8_t carry = UINT8_C(0); + +#if zig_little_endian + lhs_byte_offset -= UINT16_C(1); +#else + rhs_byte_offset = size - rhs_byte_offset; + end_byte_offset = size - end_byte_offset; +#endif + + lhs_byte = zig_u16_intCast_u8(lhs_bytes[lhs_byte_offset]) ^ lhs_sign_fill; + +#if zig_big_endian + lhs_byte_offset += UINT16_C(1); +#endif + + res_byte_offset = lhs_byte_offset; + + while (res_byte_offset != end_byte_offset) { + bool res_byte_initialized = res_byte_offset != lhs_byte_offset; + +#if zig_big_endian + rhs_byte_offset -= UINT16_C(1); + res_byte_offset -= UINT16_C(1); +#endif + + if (res_byte_initialized) res_byte = res_bytes[res_byte_offset]; + carry = zig_addo_u8(&res_byte, res_byte, carry, UINT8_C(8)); + carry += zig_addo_u8(&res_byte, res_byte, zig_u8_intCast_u16( + zig_shr_u16(mul_res, UINT8_C(8)) + ), UINT8_C(8)); + mul_res = lhs_byte * zig_u16_intCast_u8(rhs_bytes[rhs_byte_offset] ^ rhs_sign_fill); + carry += zig_addo_u8(&res_bytes[res_byte_offset], res_byte, zig_u8_truncate_u16( + mul_res, + UINT8_C(8) + ), UINT8_C(8)); + +#if zig_little_endian + rhs_byte_offset += UINT16_C(1); + res_byte_offset += UINT16_C(1); +#endif + } + + while (rhs_byte_offset != end_byte_offset) { +#if zig_big_endian + rhs_byte_offset -= UINT16_C(1); +#endif + + carry = zig_addo_u8( + &res_byte, + zig_u8_intCast_u16(zig_shr_u16(mul_res, UINT8_C(8))), + carry, + UINT8_C(8) + ); + mul_res = lhs_byte * zig_u16_intCast_u8(rhs_bytes[rhs_byte_offset] ^ rhs_sign_fill); + carry += zig_addo_u8(&res_byte, res_byte, zig_u8_truncate_u16( + mul_res, + UINT8_C(8) + ), UINT8_C(8)); + overflow |= res_byte != UINT8_C(0); + +#if zig_little_endian + rhs_byte_offset += UINT16_C(1); +#endif + } + + overflow |= zig_shr_u16(mul_res, UINT8_C(8)) != UINT16_C(0); + overflow |= carry != UINT8_C(0); } - zig_trap(); +#if zig_little_endian + sign_byte_offset -= UINT64_C(1); +#else + sign_byte_offset = size - sign_byte_offset; +#endif + + if (lhs_sign_fill != rhs_sign_fill) { + uint16_t byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint8_t res_byte; + int8_t signed_res_byte; + uint8_t carry = UINT8_C(0); + +#if zig_big_endian + byte_offset = size - byte_offset; + end_byte_offset += UINT16_C(1); +#endif + + while (byte_offset != end_byte_offset) { +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + carry = zig_subo_u8(&res_byte, UINT8_C(0), carry, UINT8_C(8)); + carry += zig_subo_u8(&res_byte, res_byte, res_bytes[byte_offset], UINT8_C(8)); + carry += zig_subo_u8( + &res_bytes[byte_offset], + res_byte, + (lhs_sign_fill == UINT8_C(0) ? lhs_bytes : rhs_bytes)[byte_offset], + UINT8_C(8) + ); + +#if zig_little_endian + byte_offset += UINT16_C(1); +#endif + } + +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + signed_res_byte = zig_i8_bitCast_u8(res_bytes[byte_offset], UINT8_C(8)); + overflow |= signed_res_byte < INT8_C(0); + overflow |= zig_subo_i8(&signed_res_byte, INT8_C(0), signed_res_byte, UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_intCast_u8(carry), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + (lhs_sign_fill == UINT8_C(0) ? lhs_bytes : rhs_bytes)[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + res_bytes[byte_offset] = zig_i8_bitCast_u8(signed_res_byte, UINT8_C(8)); + } else if (lhs_sign_fill != UINT8_C(0)) { + uint16_t byte_offset = UINT16_C(0); + uint16_t end_byte_offset = sign_byte_offset; + uint8_t res_byte; + int8_t signed_res_byte; + uint8_t carry = UINT8_C(1); + +#if zig_big_endian + byte_offset = size - byte_offset; + end_byte_offset += UINT16_C(1); +#endif + + while (byte_offset != end_byte_offset) { +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + carry = zig_subo_u8(&res_byte, res_bytes[byte_offset], carry, UINT8_C(8)); + carry += zig_subo_u8(&res_byte, res_byte, lhs_bytes[byte_offset], UINT8_C(8)); + carry += zig_subo_u8(&res_bytes[byte_offset], res_byte, rhs_bytes[byte_offset], UINT8_C(8)); + +#if zig_little_endian + byte_offset += UINT16_C(1); +#endif + } + +#if zig_big_endian + byte_offset -= UINT16_C(1); +#endif + + signed_res_byte = zig_i8_bitCast_u8(res_bytes[byte_offset], UINT8_C(8)); + overflow |= signed_res_byte < INT8_C(0); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_intCast_u8(carry), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + lhs_bytes[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + overflow |= zig_subo_i8(&signed_res_byte, signed_res_byte, zig_i8_bitCast_u8( + rhs_bytes[byte_offset], + UINT8_C(8) + ), UINT8_C(8)); + res_bytes[byte_offset] = zig_i8_bitCast_u8(signed_res_byte, UINT8_C(8)); + } else if (is_signed) { + int8_t signed_res_byte = zig_i8_bitCast_u8(res_bytes[sign_byte_offset], UINT8_C(8)); + + overflow |= signed_res_byte < INT8_C(0); + } + + { + uint8_t truncate_bits = zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t fill_byte = UINT8_C(0); + + if (is_signed) { + int8_t sign_byte = zig_i8_bitCast_u8(res_bytes[sign_byte_offset], UINT8_C(8)); + int8_t truncated = zig_i8_truncate_i8(sign_byte, truncate_bits); + + overflow |= sign_byte != truncated; + res_bytes[sign_byte_offset] = zig_u8_bitCast_i8(truncated, UINT8_C(8)); + fill_byte = zig_u8_bitCast_i8(zig_shr_i8(truncated, UINT8_C(7)), UINT8_C(8)); + } else { + uint8_t sign_byte = res_bytes[sign_byte_offset]; + uint8_t truncated = zig_u8_truncate_u8(sign_byte, truncate_bits); + + overflow |= sign_byte != truncated; + res_bytes[sign_byte_offset] = truncated; + } + +#if zig_little_endian + sign_byte_offset += UINT16_C(1); + memset(&res_bytes[sign_byte_offset], fill_byte, size - sign_byte_offset); +#else + memset(&res_bytes[0], fill_byte, sign_byte_offset); +#endif + } + + return overflow; +} + +static inline void zig_mul_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + if (zig_mulo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: integer overflow } -static inline void zig_div_ceil_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - zig_trap(); +static inline void zig_mulw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + (void)zig_mulo_big(res, lhs, rhs, is_signed, bits); } -zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __umodei4(res, lhs, rhs, bits); - return; +static inline void zig_muls_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + int8_t sat_sign = zig_signFill_big(lhs, is_signed, bits) ^ zig_signFill_big(rhs, is_signed, bits); + + if (!zig_mulo_big(res, lhs, rhs, is_signed, bits)) return; + switch (sat_sign) { + case -INT8_C(1): return zig_minInt_big(res, is_signed, bits); + case INT8_C(0): return zig_maxInt_big(res, is_signed, bits); } +} + +static inline void zig_divTrunc_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + if (is_signed) { + zig_extern void __divei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __divei5(res, lhs, rhs, temp, bits); + } else { + zig_extern void __udivei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __udivei5(res, lhs, rhs, temp, bits); + } +} - zig_trap(); +static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + if (is_signed) { + zig_extern void __modei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __modei5(res, lhs, rhs, temp, bits); + } else { + zig_extern void __umodei5(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uint32_t *temp, uintptr_t bits); + __umodei5(res, lhs, rhs, temp, bits); + } } -static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_rem_big(res, lhs, rhs, is_signed, bits); - return; +static inline void zig_divFloor_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool decrement = false; + + if (is_signed) { + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + decrement = zig_u32_bitCast_i32(zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ), UINT8_C(32)) > zig_u32_bitCast_i32(zig_minInt_i32, UINT8_C(32)); } + zig_divTrunc_big(res, lhs, rhs, temp, is_signed, bits); + if (decrement) zig_decrement_big(res, is_signed, bits); +} - zig_trap(); +static inline void zig_divCeil_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool increment = false; + + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + increment = zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ) > INT32_C(0); + zig_divTrunc_big(res, lhs, rhs, temp, is_signed, bits); + if (increment) zig_increment_big(res, is_signed, bits); } -static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t skip_bits = remaining_bytes * 8 - bits; - uint16_t total_lz = 0; - uint16_t limb_lz; - (void)is_signed; +static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, void *temp, bool is_signed, uint16_t bits) { + bool fixup = false; -#if zig_little_endian - byte_offset = remaining_bytes; + zig_rem_big(res, lhs, rhs, temp, is_signed, bits); + if (is_signed && zig_u32_bitCast_i32(zig_xor_i32( + zig_cmp_big_u8(res, UINT8_C(0), is_signed, bits), + zig_and_i32(zig_i32_intCast_i8(zig_signFill_big(rhs, is_signed, bits)), zig_minInt_i32) + ), UINT8_C(32)) > zig_u32_bitCast_i32(zig_minInt_i32, UINT8_C(32))) zig_add_big(res, res, rhs, is_signed, bits); +} + +static inline void zig_shr_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = UINT16_C(0); + uint16_t lhs_byte_offset = zig_shr_u16(rhs, UINT8_C(3)); + uint16_t end_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t lhs_prev_byte; + uint8_t byte_shift = zig_u8_truncate_u16(rhs, UINT8_C(3)); + +#if zig_big_endian + res_byte_offset = size - res_byte_offset; + lhs_byte_offset = size - lhs_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - while (remaining_bytes >= 128 / CHAR_BIT) { + { +#if zig_big_endian + lhs_byte_offset -= UINT16_C(1); +#endif + + lhs_prev_byte = lhs_bytes[lhs_byte_offset]; + #if zig_little_endian - byte_offset -= 128 / CHAR_BIT; + lhs_byte_offset += UINT16_C(1); +#endif + } + + while (lhs_byte_offset != end_byte_offset) { +#if zig_big_endian + res_byte_offset -= UINT16_C(1); + lhs_byte_offset -= UINT16_C(1); #endif { - zig_u128 val_limb; + uint8_t lhs_byte = lhs_bytes[lhs_byte_offset]; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u128(val_limb, 128 - skip_bits); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_prev_byte) + ), byte_shift)); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 128 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 128 / CHAR_BIT; +#if zig_little_endian + res_byte_offset += UINT16_C(1); + lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 64 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 64 / CHAR_BIT; + { + uint8_t lhs_sign_fill = UINT8_C(0); + +#if zig_big_endian + res_byte_offset -= UINT16_C(1); #endif - { - uint64_t val_limb; + if (is_signed) { + int8_t signed_byte = zig_i8_bitCast_u8(lhs_prev_byte, UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u64(val_limb, 64 - skip_bits); + res_bytes[res_byte_offset] = zig_shr_i8(signed_byte, byte_shift); + lhs_sign_fill = zig_u8_bitCast_i8(zig_shr_i8(signed_byte, UINT8_C(7)), UINT8_C(8)); + } else { + res_bytes[res_byte_offset] = zig_shr_u8(lhs_prev_byte, byte_shift); } - total_lz += limb_lz; - if (limb_lz < 64 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 64 / CHAR_BIT; +#if zig_little_endian + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], lhs_sign_fill, size - res_byte_offset); +#else + memset(&res_bytes[0], lhs_sign_fill, res_byte_offset); #endif } +} + +static inline bool zig_shlo_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *lhs_bytes = lhs; + uint8_t lhs_sign_fill = zig_u8_bitCast_i8(zig_signFill_big(lhs, is_signed, bits), UINT8_C(8)); + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t lhs_byte_offset = UINT16_C(0); + uint16_t end_byte_offset = res_byte_offset - UINT16_C(1) - zig_shr_u16(rhs, UINT8_C(3)); + uint8_t lhs_prev_byte = lhs_sign_fill; + uint8_t byte_shift = UINT8_C(8) - zig_u8_truncate_u16(rhs, UINT8_C(3)); + bool overflow = false; - while (remaining_bytes >= 32 / CHAR_BIT) { #if zig_little_endian - byte_offset -= 32 / CHAR_BIT; + lhs_byte_offset = size - lhs_byte_offset; +#else + res_byte_offset = size - res_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - { - uint32_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u32(val_limb, 32 - skip_bits); - } + while (lhs_byte_offset != end_byte_offset) { +#if zig_little_endian + lhs_byte_offset -= UINT16_C(1); +#endif - total_lz += limb_lz; - if (limb_lz < 32 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 32 / CHAR_BIT; + overflow |= lhs_prev_byte != lhs_sign_fill; + lhs_prev_byte = lhs_bytes[lhs_byte_offset]; #if zig_big_endian - byte_offset += 32 / CHAR_BIT; + lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 16 / CHAR_BIT) { #if zig_little_endian - byte_offset -= 16 / CHAR_BIT; + end_byte_offset = UINT16_C(0); +#else + end_byte_offset = size; +#endif + + { + bool lhs_more_bytes = lhs_byte_offset != end_byte_offset; + +#if zig_little_endian + if (lhs_more_bytes) lhs_byte_offset -= UINT16_C(1); #endif { - uint16_t val_limb; + uint8_t lhs_byte = UINT8_C(0); + + if (lhs_more_bytes) lhs_byte = lhs_bytes[lhs_byte_offset]; + + if (is_signed) { + int16_t shifted = zig_shr_i16(zig_or_i16( + zig_shl_i16(zig_i16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_i16_intCast_u8(lhs_byte) + ), byte_shift); + int8_t truncated = zig_i8_truncate_i16( + shifted, + zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1) + ); + uint8_t fill = zig_u8_bitCast_i8(zig_shr_i8(truncated, UINT8_C(7)), UINT8_C(8)); + + overflow |= zig_i16_intCast_i8(truncated) != shifted; +#if zig_little_endian + memset(&res_bytes[res_byte_offset], fill, size - res_byte_offset); + res_byte_offset -= UINT16_C(1); +#else + memset(&res_bytes[0], fill, res_byte_offset); +#endif + res_bytes[res_byte_offset] = zig_u8_bitCast_i8(truncated, UINT8_C(8)); + } else { + uint16_t shifted = zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_byte) + ), byte_shift); + uint8_t truncated = zig_u8_truncate_u16( + shifted, + zig_u8_truncate_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT8_C(1) + ); + + overflow |= zig_u16_intCast_u8(truncated) != shifted; +#if zig_little_endian + memset(&res_bytes[res_byte_offset], zig_minInt_u8, size - res_byte_offset); + res_byte_offset -= UINT16_C(1); +#else + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#endif + res_bytes[res_byte_offset] = truncated; + } - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u16(val_limb, 16 - skip_bits); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 16 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 16 / CHAR_BIT; - #if zig_big_endian - byte_offset += 16 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + if (lhs_more_bytes) lhs_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 8 / CHAR_BIT) { + while (lhs_byte_offset != end_byte_offset) { #if zig_little_endian - byte_offset -= 8 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); + lhs_byte_offset -= UINT16_C(1); #endif { - uint8_t val_limb; + uint8_t lhs_byte = lhs_bytes[lhs_byte_offset]; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u8(val_limb, 8 - skip_bits); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + zig_u16_intCast_u8(lhs_byte) + ), byte_shift)); + lhs_prev_byte = lhs_byte; } - total_lz += limb_lz; - if (limb_lz < 8 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 8 / CHAR_BIT; - #if zig_big_endian - byte_offset += 8 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + lhs_byte_offset += UINT16_C(1); #endif } - return total_lz; -} + { +#if zig_little_endian + res_byte_offset -= UINT16_C(1); +#endif -static inline uint16_t zig_ctz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t total_tz = 0; - uint16_t limb_tz; - (void)is_signed; + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16( + zig_shl_u16(zig_u16_intCast_u8(lhs_prev_byte), UINT8_C(8)), + byte_shift + )); #if zig_big_endian - byte_offset = remaining_bytes; + res_byte_offset += UINT16_C(1); #endif + } - while (remaining_bytes >= 128 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 128 / CHAR_BIT; +#if zig_little_endian + memset(&res_bytes[0], zig_minInt_u8, res_byte_offset); +#else + memset(&res_bytes[res_byte_offset], zig_minInt_u8, size - res_byte_offset); #endif - { - zig_u128 val_limb; + return overflow; +} - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u128(val_limb, 128); - } +static inline void zig_shl_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + if (zig_shlo_big(res, lhs, rhs, is_signed, bits)) zig_trap(); // panic: left shift overflowed bits +} - total_tz += limb_tz; - if (limb_tz < 128) return total_tz; - remaining_bytes -= 128 / CHAR_BIT; +static inline void zig_shlw_big(void *res, const void *lhs, uint16_t rhs, bool is_signed, uint16_t bits) { + (void)zig_shlo_big(res, lhs, rhs, is_signed, bits); +} -#if zig_little_endian - byte_offset += 128 / CHAR_BIT; -#endif +#define zig_big_shls_builtin(w) \ + static inline uint##w##_t zig_shls_u##w##_big(uint##w##_t lhs, const void *rhs, \ + uint8_t lhs_bits, bool rhs_is_signed, uint16_t rhs_bits) { \ + uint##w##_t res; \ + const uint8_t *rhs_bytes = rhs; \ + if (zig_cmp_big_u8(rhs, lhs_bits, rhs_is_signed, rhs_bits) < INT32_C(0) && \ + !zig_shlo_u##w(&res, lhs, rhs_bytes[0], lhs_bits)) return res; \ + return lhs == INT##w##_C(0) ? zig_minInt_u(w, lhs_bits) : zig_maxInt_u(w, lhs_bits); \ + } \ +\ + static inline int##w##_t zig_shls_i##w##_big(int##w##_t lhs, const void *rhs, \ + uint8_t lhs_bits, bool rhs_is_signed, uint16_t rhs_bits) { \ + int##w##_t res; \ + const uint8_t *rhs_bytes = rhs; \ + if (zig_cmp_big_u8(rhs, lhs_bits, rhs_is_signed, rhs_bits) < INT32_C(0) && \ + !zig_shlo_i##w(&res, lhs, rhs_bytes[0], lhs_bits)) return res; \ + return lhs == INT##w##_C(0) ? INT##w##_C(0) : \ + lhs < INT##w##_C(0) ? zig_minInt_i(w, lhs_bits) : zig_maxInt_i(w, lhs_bits); \ + } \ +\ + static inline void zig_shls_big_u##w(void *res, const void *lhs, uint##w##_t rhs, bool is_signed, uint16_t bits) { \ + const uint8_t *lhs_bytes = lhs; \ + if (rhs < bits && !zig_shlo_big(res, lhs, zig_u16_intCast_u##w(rhs), is_signed, bits)) return; \ + switch (zig_cmp_big_u8(lhs, UINT8_C(0), is_signed, bits)) { \ + case -INT32_C(1): return zig_minInt_big(res, is_signed, bits); \ + case INT32_C(0): return zig_minInt_big(res, false, bits); \ + case INT32_C(1): return zig_maxInt_big(res, is_signed, bits); \ + default: zig_unreachable(); \ + } \ } +zig_big_shls_builtin(8) +zig_big_shls_builtin(16) +zig_big_shls_builtin(32) +zig_big_shls_builtin(64) + +static inline void zig_byteSwap_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t res_byte_offset = UINT16_C(0); + uint16_t arg_byte_offset = bits / CHAR_BIT; + uint16_t end_byte_offset = UINT16_C(1); + uint16_t size = zig_int_bytes(bits); - while (remaining_bytes >= 64 / CHAR_BIT) { #if zig_big_endian - byte_offset -= 64 / CHAR_BIT; + res_byte_offset = size - res_byte_offset; + arg_byte_offset = size - arg_byte_offset; + end_byte_offset = size - end_byte_offset; #endif - { - uint64_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u64(val_limb, 64); - } + while (arg_byte_offset != end_byte_offset) { +#if zig_little_endian + arg_byte_offset -= UINT16_C(1); +#else + res_byte_offset -= UINT16_C(1); +#endif - total_tz += limb_tz; - if (limb_tz < 64) return total_tz; - remaining_bytes -= 64 / CHAR_BIT; + res_bytes[res_byte_offset] = arg_bytes[arg_byte_offset]; #if zig_little_endian - byte_offset += 64 / CHAR_BIT; + res_byte_offset += UINT16_C(1); +#else + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 32 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 32 / CHAR_BIT; + { +#if zig_little_endian + arg_byte_offset -= UINT16_C(1); +#else + res_byte_offset -= UINT16_C(1); #endif { - uint32_t val_limb; + uint8_t byte = arg_bytes[arg_byte_offset]; + uint8_t fill = is_signed + ? zig_u8_bitCast_i8(zig_shr_i8(zig_i8_bitCast_u8(byte, UINT8_C(8)), UINT8_C(7)), UINT8_C(8)) + : UINT8_C(0); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u32(val_limb, 32); + res_bytes[res_byte_offset] = byte; + +#if zig_little_endian + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], fill, size - res_byte_offset); +#else + memset(&res_bytes[0], fill, res_byte_offset); +#endif } + } +} - total_tz += limb_tz; - if (limb_tz < 32) return total_tz; - remaining_bytes -= 32 / CHAR_BIT; +static inline void zig_bitReverse_big(void *res, const void *arg, bool is_signed, uint16_t bits) { + uint8_t *res_bytes = res; + const uint8_t *arg_bytes = arg; + uint16_t size = zig_int_bytes(bits); + uint16_t res_byte_offset = UINT16_C(0); + uint16_t arg_byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t end_byte_offset = UINT16_C(0); + uint8_t arg_prev_byte; + uint8_t byte_shift = zig_u8_intCast_u16(zig_subw_u16(UINT16_C(0), bits, UINT8_C(3))); + +#if zig_big_endian + res_byte_offset = size - res_byte_offset; + arg_byte_offset = size - arg_byte_offset; + end_byte_offset = size - end_byte_offset; +#endif + { #if zig_little_endian - byte_offset += 32 / CHAR_BIT; + arg_byte_offset -= UINT16_C(1); +#endif + + arg_prev_byte = zig_bitReverse_u8(arg_bytes[arg_byte_offset], UINT8_C(8)); + +#if zig_big_endian + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 16 / CHAR_BIT) { + while (arg_byte_offset != end_byte_offset) { #if zig_big_endian - byte_offset -= 16 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); +#else + arg_byte_offset -= UINT16_C(1); #endif { - uint16_t val_limb; + uint8_t arg_byte = zig_bitReverse_u8(arg_bytes[arg_byte_offset], UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u16(val_limb, 16); + res_bytes[res_byte_offset] = zig_u8_intCast_u16(zig_shr_u16(zig_or_u16( + zig_shl_u16(zig_u16_intCast_u8(arg_byte), UINT8_C(8)), + zig_u16_intCast_u8(arg_prev_byte) + ), byte_shift)); + arg_prev_byte = arg_byte; } - total_tz += limb_tz; - if (limb_tz < 16) return total_tz; - remaining_bytes -= 16 / CHAR_BIT; - #if zig_little_endian - byte_offset += 16 / CHAR_BIT; + res_byte_offset += UINT16_C(1); +#else + arg_byte_offset += UINT16_C(1); #endif } - while (remaining_bytes >= 8 / CHAR_BIT) { + { + uint8_t arg_sign_fill = UINT8_C(0); + #if zig_big_endian - byte_offset -= 8 / CHAR_BIT; + res_byte_offset -= UINT16_C(1); #endif - { - uint8_t val_limb; + if (is_signed) { + int8_t signed_byte = zig_i8_bitCast_u8(arg_prev_byte, UINT8_C(8)); - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u8(val_limb, 8); + res_bytes[res_byte_offset] = zig_shr_i8(signed_byte, byte_shift); + arg_sign_fill = zig_u8_bitCast_i8(zig_shr_i8(signed_byte, UINT8_C(7)), UINT8_C(8)); + } else { + res_bytes[res_byte_offset] = zig_shr_u8(arg_prev_byte, byte_shift); } - total_tz += limb_tz; - if (limb_tz < 8) return total_tz; - remaining_bytes -= 8 / CHAR_BIT; - #if zig_little_endian - byte_offset += 8 / CHAR_BIT; + res_byte_offset += UINT16_C(1); + memset(&res_bytes[res_byte_offset], arg_sign_fill, size - res_byte_offset); +#else + memset(&res_bytes[0], arg_sign_fill, res_byte_offset); #endif } - - return total_tz; } -static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; +static inline uint16_t zig_popCount_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); + uint16_t remaining_bytes = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); uint16_t total_pc = 0; (void)is_signed; #if zig_big_endian - byte_offset = remaining_bytes; + byte_offset = zig_int_bytes(bits); #endif while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 128 / CHAR_BIT; #endif { - zig_u128 val_limb; + zig_u128 arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u128(val_limb, 128); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 128 / CHAR_BIT; @@ -3575,15 +5300,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 64 / CHAR_BIT; #endif { - uint64_t val_limb; + uint64_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u64(val_limb, 64); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 64 / CHAR_BIT; @@ -3594,15 +5321,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 32 / CHAR_BIT; #endif { - uint32_t val_limb; + uint32_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u32(val_limb, 32); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 32 / CHAR_BIT; @@ -3613,15 +5342,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 16 / CHAR_BIT; #endif { - uint16_t val_limb; + uint16_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u16(val_limb, 16); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 16 / CHAR_BIT; @@ -3632,15 +5363,17 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ } while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + #if zig_big_endian byte_offset -= 8 / CHAR_BIT; #endif { - uint8_t val_limb; + uint8_t arg_limb; - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u8(val_limb, 8); + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + total_pc += zig_popCount_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); } remaining_bytes -= 8 / CHAR_BIT; @@ -3653,6 +5386,274 @@ static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_ return total_pc; } +static inline uint16_t zig_ctz_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = UINT16_C(0); + uint16_t remaining_bytes = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + uint16_t total_tz = UINT16_C(0); + uint16_t limb_tz; + (void)is_signed; + +#if zig_big_endian + byte_offset = zig_int_bytes(bits); +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_tz = zig_ctz_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); + } + + total_tz += limb_tz; + if (limb_tz < limb_bits) return total_tz; + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_little_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return total_tz; +} + +static inline uint16_t zig_clz_big(const void *arg, bool is_signed, uint16_t bits) { + const uint8_t *arg_bytes = arg; + uint16_t byte_offset = zig_shr_u16(bits - UINT16_C(1), UINT8_C(3)) + UINT16_C(1); + uint16_t remaining_bytes = byte_offset; + uint8_t top_bits = zig_u8_intCast_u16(remaining_bytes * CHAR_BIT - bits); + bool sign_limb = true; + uint16_t total_lz = UINT16_C(0); + uint16_t limb_lz; + (void)is_signed; + +#if zig_big_endian + byte_offset = zig_int_bytes(bits) - remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(128) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + { + zig_u128 arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u128(zig_u128_truncate_u128(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(64) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + { + uint64_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u64(zig_u64_truncate_u64(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(32) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + { + uint32_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u32(zig_u32_truncate_u32(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(16) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + { + uint16_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u16(zig_u16_truncate_u16(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { + uint8_t limb_bits = UINT8_C(8) - (sign_limb ? top_bits : UINT8_C(0)); + +#if zig_little_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + { + uint8_t arg_limb; + + memcpy(&arg_limb, &arg_bytes[byte_offset], sizeof(arg_limb)); + limb_lz = zig_clz_u8(zig_u8_truncate_u8(arg_limb, limb_bits), limb_bits); + } + + total_lz += limb_lz; + if (limb_lz < limb_bits) return total_lz; + sign_limb = false; + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_big_endian + byte_offset += 8 / CHAR_BIT; +#endif + } + + return total_lz; +} + /* ========================= Floating Point Support ========================= */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ @@ -3687,29 +5688,29 @@ long double __cdecl nanl(char const* input); #define zig_make_special_f80(sign, name, arg, repr) sign zig_make_f80 (__builtin_##name, )(arg) #define zig_make_special_f128(sign, name, arg, repr) sign zig_make_f128(__builtin_##name, )(arg) #else -#define zig_make_special_f16(sign, name, arg, repr) zig_bitCast_f16 (repr) -#define zig_make_special_f32(sign, name, arg, repr) zig_bitCast_f32 (repr) -#define zig_make_special_f64(sign, name, arg, repr) zig_bitCast_f64 (repr) -#define zig_make_special_f80(sign, name, arg, repr) zig_bitCast_f80 (repr) -#define zig_make_special_f128(sign, name, arg, repr) zig_bitCast_f128(repr) +#define zig_make_special_f16(sign, name, arg, repr) zig_f16_bitCast_u16 (repr) +#define zig_make_special_f32(sign, name, arg, repr) zig_f32_bitCast_u32 (repr) +#define zig_make_special_f64(sign, name, arg, repr) zig_f64_bitCast_u64 (repr) +#define zig_make_special_f80(sign, name, arg, repr) zig_f80_bitCast_u128(repr) +#define zig_make_special_f128(sign, name, arg, repr) zig_f128_bitCast_u128(repr) #endif #define zig_has_f16 1 #define zig_libc_name_f16(name) __##name##h #define zig_init_special_f16(sign, name, arg, repr) zig_make_special_f16(sign, name, arg, repr) -#if FLT_MANT_DIG == 11 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && FLT_MANT_DIG == 11 typedef float zig_f16; #define zig_make_f16(fp, repr) fp##f -#elif DBL_MANT_DIG == 11 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && DBL_MANT_DIG == 11 typedef double zig_f16; #define zig_make_f16(fp, repr) fp -#elif LDBL_MANT_DIG == 11 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && LDBL_MANT_DIG == 11 typedef long double zig_f16; #define zig_make_f16(fp, repr) fp##l -#elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gcc)) +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gcc)) typedef _Float16 zig_f16; #define zig_make_f16(fp, repr) fp##f16 -#elif defined(__SIZEOF_FP16__) +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F16_ABI) && defined(__SIZEOF_FP16__) typedef __fp16 zig_f16; #define zig_make_f16(fp, repr) fp##f16 #else @@ -3723,11 +5724,6 @@ typedef uint16_t zig_f16; #undef zig_init_special_f16 #define zig_init_special_f16(sign, name, arg, repr) repr #endif -#if defined(zig_darwin) && defined(zig_x86) -typedef uint16_t zig_compiler_rt_f16; -#else -typedef zig_f16 zig_compiler_rt_f16; -#endif #define zig_has_f32 1 #define zig_libc_name_f32(name) name##f @@ -3736,16 +5732,16 @@ typedef zig_f16 zig_compiler_rt_f16; #else #define zig_init_special_f32(sign, name, arg, repr) zig_make_special_f32(sign, name, arg, repr) #endif -#if FLT_MANT_DIG == 24 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && FLT_MANT_DIG == 24 typedef float zig_f32; #define zig_make_f32(fp, repr) fp##f -#elif DBL_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && DBL_MANT_DIG == 24 typedef double zig_f32; #define zig_make_f32(fp, repr) fp -#elif LDBL_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && LDBL_MANT_DIG == 24 typedef long double zig_f32; #define zig_make_f32(fp, repr) fp##l -#elif FLT32_MANT_DIG == 24 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F32_ABI) && FLT32_MANT_DIG == 24 typedef _Float32 zig_f32; #define zig_make_f32(fp, repr) fp##f32 #else @@ -3768,19 +5764,19 @@ typedef uint32_t zig_f32; #else #define zig_init_special_f64(sign, name, arg, repr) zig_make_special_f64(sign, name, arg, repr) #endif -#if FLT_MANT_DIG == 53 +#if !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT_MANT_DIG == 53 typedef float zig_f64; #define zig_make_f64(fp, repr) fp##f -#elif DBL_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && DBL_MANT_DIG == 53 typedef double zig_f64; #define zig_make_f64(fp, repr) fp -#elif LDBL_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && LDBL_MANT_DIG == 53 typedef long double zig_f64; #define zig_make_f64(fp, repr) fp##l -#elif FLT64_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT64_MANT_DIG == 53 typedef _Float64 zig_f64; #define zig_make_f64(fp, repr) fp##f64 -#elif FLT32X_MANT_DIG == 53 +#elif !defined(ZIG_TARGET_SOFT_COMPILER_RT_F64_ABI) && FLT32X_MANT_DIG == 53 typedef _Float32x zig_f64; #define zig_make_f64(fp, repr) fp##f32x #else @@ -3798,7 +5794,14 @@ typedef uint64_t zig_f64; #define zig_has_f80 1 #define zig_libc_name_f80(name) __##name##x #define zig_init_special_f80(sign, name, arg, repr) zig_make_special_f80(sign, name, arg, repr) -#if FLT_MANT_DIG == 64 +#ifdef ZIG_TARGET_SOFT_COMPILER_RT_F80_ABI +#undef zig_has_f80 +typedef struct { uint64_t mantissa; uint16_t exponent; } zig_f80; +#define zig_init_repr_f80(mantissa, exponent) { .mant##issa = mantissa, .expo##nent = exponent } +#define zig_make_repr_f80(mantissa, exponent) (zig_f80)zig_init_repr_f80(mantissa, exponent) +#define zig_mantissa_repr_f80(arg) (arg).mantissa +#define zig_exponent_repr_f80(arg) (arg).exponent +#elif FLT_MANT_DIG == 64 typedef float zig_f80; #define zig_make_f80(fp, repr) fp##f #elif DBL_MANT_DIG == 64 @@ -3818,68 +5821,91 @@ typedef __float80 zig_f80; #define zig_make_f80(fp, repr) fp##l #else #undef zig_has_f80 -#define zig_has_f80 0 -#define zig_repr_f80 u128 typedef zig_u128 zig_f80; +#define zig_init_repr_f80(mantissa, exponent) zig_init_u128(exponent, mantissa) +#define zig_make_repr_f80(mantissa, exponent) zig_make_u128(exponent, mantissa) +#define zig_mantissa_repr_f80(arg) zig_lo_u128(arg) +#define zig_exponent_repr_f80(arg) (uint16_t)zig_hi_u128(arg) +#endif +#ifndef zig_has_f80 +#define zig_has_f80 0 #define zig_make_f80(fp, repr) repr +#ifndef zig_make_repr_f80 +#define zig_make_repr_f80(mantissa, exponent) (zig_f80)zig_init_repr_f80(mantissa, exponent) +#endif #undef zig_make_special_f80 #define zig_make_special_f80(sign, name, arg, repr) repr #undef zig_init_special_f80 #define zig_init_special_f80(sign, name, arg, repr) repr #endif -#if defined(zig_gcc) && defined(zig_x86) -#define zig_f128_has_miscompilations 1 -#else -#define zig_f128_has_miscompilations 0 -#endif - #define zig_has_f128 1 -#define zig_libc_name_f128(name) name##q +#define zig_libc_name_f128(name) name##f128 #define zig_init_special_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr) -#if !zig_f128_has_miscompilations && FLT_MANT_DIG == 113 +#ifdef ZIG_TARGET_SOFT_COMPILER_RT_F128_ABI +#undef zig_has_f128 +#if zig_little_endian +typedef struct { uint64_t lo, hi; } zig_f128; +#else +typedef struct { uint64_t hi, lo; } zig_f128; +#endif +#define zig_init_repr_f128(hi, lo) { .h##i = hi, .l##o = lo } +#define zig_lo_repr_f128(arg) (arg).lo +#define zig_hi_repr_f128(arg) (arg).hi +#elif FLT_MANT_DIG == 113 typedef float zig_f128; #define zig_make_f128(fp, repr) fp##f -#elif !zig_f128_has_miscompilations && DBL_MANT_DIG == 113 +#elif DBL_MANT_DIG == 113 typedef double zig_f128; #define zig_make_f128(fp, repr) fp -#elif !zig_f128_has_miscompilations && LDBL_MANT_DIG == 113 +#elif LDBL_MANT_DIG == 113 typedef long double zig_f128; #define zig_make_f128(fp, repr) fp##l -#elif !zig_f128_has_miscompilations && FLT128_MANT_DIG == 113 +#elif FLT128_MANT_DIG == 113 typedef _Float128 zig_f128; #define zig_make_f128(fp, repr) fp##f128 -#elif !zig_f128_has_miscompilations && FLT64X_MANT_DIG == 113 +#elif FLT64X_MANT_DIG == 113 typedef _Float64x zig_f128; #define zig_make_f128(fp, repr) fp##f64x -#elif !zig_f128_has_miscompilations && defined(__SIZEOF_FLOAT128__) +#elif defined(__SIZEOF_FLOAT128__) typedef __float128 zig_f128; #define zig_make_f128(fp, repr) fp##q #undef zig_make_special_f128 #define zig_make_special_f128(sign, name, arg, repr) sign __builtin_##name##f128(arg) #else #undef zig_has_f128 -#define zig_has_f128 0 -#undef zig_make_special_f128 -#undef zig_init_special_f128 -#if defined(zig_darwin) || defined(zig_aarch64) -typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_v2u64; -zig_basic_operator(zig_v2u64, xor_v2u64, ^) -#define zig_repr_f128 v2u64 -typedef zig_v2u64 zig_f128; -#define zig_make_f128_zig_make_u128(hi, lo) (zig_f128){ lo, hi } -#define zig_make_f128_zig_init_u128 zig_make_f128_zig_make_u128 -#define zig_make_f128(fp, repr) zig_make_f128_##repr -#define zig_make_special_f128(sign, name, arg, repr) zig_make_f128_##repr -#define zig_init_special_f128(sign, name, arg, repr) zig_make_f128_##repr +#if defined(zig_x86_64) && defined(ZIG_TARGET_ABI_MSVC) +#if defined(zig_msvc) && !defined(__clang__) +#include +typedef __m128i zig_f128; +#define zig_init_repr_f128(hi, lo) { .m128i_u64 = { lo, hi } } +#define zig_lo_repr_f128(arg) (arg).m128i_u64[0] +#define zig_hi_repr_f128(arg) (arg).m128i_u64[1] +#else +typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_f128; +#define zig_init_repr_f128(hi, lo) { lo, hi } +#define zig_lo_repr_f128(arg) (arg)[0] +#define zig_hi_repr_f128(arg) (arg)[1] +#endif #else -#define zig_repr_f128 u128 typedef zig_u128 zig_f128; +#define zig_init_repr_f128(hi, lo) zig_init_u128(hi, lo) +#define zig_make_repr_f128(hi, lo) zig_make_u128(hi, lo) +#define zig_lo_repr_f128(arg) zig_lo_u128(arg) +#define zig_hi_repr_f128(arg) zig_hi_u128(arg) +#endif +#endif +#ifndef zig_has_f128 +#define zig_has_f128 0 #define zig_make_f128(fp, repr) repr +#ifndef zig_make_repr_f128 +#define zig_make_repr_f128(hi, lo) (zig_f128)zig_init_repr_f128(hi, lo) +#endif +#undef zig_make_special_f128 #define zig_make_special_f128(sign, name, arg, repr) repr +#undef zig_init_special_f128 #define zig_init_special_f128(sign, name, arg, repr) repr #endif -#endif #if !defined(zig_msvc) && defined(ZIG_TARGET_ABI_MSVC) /* Emulate msvc abi on a gnu compiler */ @@ -3892,84 +5918,141 @@ typedef zig_f128 zig_c_longdouble; typedef long double zig_c_longdouble; #endif -#define zig_bitCast_float(Type, ReprType) \ - static inline zig_##Type zig_bitCast_##Type(ReprType repr) { \ - zig_##Type result; \ - memcpy(&result, &repr, sizeof(result)); \ - return result; \ +#if __AVR__ +typedef signed char zig_FloatCompareResult; +#elif defined(zig_aarch64) +typedef signed int zig_FloatCompareResult; +#elif __SIZEOF_LONG__ >= __SIZEOF_POINTER__ +typedef signed long zig_FloatCompareResult; +#else +typedef signed long long zig_FloatCompareResult; +#endif + +#define zig_bitCast_float(w, iw, UnsignedReprType, SignedReprType) \ + static inline zig_f##w zig_f##w##_bitCast_u##iw(UnsignedReprType arg) { \ + zig_f##w res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return res; \ + } \ + static inline zig_f##w zig_f##w##_bitCast_i##iw(SignedReprType arg) { \ + zig_f##w res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return res; \ + } \ + static inline UnsignedReprType zig_u##iw##_bitCast_f##w(zig_f##w arg) { \ + UnsignedReprType res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return zig_u##iw##_truncate_u##iw(res, w); \ + } \ + static inline SignedReprType zig_i##iw##_bitCast_f##w(zig_f##w arg) { \ + SignedReprType res; \ + memcpy(&res, &arg, sizeof(zig_f##w)); \ + return zig_i##iw##_truncate_i##iw(res, w); \ + } +zig_bitCast_float(16, 16, uint16_t, int16_t) +zig_bitCast_float(32, 32, uint32_t, int32_t) +zig_bitCast_float(64, 64, uint64_t, int64_t) +#if zig_has_f80 +zig_bitCast_float(80, 128, zig_u128, zig_i128) +#else +static inline zig_f80 zig_f80_bitCast_u128(zig_u128 arg) { + return zig_make_repr_f80(zig_lo_u128(arg), (uint16_t)zig_hi_u128(arg)); +} +static inline zig_f80 zig_f80_bitCast_i128(zig_i128 arg) { + return zig_make_repr_f80(zig_lo_i128(arg), (uint16_t)zig_hi_i128(arg)); +} +static inline zig_u128 zig_u128_bitCast_f80(zig_f80 arg) { + return zig_make_u128(zig_exponent_repr_f80(arg), zig_mantissa_repr_f80(arg)); +} +static inline zig_i128 zig_i128_bitCast_f80(zig_f80 arg) { + return zig_make_i128((int16_t)zig_exponent_repr_f80(arg), zig_mantissa_repr_f80(arg)); +} +#endif +static inline zig_f80 zig_f80_bitCast_big(const void *arg) { + return zig_f80_bitCast_u128(zig_u128_truncate_big(arg, UINT8_C(80), false, UINT16_C(80))); +} +static inline void zig_big_bitCast_f80(void *res, zig_f80 arg, bool res_is_signed, uint16_t res_bits) { + if (res_is_signed) { + zig_big_truncate_i128(res, zig_i128_bitCast_f80(arg), res_is_signed, res_bits); + } else { + zig_big_truncate_u128(res, zig_u128_bitCast_f80(arg), res_is_signed, res_bits); } -zig_bitCast_float(f16, uint16_t) -zig_bitCast_float(f32, uint32_t) -zig_bitCast_float(f64, uint64_t) -zig_bitCast_float(f80, zig_u128) -zig_bitCast_float(f128, zig_u128) +} +#if zig_has_f128 +zig_bitCast_float(128, 128, zig_u128, zig_i128) +#else +static inline zig_f128 zig_f128_bitCast_u128(zig_u128 arg) { + return zig_make_repr_f128(zig_hi_u128(arg), zig_lo_u128(arg)); +} +static inline zig_f128 zig_f128_bitCast_i128(zig_i128 arg) { + return zig_make_repr_f128((uint64_t)zig_hi_i128(arg), zig_lo_i128(arg)); +} +static inline zig_u128 zig_u128_bitCast_f128(zig_f128 arg) { + return zig_make_u128(zig_hi_repr_f128(arg), zig_lo_repr_f128(arg)); +} +static inline zig_i128 zig_i128_bitCast_f128(zig_f128 arg) { + return zig_make_i128((int64_t)zig_hi_repr_f128(arg), zig_lo_repr_f128(arg)); +} +#endif -#define zig_convert_builtin(ExternResType, ResType, operation, ExternArgType, ArgType, version) \ - zig_extern ExternResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ExternArgType); \ +#define zig_convert_float_00(ResType, operation, ArgType, version) \ + zig_extern ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ + zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ArgType arg); \ + return zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ + zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(arg) +#define zig_convert_float_01(ResType, operation, ArgType, version) \ + zig_convert_float_00(ResType, operation, ArgType, version) +#define zig_convert_float_10(ResType, operation, ArgType, version) \ + zig_convert_float_00(ResType, operation, ArgType, version) +#define zig_convert_float_11(ResType, operation, ArgType, version) \ + return (ResType)arg +#define zig_convert_float(res_when, ResType, operation, arg_when, ArgType, version) \ static inline ResType zig_expand_concat(zig_expand_concat(zig_##operation, \ zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType)(ArgType arg) { \ - ResType res; \ - ExternResType extern_res; \ - ExternArgType extern_arg; \ - memcpy(&extern_arg, &arg, sizeof(extern_arg)); \ - extern_res = zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(extern_arg); \ - memcpy(&res, &extern_res, sizeof(res)); \ - return extern_res; \ + zig_expand_concat(zig_expand_concat(zig_convert_float_, zig_has_##res_when), \ + zig_has_##arg_when)(ResType, operation, ArgType, version); \ } -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f32, zig_f32, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f80, zig_f80, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f80, zig_f80, 2) -#ifdef __ARM_EABI__ +#define zig_convert_floats(SmallType, BigType) \ + zig_convert_float(SmallType, zig_##SmallType, trunc, BigType, zig_##BigType, 2) \ + zig_convert_float(BigType, zig_##BigType, extend, SmallType, zig_##SmallType, 2) +zig_convert_floats(f16, f32) +zig_convert_floats(f16, f64) +zig_convert_floats(f16, f80) +zig_convert_floats(f16, f128) +zig_convert_floats(f32, f64) +zig_convert_floats(f32, f80) +zig_convert_floats(f32, f128) +zig_convert_floats(f64, f80) +zig_convert_floats(f64, f128) +zig_convert_floats(f80, f128) -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_d2f(zig_f64); -static inline zig_f32 zig_truncdfsf(zig_f64 arg) { return __aeabi_d2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_f2d(zig_f32); -static inline zig_f64 zig_extendsfdf(zig_f32 arg) { return __aeabi_f2d(arg); } - -#else /* __ARM_EABI__ */ - -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_f32, zig_f32, 2) - -#endif /* __ARM_EABI__ */ - -#define zig_float_negate_builtin_0(w, c, sb) \ - zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, c sb)) -#define zig_float_negate_builtin_1(w, c, sb) -arg -#define zig_float_negate_builtin(w, c, sb) \ +#define zig_float_negate_builtin_0(w, sb) \ + zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, sb)) +#define zig_float_negate_builtin_1(w, sb) -arg +#define zig_float_negate_builtin(w, sb) \ static inline zig_f##w zig_neg_f##w(zig_f##w arg) { \ - return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, c, sb); \ + return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, sb); \ } -zig_float_negate_builtin(16, , UINT16_C(1) << 15 ) -zig_float_negate_builtin(32, , UINT32_C(1) << 31 ) -zig_float_negate_builtin(64, , UINT64_C(1) << 63 ) -zig_float_negate_builtin(80, zig_make_u128, (UINT64_C(1) << 15, UINT64_C(0))) -zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) +zig_float_negate_builtin(16, UINT16_C(1) << 15) +zig_float_negate_builtin(32, UINT32_C(1) << 31) +zig_float_negate_builtin(64, UINT64_C(1) << 63) + +#undef zig_float_negate_builtin_0 +#define zig_float_negate_builtin_0(w, sb) \ + zig_make_repr_f##w(zig_mantissa_repr_f##w(arg), zig_xor_u16(zig_exponent_repr_f##w(arg), sb)) +zig_float_negate_builtin(80, UINT16_C(1) << 15) + +#undef zig_float_negate_builtin_0 +#define zig_float_negate_builtin_0(w, sb) \ + zig_make_repr_f##w(zig_xor_u64(zig_hi_repr_f##w(arg), sb), zig_lo_repr_f##w(arg)) +zig_float_negate_builtin(128, UINT64_C(1) << 63) #define zig_float_less_builtin_0(Type, operation) \ - zig_extern int32_t zig_expand_concat(zig_expand_concat(__##operation, \ + zig_extern zig_FloatCompareResult zig_expand_concat(zig_expand_concat(__##operation, \ zig_compiler_rt_abbrev_zig_##Type), 2)(zig_##Type, zig_##Type); \ static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \ + return (int32_t)zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \ } #define zig_float_less_builtin_1(Type, operation) \ static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ @@ -3994,13 +6077,52 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) return lhs operator rhs; \ } +#define zig_float_builtins(w) \ + zig_common_float_builtins(w) \ + zig_convert_float(f##w, zig_f##w, float, int128, zig_i128, ) \ + zig_convert_float(f##w, zig_f##w, floatun, int128, zig_u128, ) #define zig_common_float_builtins(w) \ - zig_convert_builtin( int64_t, int64_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_i128, zig_i128, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_u128, zig_u128, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int64_t, int64_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, zig_i128, zig_i128, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, zig_u128, zig_u128, ) \ + zig_convert_float(always, int32_t, fix, f##w, zig_f##w, ) \ + zig_convert_float(always, int64_t, fix, f##w, zig_f##w, ) \ + zig_convert_float(int128, zig_i128, fix, f##w, zig_f##w, ) \ + zig_convert_float(always, uint32_t, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(always, uint64_t, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(int128, zig_u128, fixuns, f##w, zig_f##w, ) \ + zig_convert_float(f##w, zig_f##w, float, always, int32_t, ) \ + zig_convert_float(f##w, zig_f##w, float, always, int64_t, ) \ + zig_convert_float(f##w, zig_f##w, floatun, always, uint32_t, ) \ + zig_convert_float(f##w, zig_f##w, floatun, always, uint64_t, ) \ +\ + static inline void zig_expand_concat(zig_expand_concat(zig_fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(void *res, zig_f##w arg, uint16_t bits) { \ + zig_extern void zig_expand_concat(zig_expand_concat(__fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(uint8_t *res, uintptr_t bits, zig_f##w arg); \ + zig_expand_concat(zig_expand_concat(__fix, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(res, bits, arg); \ + } \ +\ + static inline void zig_expand_concat(zig_expand_concat(zig_fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(void *res, zig_f##w arg, uint16_t bits) { \ + zig_extern void zig_expand_concat(zig_expand_concat(__fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(uint8_t *res, uintptr_t bits, zig_f##w arg); \ + zig_expand_concat(zig_expand_concat(__fixuns, \ + zig_compiler_rt_abbrev_zig_f##w), ei)(res, bits, arg); \ + } \ +\ + static inline zig_f##w zig_expand_concat(zig_floatei, \ + zig_compiler_rt_abbrev_zig_f##w)(void *res, uint16_t bits) { \ + zig_extern zig_f##w zig_expand_concat(__floatei, \ + zig_compiler_rt_abbrev_zig_f##w)(const uint8_t *arg, uintptr_t bits); \ + return zig_expand_concat(__floatei, zig_compiler_rt_abbrev_zig_f##w)(res, bits); \ + } \ +\ + static inline zig_f##w zig_expand_concat(zig_floatunei, \ + zig_compiler_rt_abbrev_zig_f##w)(void *res, uint16_t bits) { \ + zig_extern zig_f##w zig_expand_concat(__floatunei, \ + zig_compiler_rt_abbrev_zig_f##w)(const uint8_t *arg, uintptr_t bits); \ + return zig_expand_concat(__floatunei, zig_compiler_rt_abbrev_zig_f##w)(res, bits); \ + } \ +\ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, cmp) \ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, ne) \ zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, eq) \ @@ -4031,82 +6153,48 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmax)))(zig_f##w, zig_max_f##w, zig_libc_name_f##w(fmax), (zig_f##w x, zig_f##w y), (x, y)) \ zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fma)))(zig_f##w, zig_fma_f##w, zig_libc_name_f##w(fma), (zig_f##w x, zig_f##w y, zig_f##w z), (x, y, z)) \ \ - static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divTrunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_trunc_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ - static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divFloor_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_floor_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ - static inline zig_f##w zig_div_ceil_f##w(zig_f##w lhs, zig_f##w rhs) { \ + static inline zig_f##w zig_divCeil_f##w(zig_f##w lhs, zig_f##w rhs) { \ return zig_ceil_f##w(zig_div_f##w(lhs, rhs)); \ } \ \ static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ - return zig_sub_f##w(lhs, zig_mul_f##w(zig_div_floor_f##w(lhs, rhs), rhs)); \ + return zig_sub_f##w(lhs, zig_mul_f##w(zig_divFloor_f##w(lhs, rhs), rhs)); \ } -zig_common_float_builtins(16) -zig_common_float_builtins(32) -zig_common_float_builtins(64) -zig_common_float_builtins(80) -zig_common_float_builtins(128) - -#define zig_float_builtins(w) \ - zig_convert_builtin( int32_t, int32_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint32_t, uint32_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint64_t, uint64_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int32_t, int32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint32_t, uint32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint64_t, uint64_t, ) zig_float_builtins(16) -zig_float_builtins(80) -zig_float_builtins(128) - -#ifdef __ARM_EABI__ - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_f2iz(zig_f32); -static inline int32_t zig_fixsfsi(zig_f32 arg) { return __aeabi_f2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_f2uiz(zig_f32); -static inline uint32_t zig_fixunssfsi(zig_f32 arg) { return __aeabi_f2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_f2ulz(zig_f32); -static inline uint64_t zig_fixunssfdi(zig_f32 arg) { return __aeabi_f2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_i2f(int32_t); -static inline zig_f32 zig_floatsisf(int32_t arg) { return __aeabi_i2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ui2f(uint32_t); -static inline zig_f32 zig_floatunsisf(uint32_t arg) { return __aeabi_ui2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ul2f(uint64_t); -static inline zig_f32 zig_floatundisf(uint64_t arg) { return __aeabi_ul2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_d2iz(zig_f64); -static inline int32_t zig_fixdfsi(zig_f64 arg) { return __aeabi_d2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_d2uiz(zig_f64); -static inline uint32_t zig_fixunsdfsi(zig_f64 arg) { return __aeabi_d2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_d2ulz(zig_f64); -static inline uint64_t zig_fixunsdfdi(zig_f64 arg) { return __aeabi_d2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_i2d(int32_t); -static inline zig_f64 zig_floatsidf(int32_t arg) { return __aeabi_i2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ui2d(uint32_t); -static inline zig_f64 zig_floatunsidf(uint32_t arg) { return __aeabi_ui2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ul2d(uint64_t); -static inline zig_f64 zig_floatundidf(uint64_t arg) { return __aeabi_ul2d(arg); } - -#else /* __ARM_EABI__ */ - zig_float_builtins(32) zig_float_builtins(64) - -#endif /* __ARM_EABI__ */ +zig_float_builtins(80) +#if defined(zig_x86_32) +zig_common_float_builtins(128) +static inline zig_f128 zig_floattitf(zig_i128 arg) { + extern zig_f128 __floattitf(zig_f128 arg); + return __floattitf(zig_f128_bitCast_i128(arg)); +} +static inline zig_f128 zig_floatuntitf(zig_u128 arg) { + extern zig_f128 __floatuntitf(zig_f128 arg); + return __floatuntitf(zig_f128_bitCast_u128(arg)); +} +#elif defined(zig_x86_64) && defined(zig_windows) +zig_common_float_builtins(128) +static inline zig_f128 zig_floattitf(zig_i128 arg) { + extern zig_f128 __floattitf(zig_i128 arg); + return __floattitf(arg); +} +static inline zig_f128 zig_floatuntitf(zig_u128 arg) { + extern zig_f128 __floatuntitf(uint64_t arg_lo, uint64_t arg_hi); + return __floatuntitf(zig_lo_u128(arg), zig_hi_u128(arg)); +} +#else +zig_float_builtins(128) +#endif /* ============================ Atomics Support ============================= */ @@ -4410,19 +6498,19 @@ typedef int zig_memory_order; } \ static inline void zig_msvc_atomic_store_##ZigType(Type volatile* obj, Type value) { \ (void)_InterlockedExchange##suffix((SigType volatile*)obj, (SigType)value); \ - } \ + } \ static inline Type zig_msvc_atomic_load_zig_memory_order_relaxed_##ZigType(Type volatile* obj) { \ return __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ } \ static inline Type zig_msvc_atomic_load_zig_memory_order_acquire_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ + Type value = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - return val; \ + return value; \ } \ static inline Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ + Type value = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - return val; \ + return value; \ } zig_msvc_atomics( u8, uint8_t, char, 8, 8) @@ -4465,14 +6553,14 @@ zig_msvc_atomics(i64, int64_t, __int64, 64, 64) zig_##Type result; \ SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ + memcpy(&result, &initial, sizeof(result)); \ return result; \ } \ static inline zig_##Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##Type(zig_##Type volatile* obj) { \ zig_##Type result; \ SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ + memcpy(&result, &initial, sizeof(result)); \ return result; \ } @@ -4502,9 +6590,9 @@ static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p32(void volat } static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p32(void volatile* obj) { - void* val = (void*)__iso_volatile_load32(obj); + void* value = (void*)__iso_volatile_load32(obj); _ReadWriteBarrier(); - return val; + return value; } static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p32(void volatile* obj) { @@ -4532,9 +6620,9 @@ static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p64(void volat } static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p64(void volatile* obj) { - void* val = (void*)__iso_volatile_load64(obj); + void* value = (void*)__iso_volatile_load64(obj); _ReadWriteBarrier(); - return val; + return value; } static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p64(void volatile* obj) { diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index 1664bd4095df86103a6e4bacfc682054a0cb8fc1..8587696fd79e5f385e8ea9fcf56614213bcce485 100644 Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ diff --git a/test/behavior/abs.zig b/test/behavior/abs.zig index 895f9bbf8d956e61bdf5455084cd4d58ebd2b1e9..9c140d35499fe43c6dfb1b5309e4dbd8bd7263c0 100644 --- a/test/behavior/abs.zig +++ b/test/behavior/abs.zig @@ -144,7 +144,6 @@ test "@abs big int <= 128 bits" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try comptime testAbsSignedBigInt(); try testAbsSignedBigInt(); @@ -256,7 +255,6 @@ fn testAbsFloats(comptime T: type) !void { test "@abs int vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 9ffb238dfdb9994bf587b7e4e4b5743842dbcc4c..c9294e953b8d2c907a8b86e2c6b5916b1d75941a 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -129,8 +129,7 @@ test "alignment and size of structs with 128-bit fields" { y: u8, }; const expected = switch (builtin.cpu.arch) { - .s390x, - => .{ + .s390x => .{ .a_align = 8, .a_size = 16, @@ -142,7 +141,32 @@ test "alignment and size of structs with 128-bit fields" { .u129_align = 8, .u129_size = 24, }, + .x86 => switch (builtin.os.tag) { + else => .{ + .a_align = 4, + .a_size = 16, + .b_align = 4, + .b_size = 20, + + .u128_align = 4, + .u128_size = 16, + .u129_align = 4, + .u129_size = 20, + }, + .uefi, .windows => .{ + .a_align = 8, + .a_size = 16, + + .b_align = 8, + .b_size = 24, + + .u128_align = 8, + .u128_size = 16, + .u129_align = 8, + .u129_size = 24, + }, + }, .amdgcn, .arm, .armeb, @@ -155,12 +179,13 @@ test "alignment and size of structs with 128-bit fields" { .powerpc, .powerpcle, .riscv32, + .sparc, => .{ .a_align = 8, .a_size = 16, - .b_align = 16, - .b_size = 32, + .b_align = 8, + .b_size = 24, .u128_align = 8, .u128_size = 16, @@ -178,12 +203,10 @@ test "alignment and size of structs with 128-bit fields" { .nvptx64, .powerpc64, .powerpc64le, - .sparc, .sparc64, .riscv64, .wasm32, .wasm64, - .x86, .x86_64, => .{ .a_align = 16, @@ -200,12 +223,11 @@ test "alignment and size of structs with 128-bit fields" { else => return error.SkipZigTest, }; - const min_struct_align = if (builtin.zig_backend == .stage2_c) if (builtin.cpu.arch == .s390x) 8 else 16 else 0; comptime { - assert(@alignOf(A) == @max(expected.a_align, min_struct_align)); + assert(@alignOf(A) == expected.a_align); assert(@sizeOf(A) == expected.a_size); - assert(@alignOf(B) == @max(expected.b_align, min_struct_align)); + assert(@alignOf(B) == expected.b_align); assert(@sizeOf(B) == expected.b_size); assert(@alignOf(u128) == expected.u128_align); @@ -547,8 +569,6 @@ test "sub-aligned pointer field access" { } test "alignment of zero-bit types is respected" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO @@ -582,7 +602,6 @@ test "zero-bit fields in extern struct pad fields appropriately" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const S = extern struct { x: u8, diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 16fdfc8c15cbd9f5e9ad3cc11d72461092cf839c..42c85b0487e2d024adf394300c165feaa126d325 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -797,10 +797,8 @@ test "auto created variables have correct alignment" { } test "extern variable with non-pointer opaque type" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO @export(&var_to_export, .{ .name = "opaque_extern_var" }); @@ -1398,7 +1396,6 @@ test "allocation and looping over 3-byte integer" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag.isDarwin()) return error.SkipZigTest; // TODO try expect(@sizeOf(u24) == 4); try expect(@sizeOf([1]u24) == 4); diff --git a/test/behavior/bit_shifting.zig b/test/behavior/bit_shifting.zig index 9eed252ac8ddc055038a0bf227616f3df49369bd..a9d81b6b53e6d1761e99234200fdcc155e2efa1f 100644 --- a/test/behavior/bit_shifting.zig +++ b/test/behavior/bit_shifting.zig @@ -147,7 +147,6 @@ test "Saturating Shift Left where lhs is of a computed type" { test "Saturating Shift Left" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index b3b64af19b9d99ed922ec087209d02ecab14354a..d790d68416add0ba62603eaabaa691d1bdfe9c32 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -210,7 +210,6 @@ test "triple level result location with bitcast sandwich passed as tuple element test "@bitCast packed struct of floats" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -247,7 +246,6 @@ test "@bitCast packed struct of floats" { test "comptime @bitCast packed struct to int and back" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -283,7 +281,6 @@ test "comptime @bitCast packed struct to int and back" { test "bitcast vector to integer and back" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -329,10 +326,10 @@ fn bitCastWrapper128(x: f128) u128 { } test "bitcast nan float does not modify signaling bit" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const snan_u16: u16 = 0x7D00; const snan_u32: u32 = 0x7FA00000; @@ -383,7 +380,6 @@ test "bitcast nan float does not modify signaling bit" { test "@bitCast of packed struct of bools all true" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO @@ -404,7 +400,6 @@ test "@bitCast of packed struct of bools all true" { test "@bitCast of packed struct of bools all false" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO const P = packed struct { @@ -437,6 +432,22 @@ test "@bitCast of packed struct with void field to integer" { try comptime S.doTheTest(123); } +test "@bitCast of packed struct with void field and multiple integers" { + const S = packed struct { + x: u8, + v: void, + y: u8, + + fn doTheTest(x: u8, y: u8) !void { + const foo = @as(@This(), .{ .x = x, .v = {}, .y = y }); + const as_int: u16 = @bitCast(foo); + try expect(as_int == @as(u16, y) << 8 | x); + } + }; + try S.doTheTest(123, 45); + try comptime S.doTheTest(123, 45); +} + test "@bitCast vector to array with different element size" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/builtin_functions_returning_void_or_noreturn.zig b/test/behavior/builtin_functions_returning_void_or_noreturn.zig index cd3bc58de61600a0ad57d745355b5b707b4e5322..820a920464c77e42b6130b5d96838d7eda7a3d9a 100644 --- a/test/behavior/builtin_functions_returning_void_or_noreturn.zig +++ b/test/behavior/builtin_functions_returning_void_or_noreturn.zig @@ -6,7 +6,6 @@ var x: u8 = 1; // This excludes builtin functions that return void or noreturn that cannot be tested. test { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/call.zig b/test/behavior/call.zig index 94e19e723d60cb8cdf2f5cfc1aaa7306ec7bbd81..5f2b24b6b72eadd8dfffa6998ee996e292ed381c 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -21,7 +21,6 @@ test "super basic invocations" { test "basic invocations" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 192afbe68d030d894827f1b0caa642ba8f79ff0c..2a79566b74f6fad214b6324ff3e41b5ae087ae6d 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -120,6 +120,7 @@ test "@floatFromInt" { try expect(@as(i32, @floor(f)) == k); try expect(@as(i32, @ceil(f)) == k); try expect(@as(i32, @trunc(f)) == k); + try expect(@as(i32, @trunc(@floor(f))) == k); } }; try S.doTheTest(); @@ -134,7 +135,6 @@ test "@intFromFloat > 128 bits" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testIntFromFloat(f16, 1024, u140, 1024); try testIntFromFloat(f16, -1024, i140, -1024); @@ -160,7 +160,6 @@ test "@floatFromInt > 128 bits" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testFloatFromInt(u140, 1024, f16, 1024); try testFloatFromInt(i140, -1024, f16, -1024); @@ -182,8 +181,8 @@ test "@floatFromInt(f80)" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; const S = struct { fn doTheTest(comptime Int: type) !void { @@ -199,6 +198,7 @@ test "@floatFromInt(f80)" { try expect(@as(Int, @floor(f)) == k); try expect(@as(Int, @ceil(f)) == k); try expect(@as(Int, @trunc(f)) == k); + try expect(@as(Int, @trunc(@floor(f))) == k); } }; try S.doTheTest(i31); @@ -207,7 +207,7 @@ test "@floatFromInt(f80)" { try S.doTheTest(i64); try S.doTheTest(i80); try S.doTheTest(i128); - // try S.doTheTest(i256); // TODO missing compiler_rt symbols + try S.doTheTest(i256); try comptime S.doTheTest(i31); try comptime S.doTheTest(i32); try comptime S.doTheTest(i45); @@ -281,6 +281,7 @@ test "type coercion from int to float" { test "@intFromFloat" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + try testIntFromFloats(); try comptime testIntFromFloats(); } @@ -498,7 +499,7 @@ test "array coercion to undefined at runtime" { @setRuntimeSafety(true); - if (builtin.mode != .Debug and builtin.mode != .ReleaseSafe) { + if (builtin.mode != .debug and builtin.mode != .safe) { return error.SkipZigTest; } @@ -1473,11 +1474,6 @@ fn foobar(func: PFN_void) !void { test "cast function with an opaque parameter" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) { - // https://github.com/ziglang/zig/issues/16845 - return error.SkipZigTest; - } - const Container = struct { const Ctx = opaque {}; ctx: *Ctx, @@ -1724,9 +1720,7 @@ test "cast f16 to wider types" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1831,21 +1825,15 @@ test "pointer to empty struct literal to mutable slice" { test "coerce between pointers of compatible differently-named floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12396 - return error.SkipZigTest; - } - const F = switch (@typeInfo(c_longdouble).float.bits) { 64 => f64, 80 => f80, 128 => f128, - else => @compileError("unreachable"), + else => comptime unreachable, }; var f1: F = 12.34; const f2: *c_longdouble = &f1; diff --git a/test/behavior/cast_int.zig b/test/behavior/cast_int.zig index 34adedf7267030379ee573cb519ce6dbe29c95e3..50a1b74d8ab76bdccf8b04795a04ca77bdee078b 100644 --- a/test/behavior/cast_int.zig +++ b/test/behavior/cast_int.zig @@ -168,7 +168,6 @@ test "@intCast <= 64 bits" { test "@intCast > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testIntCast(u8, 123, u140, 123); diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 60a06886d45ac988b55d0a51f5bc40101f098e7e..f86ab963d2a4ea5dd0cec5493f583ac672a174e7 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -513,7 +513,6 @@ test "runtime 128 bit integer division" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u128 = 152313999999999991610955792383; diff --git a/test/behavior/export_builtin.zig b/test/behavior/export_builtin.zig index 16fc0a7a79c20795b81abf4282c00cf7e1c54258..0381e9645488d4565a56c16630c9e937e152df61 100644 --- a/test/behavior/export_builtin.zig +++ b/test/behavior/export_builtin.zig @@ -5,11 +5,6 @@ const expect = std.testing.expect; test "exporting enum value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.cpu.arch.isWasm()) { - // https://github.com/ziglang/zig/issues/4866 - return error.SkipZigTest; - } - const S = struct { const E = enum(c_int) { one, two }; const e: E = .two; @@ -35,11 +30,6 @@ test "exporting with internal linkage" { test "exporting using namespace access" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.cpu.arch.isWasm()) { - // https://github.com/ziglang/zig/issues/4866 - return error.SkipZigTest; - } - const S = struct { const Inner = struct { const x: u32 = 5; @@ -57,11 +47,6 @@ test "exporting comptime-known value" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.cpu.arch.isWasm()) { - // https://github.com/ziglang/zig/issues/4866 - return error.SkipZigTest; - } - const x: u32 = 10; @export(&x, .{ .name = "exporting_comptime_known_value_foo" }); const S = struct { diff --git a/test/behavior/extern.zig b/test/behavior/extern.zig index 4de68589468790419a9e993fd68caf2f20e6eae9..ed95406aa889d361abbf87a79764eb23d62021ca 100644 --- a/test/behavior/extern.zig +++ b/test/behavior/extern.zig @@ -3,7 +3,6 @@ const std = @import("std"); const expect = std.testing.expect; test "anyopaque extern symbol" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/field_parent_ptr.zig b/test/behavior/field_parent_ptr.zig index 85250c54ad7d083be1a2f132b7fdc0a2785e10b2..8694f366a586cd4a756f7f1acb7862c656b04f02 100644 --- a/test/behavior/field_parent_ptr.zig +++ b/test/behavior/field_parent_ptr.zig @@ -586,7 +586,6 @@ test "@fieldParentPtr extern struct last zero-bit field" { } test "@fieldParentPtr unaligned packed struct" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -725,7 +724,6 @@ test "@fieldParentPtr unaligned packed struct" { } test "@fieldParentPtr aligned packed struct" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -1897,7 +1895,6 @@ test "@fieldParentPtr packed union" { } test "@fieldParentPtr tagged union all zero-bit fields" { - if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 780ed846d34a1f4cc45f6fa40467b97e93a2cdb0..73a1d8c4d4ad0e1e125fc89a40ada8286d8dfb20 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -118,7 +118,6 @@ fn testMul(comptime T: type) !void { test "cmp f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 try testCmp(f16); try comptime testCmp(f16); @@ -127,7 +126,6 @@ test "cmp f16" { test "cmp f32" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 try testCmp(f32); try comptime testCmp(f32); @@ -142,7 +140,6 @@ test "cmp f64" { test "cmp f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -152,7 +149,6 @@ test "cmp f128" { test "cmp f80/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -220,7 +216,6 @@ test "vector cmp f16" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; try testCmpVector(f16); @@ -233,7 +228,7 @@ test "vector cmp f32" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isArm()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/214198 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; try testCmpVector(f32); @@ -253,10 +248,9 @@ test "vector cmp f64" { test "vector cmp f128" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .powerpc64le) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/214198 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; try testCmpVector(f128); @@ -266,7 +260,7 @@ test "vector cmp f128" { test "vector cmp f80/c_longdouble" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .powerpc64le) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/214198 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -381,11 +375,7 @@ test "@sqrt f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - - if (builtin.os.tag == .freebsd) { - // TODO https://github.com/ziglang/zig/issues/10875 - return error.SkipZigTest; - } + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; try testSqrt(f80); try comptime testSqrt(f80); @@ -431,9 +421,9 @@ fn testSqrt(comptime T: type) !void { var inf: T = math.inf(T); try expect(math.isPositiveInf(@sqrt(inf))); var zero: T = 0.0; - try expect(@sqrt(zero) == 0.0); + try expect(math.isPositiveZero(@sqrt(zero))); var neg_zero: T = -0.0; - try expect(@sqrt(neg_zero) == 0.0); + try expect(math.isNegativeZero(@sqrt(neg_zero))); var neg_one: T = -1.0; try expect(math.isNan(@sqrt(neg_one))); var nan: T = math.nan(T); @@ -947,7 +937,7 @@ test "@log2 with vectors" { builtin.cpu.arch == .aarch64 and builtin.os.tag == .windows) return error.SkipZigTest; - if (builtin.os.tag == .windows and builtin.cpu.arch == .x86) { + if (builtin.os.tag == .windows and builtin.cpu.arch == .x86 and builtin.abi == .msvc) { // https://codeberg.org/ziglang/zig/issues/35518 return error.SkipZigTest; } @@ -1054,7 +1044,6 @@ test "@abs f32/f64" { test "@abs f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -1172,16 +1161,10 @@ test "@floor f32/f64" { test "@floor f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - try testFloor(f80); try comptime testFloor(f80); try testFloor(f128); @@ -1261,16 +1244,10 @@ test "@ceil f32/f64" { test "@ceil f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - try testCeil(f80); try comptime testCeil(f80); try testCeil(f128); @@ -1281,16 +1258,10 @@ test "@ceil f80/f128/c_longdouble" { test "@ceil f80 maxInt(u64)" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - var x: u64 = std.math.maxInt(u64); x = x; const float: f80 = @floatFromInt(x); @@ -1368,16 +1339,10 @@ test "@trunc f32/f64" { test "@trunc f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - try testTrunc(f80); try comptime testTrunc(f80); try testTrunc(f128); @@ -1440,11 +1405,6 @@ test "neg f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.os.tag == .freebsd) { - // TODO file issue to track this failure - return error.SkipZigTest; - } - try testNeg(f16); try comptime testNeg(f16); } @@ -1501,9 +1461,9 @@ fn testNeg(comptime T: type) !void { // subnormals var zero: T = 0.0; - try expect(-zero == -0.0); + try expect(math.isNegativeZero(-zero)); var neg_zero: T = -0.0; - try expect(-neg_zero == 0.0); + try expect(math.isPositiveZero(-neg_zero)); var true_min: T = math.floatTrueMin(T); try expect(-true_min == -math.floatTrueMin(T)); var neg_true_min: T = -math.floatTrueMin(T); @@ -1678,7 +1638,7 @@ test "runtime isNan(inf * 0)" { test "optimized float mode" { if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; - if (builtin.mode == .Debug) return error.SkipZigTest; + if (builtin.mode == .debug) return error.SkipZigTest; const big = 0x1p40; const small = 0.001; diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 14cb20f5442a452695ccad2134bd4d0c306ab4b2..69b32ca20271f8bbdf660eb5cc8039c6e0a5bfb1 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -147,7 +147,6 @@ fn fnWithUnreachable() noreturn { test "extern struct with stdcallcc fn pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .x86) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = extern struct { @@ -419,7 +418,6 @@ test "import passed byref to function in return type" { test "implicit cast function to function ptr" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S1 = struct { diff --git a/test/behavior/int128.zig b/test/behavior/int128.zig index ce69d80522516c71cc586b84bb3784f0ba9c75e6..f02aed4f90c68d6676404aed8e728b2b9a4916ba 100644 --- a/test/behavior/int128.zig +++ b/test/behavior/int128.zig @@ -31,7 +31,7 @@ test "undefined 128 bit int" { @setRuntimeSafety(true); // TODO implement @setRuntimeSafety - if (builtin.mode != .Debug and builtin.mode != .ReleaseSafe) { + if (builtin.mode != .debug and builtin.mode != .safe) { return error.SkipZigTest; } diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 22b91be640579e1e8fe460f4652f998c5c1b9b6d..e76ca9850f3ce2bc9ca356910e76407dfae07fb1 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -873,7 +873,6 @@ test "umax wrapped squaring" { test "128-bit multiplication" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { @@ -968,7 +967,6 @@ test "@addWithOverflow > 128 bits" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.target.abi == .msvc) return error.SkipZigTest; try testAddWithOverflow(u129, 4, 105, 109, 0); try testAddWithOverflow(u129, 1000, 100, 1100, 0); @@ -1136,7 +1134,6 @@ test "Multiply unwrap error * immediate" { test "@mulWithOverflow bitsize 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1163,7 +1160,6 @@ test "@mulWithOverflow bitsize 128 bits" { test "@mulWithOverflow > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testMulWithOverflow(u140, 0, maxInt(u140), 0, 0); @@ -1193,7 +1189,6 @@ test "@mulWithOverflow > 128 bits" { test "@mulWithOverflow bitsize 256 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -1298,7 +1293,6 @@ test "@subWithOverflow > 128 bits" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.target.abi == .msvc) return error.SkipZigTest; try testSubWithOverflow(u129, 4, 105, maxInt(u129) - 100, 1); try testSubWithOverflow(u129, 1000, 100, 900, 0); @@ -1389,7 +1383,6 @@ test "@shlWithOverflow > 64 bits" { test "@shlWithOverflow > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testShlWithOverflow(u140, 1 << 100, 20, 1 << 120, 0); @@ -1419,7 +1412,6 @@ fn testAnd(comptime T: type, a: T, b: T, expected: T) !void { test "and > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testAnd(u140, (1 << 139) | (1 << 70) | 0xaa, (1 << 139) | (1 << 69) | 0xcc, (1 << 139) | 0x88); try testAnd(u140, maxInt(u140), 1 << 100, 1 << 100); @@ -1448,7 +1440,6 @@ fn testOr(comptime T: type, a: T, b: T, expected: T) !void { test "or > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testOr(u140, 0, 1 << 139, 1 << 139); try testOr(u140, (1 << 70) | 0xa, (1 << 69) | 0x5, (1 << 70) | (1 << 69) | 0xf); @@ -1477,7 +1468,6 @@ fn testXor(comptime T: type, a: T, b: T, expected: T) !void { test "xor > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testXor(u140, 0, maxInt(u140), maxInt(u140)); try testXor(u140, 1 << 139, 1 << 139, 0); @@ -1506,7 +1496,6 @@ fn testNot(comptime T: type, a: T, expected: T) !void { test "not > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testNot(u140, 0, maxInt(u140)); try testNot(u140, maxInt(u140), 0); @@ -1535,7 +1524,6 @@ fn testShl(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void { test "shl > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testShl(u140, 1 << 5, 10, 1 << 15); try testShl(u140, 3, 138, (1 << 139) | (1 << 138)); @@ -1564,7 +1552,6 @@ fn testShr(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void { test "shr > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testShr(u140, 1 << 139, 39, 1 << 100); try testShr(u140, (1 << 70) | 8, 3, (1 << 67) | 1); @@ -1593,7 +1580,6 @@ fn testClz(comptime T: type, a: T, expected: u16) !void { test "@clz > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testClz(u140, 0, 140); @@ -1623,7 +1609,6 @@ fn testCtz(comptime T: type, a: T, expected: u16) !void { test "@ctz > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testCtz(u140, 0, 140); @@ -1653,7 +1638,6 @@ fn testPopCount(comptime T: type, a: T, expected: u16) !void { test "@popCount > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testPopCount(u140, 0, 0); @@ -1683,7 +1667,6 @@ fn testBitReverse(comptime T: type, a: T, expected: T) !void { test "@bitReverse > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testBitReverse(u140, 1 << 139, 1); @@ -1713,7 +1696,6 @@ fn testByteSwap(comptime T: type, a: T, expected: T) !void { test "@byteSwap > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testByteSwap(u144, 1 << 136, 1); @@ -1743,7 +1725,6 @@ fn testMax(comptime T: type, a: T, b: T, expected: T) !void { test "@max > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testMax(u140, 0, maxInt(u140), maxInt(u140)); @@ -1773,7 +1754,6 @@ fn testMin(comptime T: type, a: T, b: T, expected: T) !void { test "@min > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testMin(u140, 0, maxInt(u140), 0); @@ -1803,7 +1783,6 @@ fn testAbs(comptime T: type, a: T, expected: anytype) !void { test "@abs > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testAbs(u140, 0, 0); try testAbs(u140, 1 << 139, 1 << 139); @@ -1827,7 +1806,6 @@ fn testRem(comptime T: type, numerator: T, denominator: T, expected: T) !void { test "@rem > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testRem(u140, 0, maxInt(u140), 0); @@ -1855,7 +1833,6 @@ fn testMod(comptime T: type, numerator: T, denominator: T, expected: T) !void { test "@mod > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testMod(u140, 0, maxInt(u140), 0); @@ -1883,7 +1860,6 @@ fn testDivFloor(comptime T: type, numerator: T, denominator: T, expected: T) !vo test "@divFloor > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testDivFloor(u140, 0, maxInt(u140), 0); @@ -1912,7 +1888,6 @@ fn testDivCeil(comptime T: type, numerator: T, denominator: T, expected: T) !voi test "@divCeil > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testDivCeil(u140, 0, maxInt(u140), 0); @@ -1941,7 +1916,6 @@ fn testDivTrunc(comptime T: type, numerator: T, denominator: T, expected: T) !vo test "@divTrunc > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testDivTrunc(u140, 0, maxInt(u140), 0); @@ -2166,14 +2140,8 @@ test "remainder division" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { - // https://github.com/ziglang/zig/issues/12602 - return error.SkipZigTest; - } - if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest; try comptime remdiv(f16); @@ -2315,7 +2283,6 @@ test "@round f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testRound(f80, 12.0); @@ -2326,7 +2293,6 @@ test "@round f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testRound(f128, 12.0); @@ -2366,7 +2332,6 @@ test "NaN comparison" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 try testNanEqNan(f16); try testNanEqNan(f32); diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index 22db5a75502f8456ac0637ef134a137434d3da75..533f44869573a924e50a08b3806a03c4243fc7ee 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -115,7 +115,6 @@ test "@min/max for floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index 086a325bd6246dd660641aec924c20339494f8a2..bde6459e849c14384d69fc57811f59b747a0f2de 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -49,7 +49,6 @@ test "@mulAdd f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testMulAdd80(); @@ -68,7 +67,6 @@ test "@mulAdd f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testMulAdd128(); @@ -169,7 +167,6 @@ test "vector f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector80(); @@ -194,7 +191,6 @@ test "vector f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector128(); diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 96585d056cdf4c13b1aff3610ad08088fc0bf61c..045c19767454b64d970fe6c7a46dafcb9b2a1ac4 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -404,7 +404,6 @@ test "nested packed struct field pointers" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // ubsan unaligned pointer access if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO const S2 = packed struct { base: u8, @@ -579,7 +578,6 @@ test "packed struct fields modification" { } test "nested packed struct field access test" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -733,7 +731,6 @@ test "nested packed struct at non-zero offset 2" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { @@ -1171,7 +1168,6 @@ test "packed struct equality" { test "packed struct equality ignores padding bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = packed struct { b: bool }; diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index 9ac875fad4990e03554fc217fb38f42d0dfa6e62..807f4f5450d3fb372e18e2fc78f71fea9ce4d5bb 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -275,7 +275,7 @@ test "compare equality of optional and non-optional pointer" { } test "allowzero pointer and slice" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/saturating_arithmetic.zig b/test/behavior/saturating_arithmetic.zig index c434f014f36e40f2cfea9fc0c2508320d09c74a4..c5fa221c124d4113a73db22ab33778e521a9c52a 100644 --- a/test/behavior/saturating_arithmetic.zig +++ b/test/behavior/saturating_arithmetic.zig @@ -144,7 +144,6 @@ test "saturating multiplication <= 32 bits" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSatMul(u8, 0, maxInt(u8), 0); @@ -238,7 +237,6 @@ test "saturating multiplication" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { @@ -313,7 +311,6 @@ test "saturating shift-left" { test "saturating shift-left large rhs" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; @@ -361,7 +358,6 @@ test "saturating shl uses the LHS type" { test "sat add > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testSatAdd(u140, 0, 0, 0); @@ -377,7 +373,6 @@ test "sat add > 128 bits" { test "sat sub > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testSatSub(u140, 0, 1, 0); @@ -393,7 +388,6 @@ test "sat sub > 128 bits" { test "sat mul > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testSatMul(u140, 0, maxInt(u140), 0); @@ -409,7 +403,6 @@ test "sat mul > 128 bits" { test "sat shl > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testSatShl(u140, 0, u8, 17, 0); diff --git a/test/behavior/select.zig b/test/behavior/select.zig index f3a8eda1416e62e69db9e5d4c620c77df8070e20..0bac089d7be2db12da742b2b45b8141075805e38 100644 --- a/test/behavior/select.zig +++ b/test/behavior/select.zig @@ -31,6 +31,20 @@ fn selectVectors() !void { _ = .{ &x, &y, &z }; const xyz = @select(f32, x, y, z); try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 })); + + var vec_u0: @Vector(4, u0) = @splat(0); + var mask_u0 = @Vector(4, bool){ true, false, true, false }; + var mask_empty = @Vector(0, i32){}; + var vec_empty = @Vector(0, i32){}; + _ = .{ &vec_u0, &mask_u0, &mask_empty, &vec_empty }; + const sel_u0 = @select(u0, mask_u0, vec_u0, vec_u0); + const sel_u0_undefined = @select(u0, mask_u0, undefined, undefined); + comptime if (sel_u0[0] != 0) unreachable; + comptime if (sel_u0_undefined[1] != 0) unreachable; + const sel_empty = @select(i32, mask_empty, vec_empty, vec_empty); + const sel_empty_undefined = @select(i32, @Vector(0, bool){}, undefined, undefined); + comptime if (@as(u0, @bitCast(sel_empty)) != 0) unreachable; + comptime if (@as(u0, @bitCast(sel_empty_undefined)) != 0) unreachable; } test "@select arrays" { diff --git a/test/behavior/shuffle.zig b/test/behavior/shuffle.zig index 871852111025055a87858b65656ad15dc27062fe..e61e8f17a8d940c94b054228894bf6d799aa4c8d 100644 --- a/test/behavior/shuffle.zig +++ b/test/behavior/shuffle.zig @@ -170,3 +170,23 @@ test "@shuffle bool 2" { try S.doTheTest(); try comptime S.doTheTest(); } + +test "@shuffle u0" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const S = struct { + fn doTheTest() !void { + var v: @Vector(4, u0) = @splat(0); + const mask = @Vector(4, i32){ undefined, 0, -1, 3 }; + _ = .{ &v, &mask }; + const res = @shuffle(u0, v, v, mask); + comptime if (!std.mem.eql(u0, &@as([4]u0, res), &[4]u0{ 0, 0, 0, 0 })) unreachable; + } + }; + try S.doTheTest(); + try comptime S.doTheTest(); +} diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index f1efaa9f43686a0d3570c7e33c335a0f1e6c84e3..247c3d1be8f3a15ab8b53f9d0a47f2bdea02cc4f 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -1089,3 +1089,85 @@ test "slice field alignment" { var arr: [10]u8 = @splat(0); try S.doTheTest(&&arr); } + +test "directly deref slice with comptime-known length" { + { + const slice: []const u16 = &.{ 1, 2, 3 }; + const array = slice.*; + + comptime assert(@TypeOf(array) == [3]u16); + comptime assert(array[0] == 1); + comptime assert(array[1] == 2); + comptime assert(array[2] == 3); + } + { + const slice: [:0]const u16 = &.{ 1, 2, 3 }; + const array = slice.*; + + comptime assert(@TypeOf(array) == [3:0]u16); + comptime assert(array[0] == 1); + comptime assert(array[1] == 2); + comptime assert(array[2] == 3); + comptime assert(array[3] == 0); + } +} + +test "address of dereferenced slice is array pointer" { + { + const slice: []const u16 = &.{ 1, 2, 3 }; + const array_ptr = &slice.*; + + comptime assert(@TypeOf(array_ptr) == *const [3]u16); + comptime assert(array_ptr[0] == 1); + comptime assert(array_ptr[1] == 2); + comptime assert(array_ptr[2] == 3); + } + { + const slice: [:0]const u16 = &.{ 1, 2, 3 }; + const array_ptr = &slice.*; + + comptime assert(@TypeOf(array_ptr) == *const [3:0]u16); + comptime assert(array_ptr[0] == 1); + comptime assert(array_ptr[1] == 2); + comptime assert(array_ptr[2] == 3); + comptime assert(array_ptr[3] == 0); + } +} + +test "coerce slice with comptime-known length to array pointer" { + { + const slice: []const u16 = &.{ 1, 2, 3 }; + const array_ptr: *const [3]u16 = slice; + + comptime assert(array_ptr[0] == 1); + comptime assert(array_ptr[1] == 2); + comptime assert(array_ptr[2] == 3); + } + { + const slice: [:0]const u16 = &.{ 1, 2, 3 }; + const array_ptr: *const [3:0]u16 = slice; + + comptime assert(array_ptr[0] == 1); + comptime assert(array_ptr[1] == 2); + comptime assert(array_ptr[2] == 3); + comptime assert(array_ptr[3] == 0); + } + { + const slice: [:0]const u16 = &.{ 1, 2, 3 }; + const array_ptr: *const [3]u16 = slice; + + comptime assert(array_ptr[0] == 1); + comptime assert(array_ptr[1] == 2); + comptime assert(array_ptr[2] == 3); + } +} + +test "modify slice through coerced array pointer" { + comptime { + var array: [3]u16 = .{ 1, 2, 3 }; + const slice: []u16 = &array; + const array_ptr: *[3]u16 = slice; + array_ptr[2] = 0; + assert(slice[2] == 0); + } +} diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 379e5ec18343c226b0e2d67b1dca8b8d53f13340..2aa7920ab4b17ae56df165a880d3242e3a3fedb0 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -535,7 +535,6 @@ test "zero-bit field in packed struct" { test "packed struct with non-ABI-aligned field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -792,7 +791,6 @@ test "non-packed struct with u128 entry in union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { @@ -1539,7 +1537,6 @@ test "instantiate struct with comptime field" { } test "struct field pointer has correct alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -1569,7 +1566,6 @@ test "struct field pointer has correct alignment" { } test "extern struct field pointer has correct alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -2007,7 +2003,6 @@ test "initiate global variable with runtime value" { } test "struct containing optional pointer to array of @This()" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { @@ -2266,7 +2261,8 @@ test "struct contains aligned pointer to itself through type decl" { test "struct contains underaligned field with overaligned pointer to itself" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + const S = struct { ptr: *align(8) @This() align(1), }; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 6a44290f859261ad1c2f02974eb8525022fc0b25..c5ffdfa3e1872bfa58edb53b414b523660e9a9bb 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -1267,7 +1267,7 @@ test "switch with complex item expressions" { test "switch evaluation order" { const eu: anyerror!u32 = 0; _ = eu catch |err| switch (err) { - if (true) @compileError("unreachable") => unreachable, + if (true) comptime unreachable => unreachable, else => unreachable, }; } diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index 9f4859789c9c3f23488ae0814c67b132112a3335..caaea13e7f8aa3571a0f3f34c7b05b0ee37eea3b 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -223,7 +223,6 @@ test "unanalyzed continue with operand" { test "switch loop on larger than pointer integer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var entry: @Int(.unsigned, @bitSizeOf(usize) + 1) = undefined; @@ -268,7 +267,7 @@ test "switch loop on non-exhaustive enum" { test "switch loop with discarded tag capture" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + const S = struct { const U = union(enum) { a: u32, diff --git a/test/behavior/switch_on_captured_error.zig b/test/behavior/switch_on_captured_error.zig index c4353cd5df381e080489b9b5594df9d356277cc0..a57e93d0d1ca4bd502123b9e13ddcaeb7cbd9b68 100644 --- a/test/behavior/switch_on_captured_error.zig +++ b/test/behavior/switch_on_captured_error.zig @@ -243,7 +243,7 @@ test "switch on error union catch capture" { var a: error{}!u64 = 0; _ = &a; const b = a catch |err| switch (err) { - undefined => @compileError("unreachable"), + undefined => comptime unreachable, }; try expectEqual(@as(u64, 0), b); } @@ -829,7 +829,7 @@ test "switch on error union if else capture" { var a: error{}!u64 = 0; _ = &a; const b = if (a) |x| x else |err| switch (err) { - undefined => @compileError("unreachable"), + undefined => comptime unreachable, }; try expectEqual(@as(u64, 0), b); } @@ -840,7 +840,7 @@ test "switch on error union if else capture" { var a: error{}!u64 = 0; _ = &a; const b = if (a) |*x| x.* else |err| switch (err) { - undefined => @compileError("unreachable"), + undefined => comptime unreachable, }; try expectEqual(@as(u64, 0), b); } diff --git a/test/behavior/threadlocal.zig b/test/behavior/threadlocal.zig index cb4480f759af537ee0824d400fda530eb21a69b7..ec1ce0b62677b9cbb4988814e4c69f94ae65548c 100644 --- a/test/behavior/threadlocal.zig +++ b/test/behavior/threadlocal.zig @@ -9,11 +9,6 @@ test "thread local variable" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag.isDarwin()) { - // Fails due to register hazards. - return error.SkipZigTest; - } - const S = struct { threadlocal var t: i32 = 1234; }; diff --git a/test/behavior/truncate.zig b/test/behavior/truncate.zig index 07d19f29c0da73a045ae58d35836502cbebe5cdc..506a0d2bea99b768c6761cc3da31558b88eddf11 100644 --- a/test/behavior/truncate.zig +++ b/test/behavior/truncate.zig @@ -49,7 +49,6 @@ fn testTruncate(comptime S: type, a: S, comptime D: type, expected: D) !void { test "@truncate > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testTruncate(u140, 0, u128, 0); diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 340f7006e72b7f48ecaf7280cd9cd982f8600060..0ba364aabe557a0bac5832d285cc4595dc9cec25 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1437,7 +1437,6 @@ test "coerce enum literal to union in result loc" { } test "defined-layout union field pointer has correct alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -1472,7 +1471,6 @@ test "defined-layout union field pointer has correct alignment" { } test "undefined-layout union field pointer has correct alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -1611,6 +1609,10 @@ fn littleToNativeEndian(comptime T: type, v: T) T { } test "reinterpret extern union" { + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isRiscv32() and builtin.link_libc) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) return error.SkipZigTest; + if (true) { // https://github.com/ziglang/zig/issues/19389 return error.SkipZigTest; @@ -1678,8 +1680,6 @@ test "reinterpret extern union" { }; try comptime S.doTheTest(); - - if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO try S.doTheTest(); } @@ -1758,8 +1758,6 @@ test "reinterpret packed union" { }; try comptime S.doTheTest(); - - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try S.doTheTest(); } @@ -1800,8 +1798,6 @@ test "reinterpret packed union inside packed struct" { }; try comptime S.doTheTest(); - - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try S.doTheTest(); } diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 7d63b136fda14fca1358123c1546820a42f0dcf9..1b7d354e19c92996c8b6f30dde1acc2ad5914a4a 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -128,13 +128,6 @@ test "vector float operators" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; - - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { - // Triggers an assertion with LLVM 18: - // https://github.com/ziglang/zig/issues/20680 - return error.SkipZigTest; - } const S = struct { fn doTheTest(T: type) !void { @@ -280,7 +273,6 @@ test "array to vector with element type coercion" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -736,9 +728,7 @@ test "vector reduce operation" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; // https://github.com/llvm/llvm-project/issues/195562 const S = struct { fn testReduce(comptime op: std.builtin.ReduceOp, x: anytype, expected: anytype) !void { @@ -776,6 +766,8 @@ test "vector reduce operation" { try testReduce(.Add, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 42.9)); try testReduce(.Add, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 42.9)); try testReduce(.Add, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 42.9)); + try testReduce(.Add, [4]f80{ -1.9, 5.1, -60.3, 100.0 }, @as(f80, 42.9)); + try testReduce(.Add, [4]f128{ -1.9, 5.1, -60.3, 100.0 }, @as(f128, 42.9)); try testReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false)); try testReduce(.And, [4]u1{ 1, 0, 1, 1 }, @as(u1, 0)); @@ -794,6 +786,8 @@ test "vector reduce operation" { try testReduce(.Min, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, -100.0)); try testReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0)); try testReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0)); + try testReduce(.Min, [4]f80{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f80, -100.0)); + try testReduce(.Min, [4]f128{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f128, -100.0)); try testReduce(.Max, [4]i16{ -1, 2, 3, 4 }, @as(i16, 4)); try testReduce(.Max, [4]u16{ 1, 2, 3, 4 }, @as(u16, 4)); @@ -806,6 +800,8 @@ test "vector reduce operation" { try testReduce(.Max, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, 10.0e9)); try testReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9)); try testReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9)); + try testReduce(.Max, [4]f80{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f80, 10.0e9)); + try testReduce(.Max, [4]f128{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f128, 10.0e9)); try testReduce(.Mul, [4]i16{ -1, 2, 3, 4 }, @as(i16, -24)); try testReduce(.Mul, [4]u16{ 1, 2, 3, 4 }, @as(u16, 24)); @@ -818,6 +814,8 @@ test "vector reduce operation" { try testReduce(.Mul, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 58430.7)); try testReduce(.Mul, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 58430.7)); try testReduce(.Mul, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 58430.7)); + try testReduce(.Mul, [4]f80{ -1.9, 5.1, -60.3, 100.0 }, @as(f80, 58430.7)); + try testReduce(.Mul, [4]f128{ -1.9, 5.1, -60.3, 100.0 }, @as(f128, 58430.7)); try testReduce(.Or, [4]bool{ false, true, false, false }, @as(bool, true)); try testReduce(.Or, [4]u1{ 0, 1, 0, 0 }, @as(u1, 1)); @@ -825,6 +823,7 @@ test "vector reduce operation" { try testReduce(.Or, [4]u32{ 0xffff0000, 0xff00, 0xf0, 0xf }, ~@as(u32, 0)); try testReduce(.Or, [4]u64{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u64, 0xffffffff)); try testReduce(.Or, [4]u128{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u128, 0xffffffff)); + try testReduce(.Or, [4]u80{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u80, 0xffffffff)); try testReduce(.Xor, [4]bool{ true, true, true, false }, @as(bool, true)); try testReduce(.Xor, [4]u1{ 1, 1, 1, 0 }, @as(u1, 1)); @@ -837,22 +836,32 @@ test "vector reduce operation" { const f16_nan = math.nan(f16); const f32_nan = math.nan(f32); const f64_nan = math.nan(f64); + const f80_nan = math.nan(f80); + const f128_nan = math.nan(f128); try testReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); try testReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); try testReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); + try testReduce(.Add, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, f80_nan); + try testReduce(.Add, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, f128_nan); try testReduce(.Min, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, -1.9)); try testReduce(.Min, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, -1.9)); try testReduce(.Min, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, -1.9)); + try testReduce(.Min, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, @as(f80, -1.9)); + try testReduce(.Min, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, @as(f128, -1.9)); try testReduce(.Max, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, @as(f16, 100.0)); try testReduce(.Max, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, @as(f32, 100.0)); try testReduce(.Max, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, @as(f64, 100.0)); + try testReduce(.Max, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, @as(f80, 100.0)); + try testReduce(.Max, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, @as(f128, 100.0)); try testReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); try testReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); try testReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); + try testReduce(.Mul, [4]f80{ -1.9, 5.1, f80_nan, 100.0 }, f80_nan); + try testReduce(.Mul, [4]f128{ -1.9, 5.1, f128_nan, 100.0 }, f128_nan); } }; @@ -1321,11 +1330,6 @@ test "byte vector initialized in inline function" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and comptime builtin.cpu.has(.x86, .avx512f)) { - // TODO https://github.com/ziglang/zig/issues/13279 - return error.SkipZigTest; - } - const S = struct { fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) { return .{ e0, e1, e2, e3 }; @@ -1437,7 +1441,6 @@ test "store packed vector element" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var v = @Vector(4, u1){ 1, 1, 1, 1 }; @@ -1469,7 +1472,6 @@ test "store vector with memset" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: [5]@Vector(2, i1) = undefined; @@ -1610,7 +1612,6 @@ test "bitcast vector to array of smaller vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const u8x32 = @Vector(32, u8); const u8x64 = @Vector(64, u8); diff --git a/test/behavior/widening.zig b/test/behavior/widening.zig index c6571319d4fbb3a2265dd48fd31e67a9061e2055..6277c3acf6790cd769ac86dc885959e8281e7a71 100644 --- a/test/behavior/widening.zig +++ b/test/behavior/widening.zig @@ -41,7 +41,6 @@ test "float widening" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag == .macos) return error.SkipZigTest; var a: f16 = 12.34; var b: f32 = a; diff --git a/test/behavior/x86_64/unary.zig b/test/behavior/x86_64/unary.zig index 2b2a9e288b30c1c0a1d0ab1de61b23522582b6e8..263505f090d09aa3b76eddb309b0d6bd531057dc 100644 --- a/test/behavior/x86_64/unary.zig +++ b/test/behavior/x86_64/unary.zig @@ -56,7 +56,7 @@ fn unary(comptime op: anytype, comptime opts: struct { f32 => libc_name ++ "f", f64 => libc_name, f80 => "__" ++ libc_name ++ "x", - f128 => libc_name ++ "q", + f128 => libc_name ++ "f128", else => break :libc, }, .library_name = switch (@import("builtin").object_format) { diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index 302503ad4d839449c9aad546e712f3ebb6bdff3d..327bc04ceb34148541b994bb894f04bea85bf210 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -77,7 +77,7 @@ static void assert_or_panic(bool ok) { # define ZIG_NO_COMPLEX #endif -#ifdef ZIG_PPC32 +#ifdef __powerpc__ # define ZIG_NO_COMPLEX #endif @@ -191,9 +191,6 @@ void zig_struct_i128(struct i128); #endif void zig_five_integers(int32_t, int32_t, int32_t, int32_t, int32_t); -void zig_f32(float); -void zig_f64(double); -void zig_longdouble(long double); void zig_five_floats(float, float, float, float, float); bool zig_ret_bool(); @@ -219,7 +216,203 @@ float complex zig_cmultf(float complex a, float complex b); double complex zig_cmultd(double complex a, double complex b); #endif -#if defined(ZIG_BACKEND_STAGE2_X86_64) || defined(ZIG_PPC32) || defined(__wasm__) +float zig_ret_f32(void); +void zig_f32(float, size_t); +void zig_1_f32(size_t, float, size_t); +void zig_2_f32(size_t, size_t, float, size_t); +void zig_3_f32(size_t, size_t, size_t, float, size_t); +void zig_4_f32(size_t, size_t, size_t, size_t, float, size_t); +void zig_5_f32(size_t, size_t, size_t, size_t, size_t, float, size_t); +void zig_6_f32(size_t, size_t, size_t, size_t, size_t, size_t, float, size_t); +void zig_7_f32(size_t, size_t, size_t, size_t, size_t, size_t, size_t, float, size_t); +void zig_8_f32(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, float, size_t); + +float c_ret_f32(void) { + return 11; +} +void c_f32(float f, size_t i) { + assert_or_panic(f == 12); + assert_or_panic(i == 1); +} +void c_1_f32(size_t a0, float f, size_t i) { + assert_or_panic(f == 13); + assert_or_panic(i == 2); +} +void c_2_f32(size_t a0, size_t a1, float f, size_t i) { + assert_or_panic(f == 14); + assert_or_panic(i == 3); +} +void c_3_f32(size_t a0, size_t a1, size_t a2, float f, size_t i) { + assert_or_panic(f == 15); + assert_or_panic(i == 4); +} +void c_4_f32(size_t a0, size_t a1, size_t a2, size_t a3, float f, size_t i) { + assert_or_panic(f == 16); + assert_or_panic(i == 5); +} +void c_5_f32(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, float f, size_t i) { + assert_or_panic(f == 17); + assert_or_panic(i == 6); +} +void c_6_f32(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, float f, size_t i) { + assert_or_panic(f == 18); + assert_or_panic(i == 7); +} +void c_7_f32(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, size_t a6, float f, size_t i) { + assert_or_panic(f == 19); + assert_or_panic(i == 8); +} +void c_8_f32(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, size_t a6, size_t a7, float f, size_t i) { + assert_or_panic(f == 20); + assert_or_panic(i == 9); +} +void c_test_f32(void) { + float f = zig_ret_f32(); + assert_or_panic(f == 1); + zig_f32(2, 1); + zig_1_f32(0, 3, 2); + zig_2_f32(0, 1, 4, 3); + zig_3_f32(0, 1, 2, 5, 4); + zig_4_f32(0, 1, 2, 3, 6, 5); + zig_5_f32(0, 1, 2, 3, 4, 7, 6); + zig_6_f32(0, 1, 2, 3, 4, 5, 8, 7); + zig_7_f32(0, 1, 2, 3, 4, 5, 6, 9, 8); + zig_8_f32(0, 1, 2, 3, 4, 5, 6, 7, 10, 9); +} + +double zig_ret_f64(void); +void zig_f64(double, size_t); +void zig_1_f64(size_t, double, size_t); +void zig_2_f64(size_t, size_t, double, size_t); +void zig_3_f64(size_t, size_t, size_t, double, size_t); +void zig_4_f64(size_t, size_t, size_t, size_t, double, size_t); +void zig_5_f64(size_t, size_t, size_t, size_t, size_t, double, size_t); +void zig_6_f64(size_t, size_t, size_t, size_t, size_t, size_t, double, size_t); +void zig_7_f64(size_t, size_t, size_t, size_t, size_t, size_t, size_t, double, size_t); +void zig_8_f64(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, double, size_t); + +double c_ret_f64(void) { + return 11; +} +void c_f64(double f, size_t i) { + assert_or_panic(f == 12); + assert_or_panic(i == 1); +} +void c_1_f64(size_t a0, double f, size_t i) { + assert_or_panic(f == 13); + assert_or_panic(i == 2); +} +void c_2_f64(size_t a0, size_t a1, double f, size_t i) { + assert_or_panic(f == 14); + assert_or_panic(i == 3); +} +void c_3_f64(size_t a0, size_t a1, size_t a2, double f, size_t i) { + assert_or_panic(f == 15); + assert_or_panic(i == 4); +} +void c_4_f64(size_t a0, size_t a1, size_t a2, size_t a3, double f, size_t i) { + assert_or_panic(f == 16); + assert_or_panic(i == 5); +} +void c_5_f64(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, double f, size_t i) { + assert_or_panic(f == 17); + assert_or_panic(i == 6); +} +void c_6_f64(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, double f, size_t i) { + assert_or_panic(f == 18); + assert_or_panic(i == 7); +} +void c_7_f64(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, size_t a6, double f, size_t i) { + assert_or_panic(f == 19); + assert_or_panic(i == 8); +} +void c_8_f64(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, size_t a6, size_t a7, double f, size_t i) { + assert_or_panic(f == 20); + assert_or_panic(i == 9); +} +void c_test_f64(void) { + double f = zig_ret_f64(); + assert_or_panic(f == 1); + zig_f64(2, 1); + zig_1_f64(0, 3, 2); + zig_2_f64(0, 1, 4, 3); + zig_3_f64(0, 1, 2, 5, 4); + zig_4_f64(0, 1, 2, 3, 6, 5); + zig_5_f64(0, 1, 2, 3, 4, 7, 6); + zig_6_f64(0, 1, 2, 3, 4, 5, 8, 7); + zig_7_f64(0, 1, 2, 3, 4, 5, 6, 9, 8); + zig_8_f64(0, 1, 2, 3, 4, 5, 6, 7, 10, 9); +} + +long double zig_ret_longdouble(void); +void zig_longdouble(long double, size_t); +void zig_1_longdouble(size_t, long double, size_t); +void zig_2_longdouble(size_t, size_t, long double, size_t); +void zig_3_longdouble(size_t, size_t, size_t, long double, size_t); +void zig_4_longdouble(size_t, size_t, size_t, size_t, long double, size_t); +void zig_5_longdouble(size_t, size_t, size_t, size_t, size_t, long double, size_t); +void zig_6_longdouble(size_t, size_t, size_t, size_t, size_t, size_t, long double, size_t); +void zig_7_longdouble(size_t, size_t, size_t, size_t, size_t, size_t, size_t, long double, size_t); +void zig_8_longdouble(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, long double, size_t); + +long double c_ret_longdouble(void) { + return 11; +} +void c_longdouble(long double f, size_t i) { + assert_or_panic(f == 12); + assert_or_panic(i == 1); +} +void c_1_longdouble(size_t a0, long double f, size_t i) { + assert_or_panic(f == 13); + assert_or_panic(i == 2); +} +void c_2_longdouble(size_t a0, size_t a1, long double f, size_t i) { + assert_or_panic(f == 14); + assert_or_panic(i == 3); +} +void c_3_longdouble(size_t a0, size_t a1, size_t a2, long double f, size_t i) { + assert_or_panic(f == 15); + assert_or_panic(i == 4); +} +void c_4_longdouble(size_t a0, size_t a1, size_t a2, size_t a3, long double f, size_t i) { + assert_or_panic(f == 16); + assert_or_panic(i == 5); +} +void c_5_longdouble(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, long double f, size_t i) { + assert_or_panic(f == 17); + assert_or_panic(i == 6); +} +void c_6_longdouble(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, long double f, size_t i) { + assert_or_panic(f == 18); + assert_or_panic(i == 7); +} +void c_7_longdouble(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, size_t a6, long double f, size_t i) { + assert_or_panic(f == 19); + assert_or_panic(i == 8); +} +void c_8_longdouble(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, size_t a6, size_t a7, long double f, size_t i) { + assert_or_panic(f == 20); + assert_or_panic(i == 9); +} +void c_test_longdouble(void) { + long double f = zig_ret_longdouble(); + assert_or_panic(f == 1); + zig_longdouble(2, 1); + zig_1_longdouble(0, 3, 2); + zig_2_longdouble(0, 1, 4, 3); + zig_3_longdouble(0, 1, 2, 5, 4); + zig_4_longdouble(0, 1, 2, 3, 6, 5); + zig_5_longdouble(0, 1, 2, 3, 4, 7, 6); + zig_6_longdouble(0, 1, 2, 3, 4, 5, 8, 7); + zig_7_longdouble(0, 1, 2, 3, 4, 5, 6, 9, 8); + zig_8_longdouble(0, 1, 2, 3, 4, 5, 6, 7, 10, 9); +} + +#ifndef __hexagon__ +#ifndef __loongarch__ +#ifndef __mips__ +#ifndef ZIG_PPC64 +#if !(defined(__i386__) && defined(_WIN32)) typedef bool Vector_2_bool __attribute__((ext_vector_type(2))); @@ -4468,6 +4661,10 @@ void c_test_vector_512_bool(void) { }); } +#endif +#endif +#endif +#endif #endif typedef uint8_t Vector_1_u8 __attribute__((vector_size(1 * sizeof(uint8_t)))); @@ -14997,6 +15194,242 @@ void c_test_struct_f32_f32_f32_f32_f32(void) { zig_struct_f32_f32_f32_f32_f32((struct Struct_f32_f32_f32_f32_f32){ .a = 6, .b = 7, .c = 8, .d = 9, .e = 10 }, 11); } +struct Struct_f32 zig_ret_struct_void_f32(void); +void zig_struct_void_f32(struct Struct_f32, size_t); + +struct Struct_f32 c_ret_struct_void_f32(void) { + return (struct Struct_f32){ .a = 4 }; +} +void c_struct_void_f32(struct Struct_f32 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_struct_void_f32(void) { + struct Struct_f32 s = zig_ret_struct_void_f32(); + assert_or_panic(s.a == 1); + zig_struct_void_f32((struct Struct_f32){ .a = 2 }, 3); +} + +struct Struct_array_1_f32 { + float a[1]; +}; + +struct Struct_array_1_f32 zig_ret_struct_array_1_f32(void); +void zig_struct_array_1_f32(struct Struct_array_1_f32, size_t); + +struct Struct_array_1_f32 c_ret_struct_array_1_f32(void) { + return (struct Struct_array_1_f32){ .a = { 4 } }; +} +void c_struct_array_1_f32(struct Struct_array_1_f32 s, size_t i) { + assert_or_panic(s.a[0] == 5); + assert_or_panic(i == 6); +} +void c_test_struct_array_1_f32(void) { + struct Struct_array_1_f32 s = zig_ret_struct_array_1_f32(); + assert_or_panic(s.a[0] == 1); + zig_struct_array_1_f32((struct Struct_array_1_f32){ .a = { 2 } }, 3); +} + +struct Struct_array_2_f32 { + float a[2]; +}; + +struct Struct_array_2_f32 zig_ret_struct_array_2_f32(void); +void zig_struct_array_2_f32(struct Struct_array_2_f32, size_t); + +struct Struct_array_2_f32 c_ret_struct_array_2_f32(void) { + return (struct Struct_array_2_f32){ .a = { 6, 7 } }; +} +void c_struct_array_2_f32(struct Struct_array_2_f32 s, size_t i) { + assert_or_panic(s.a[0] == 8); + assert_or_panic(s.a[1] == 9); + assert_or_panic(i == 10); +} +void c_test_struct_array_2_f32(void) { + struct Struct_array_2_f32 s = zig_ret_struct_array_2_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + zig_struct_array_2_f32((struct Struct_array_2_f32){ .a = { 3, 4 } }, 5); +} + +struct Struct_array_3_f32 { + float a[3]; +}; + +struct Struct_array_3_f32 zig_ret_struct_array_3_f32(void); +void zig_struct_array_3_f32(struct Struct_array_3_f32, size_t); + +struct Struct_array_3_f32 c_ret_struct_array_3_f32(void) { + return (struct Struct_array_3_f32){ .a = { 8, 9, 10 } }; +} +void c_struct_array_3_f32(struct Struct_array_3_f32 s, size_t i) { + assert_or_panic(s.a[0] == 11); + assert_or_panic(s.a[1] == 12); + assert_or_panic(s.a[2] == 13); + assert_or_panic(i == 14); +} +void c_test_struct_array_3_f32(void) { + struct Struct_array_3_f32 s = zig_ret_struct_array_3_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + zig_struct_array_3_f32((struct Struct_array_3_f32){ .a = { 4, 5, 6 } }, 7); +} + +struct Struct_array_4_f32 { + float a[4]; +}; + +struct Struct_array_4_f32 zig_ret_struct_array_4_f32(void); +void zig_struct_array_4_f32(struct Struct_array_4_f32, size_t); + +struct Struct_array_4_f32 c_ret_struct_array_4_f32(void) { + return (struct Struct_array_4_f32){ .a = { 10, 11, 12, 13 } }; +} +void c_struct_array_4_f32(struct Struct_array_4_f32 s, size_t i) { + assert_or_panic(s.a[0] == 14); + assert_or_panic(s.a[1] == 15); + assert_or_panic(s.a[2] == 16); + assert_or_panic(s.a[3] == 17); + assert_or_panic(i == 18); +} +void c_test_struct_array_4_f32(void) { + struct Struct_array_4_f32 s = zig_ret_struct_array_4_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + zig_struct_array_4_f32((struct Struct_array_4_f32){ .a = { 5, 6, 7, 8 } }, 9); +} + +struct Struct_array_5_f32 { + float a[5]; +}; + +struct Struct_array_5_f32 zig_ret_struct_array_5_f32(void); +void zig_struct_array_5_f32(struct Struct_array_5_f32, size_t); + +struct Struct_array_5_f32 c_ret_struct_array_5_f32(void) { + return (struct Struct_array_5_f32){ .a = { 12, 13, 14, 15, 16 } }; +} +void c_struct_array_5_f32(struct Struct_array_5_f32 s, size_t i) { + assert_or_panic(s.a[0] == 17); + assert_or_panic(s.a[1] == 18); + assert_or_panic(s.a[2] == 19); + assert_or_panic(s.a[3] == 20); + assert_or_panic(s.a[4] == 21); + assert_or_panic(i == 22); +} +void c_test_struct_array_5_f32(void) { + struct Struct_array_5_f32 s = zig_ret_struct_array_5_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + assert_or_panic(s.a[4] == 5); + zig_struct_array_5_f32((struct Struct_array_5_f32){ .a = { 6, 7, 8, 9, 10 } }, 11); +} + +struct Struct_array_1_f32 zig_ret_struct_array_0_sentinel_f32(void); +void zig_struct_array_0_sentinel_f32(struct Struct_array_1_f32, size_t); + +struct Struct_array_1_f32 c_ret_struct_array_0_sentinel_f32(void) { + return (struct Struct_array_1_f32){ .a = { 0x1e1 } }; +} +void c_struct_array_0_sentinel_f32(struct Struct_array_1_f32 s, size_t i) { + assert_or_panic(s.a[0] == 0x1e1); + assert_or_panic(i == 2); +} +void c_test_struct_array_0_sentinel_f32(void) { + struct Struct_array_1_f32 s = zig_ret_struct_array_0_sentinel_f32(); + assert_or_panic(s.a[0] == 0x1e1); + zig_struct_array_0_sentinel_f32((struct Struct_array_1_f32){ .a = { 0x1e1 } }, 1); +} + +struct Struct_array_2_f32 zig_ret_struct_array_1_sentinel_f32(void); +void zig_struct_array_1_sentinel_f32(struct Struct_array_2_f32, size_t); + +struct Struct_array_2_f32 c_ret_struct_array_1_sentinel_f32(void) { + return (struct Struct_array_2_f32){ .a = { 4, 0x1e1 } }; +} +void c_struct_array_1_sentinel_f32(struct Struct_array_2_f32 s, size_t i) { + assert_or_panic(s.a[0] == 5); + assert_or_panic(s.a[1] == 0x1e1); + assert_or_panic(i == 6); +} +void c_test_struct_array_1_sentinel_f32(void) { + struct Struct_array_2_f32 s = zig_ret_struct_array_1_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 0x1e1); + zig_struct_array_1_sentinel_f32((struct Struct_array_2_f32){ .a = { 2, 0x1e1 } }, 3); +} + +struct Struct_array_3_f32 zig_ret_struct_array_2_sentinel_f32(void); +void zig_struct_array_2_sentinel_f32(struct Struct_array_3_f32, size_t); + +struct Struct_array_3_f32 c_ret_struct_array_2_sentinel_f32(void) { + return (struct Struct_array_3_f32){ .a = { 6, 7, 0x1e1 } }; +} +void c_struct_array_2_sentinel_f32(struct Struct_array_3_f32 s, size_t i) { + assert_or_panic(s.a[0] == 8); + assert_or_panic(s.a[1] == 9); + assert_or_panic(s.a[2] == 0x1e1); + assert_or_panic(i == 10); +} +void c_test_struct_array_2_sentinel_f32(void) { + struct Struct_array_3_f32 s = zig_ret_struct_array_2_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 0x1e1); + zig_struct_array_2_sentinel_f32((struct Struct_array_3_f32){ .a = { 3, 4, 0x1e1 } }, 5); +} + +struct Struct_array_4_f32 zig_ret_struct_array_3_sentinel_f32(void); +void zig_struct_array_3_sentinel_f32(struct Struct_array_4_f32, size_t); + +struct Struct_array_4_f32 c_ret_struct_array_3_sentinel_f32(void) { + return (struct Struct_array_4_f32){ .a = { 8, 9, 10, 0x1e1 } }; +} +void c_struct_array_3_sentinel_f32(struct Struct_array_4_f32 s, size_t i) { + assert_or_panic(s.a[0] == 11); + assert_or_panic(s.a[1] == 12); + assert_or_panic(s.a[2] == 13); + assert_or_panic(s.a[3] == 0x1e1); + assert_or_panic(i == 14); +} +void c_test_struct_array_3_sentinel_f32(void) { + struct Struct_array_4_f32 s = zig_ret_struct_array_3_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 0x1e1); + zig_struct_array_3_sentinel_f32((struct Struct_array_4_f32){ .a = { 4, 5, 6, 0x1e1 } }, 7); +} + +struct Struct_array_5_f32 zig_ret_struct_array_4_sentinel_f32(void); +void zig_struct_array_4_sentinel_f32(struct Struct_array_5_f32, size_t); + +struct Struct_array_5_f32 c_ret_struct_array_4_sentinel_f32(void) { + return (struct Struct_array_5_f32){ .a = { 10, 11, 12, 13, 0x1e1 } }; +} +void c_struct_array_4_sentinel_f32(struct Struct_array_5_f32 s, size_t i) { + assert_or_panic(s.a[0] == 14); + assert_or_panic(s.a[1] == 15); + assert_or_panic(s.a[2] == 16); + assert_or_panic(s.a[3] == 17); + assert_or_panic(s.a[4] == 0x1e1); + assert_or_panic(i == 18); +} +void c_test_struct_array_4_sentinel_f32(void) { + struct Struct_array_5_f32 s = zig_ret_struct_array_4_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + assert_or_panic(s.a[4] == 0x1e1); + zig_struct_array_4_sentinel_f32((struct Struct_array_5_f32){ .a = { 5, 6, 7, 8, 0x1e1 } }, 9); +} + struct Struct_f32a8 { alignas(8) float a; }; @@ -15212,6 +15645,146 @@ void c_test_struct_f64_f64_f64_f64_f64(void) { zig_struct_f64_f64_f64_f64_f64((struct Struct_f64_f64_f64_f64_f64){ .a = 6, .b = 7, .c = 8, .d = 9, .e = 10 }, 11); } +struct Struct_array_1_f64 { + double a[1]; +}; + +struct Struct_array_1_f64 zig_ret_struct_array_1_f64(void); +void zig_struct_array_1_f64(struct Struct_array_1_f64, size_t); + +struct Struct_array_1_f64 c_ret_struct_array_1_f64(void) { + return (struct Struct_array_1_f64){ .a = { 4 } }; +} +void c_struct_array_1_f64(struct Struct_array_1_f64 s, size_t i) { + assert_or_panic(s.a[0] == 5); + assert_or_panic(i == 6); +} +void c_test_struct_array_1_f64(void) { + struct Struct_array_1_f64 s = zig_ret_struct_array_1_f64(); + assert_or_panic(s.a[0] == 1); + zig_struct_array_1_f64((struct Struct_array_1_f64){ .a = { 2 } }, 3); +} + +struct Struct_array_2_f64 { + double a[2]; +}; + +struct Struct_array_2_f64 zig_ret_struct_array_2_f64(void); +void zig_struct_array_2_f64(struct Struct_array_2_f64, size_t); + +struct Struct_array_2_f64 c_ret_struct_array_2_f64(void) { + return (struct Struct_array_2_f64){ .a = { 6, 7 } }; +} +void c_struct_array_2_f64(struct Struct_array_2_f64 s, size_t i) { + assert_or_panic(s.a[0] == 8); + assert_or_panic(s.a[1] == 9); + assert_or_panic(i == 10); +} +void c_test_struct_array_2_f64(void) { + struct Struct_array_2_f64 s = zig_ret_struct_array_2_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + zig_struct_array_2_f64((struct Struct_array_2_f64){ .a = { 3, 4 } }, 5); +} + +struct Struct_array_3_f64 { + double a[3]; +}; + +struct Struct_array_3_f64 zig_ret_struct_array_3_f64(void); +void zig_struct_array_3_f64(struct Struct_array_3_f64, size_t); + +struct Struct_array_3_f64 c_ret_struct_array_3_f64(void) { + return (struct Struct_array_3_f64){ .a = { 8, 9, 10 } }; +} +void c_struct_array_3_f64(struct Struct_array_3_f64 s, size_t i) { + assert_or_panic(s.a[0] == 11); + assert_or_panic(s.a[1] == 12); + assert_or_panic(s.a[2] == 13); + assert_or_panic(i == 14); +} +void c_test_struct_array_3_f64(void) { + struct Struct_array_3_f64 s = zig_ret_struct_array_3_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + zig_struct_array_3_f64((struct Struct_array_3_f64){ .a = { 4, 5, 6 } }, 7); +} + +struct Struct_array_4_f64 { + double a[4]; +}; + +struct Struct_array_4_f64 zig_ret_struct_array_4_f64(void); +void zig_struct_array_4_f64(struct Struct_array_4_f64, size_t); + +struct Struct_array_4_f64 c_ret_struct_array_4_f64(void) { + return (struct Struct_array_4_f64){ .a = { 10, 11, 12, 13 } }; +} +void c_struct_array_4_f64(struct Struct_array_4_f64 s, size_t i) { + assert_or_panic(s.a[0] == 14); + assert_or_panic(s.a[1] == 15); + assert_or_panic(s.a[2] == 16); + assert_or_panic(s.a[3] == 17); + assert_or_panic(i == 18); +} +void c_test_struct_array_4_f64(void) { + struct Struct_array_4_f64 s = zig_ret_struct_array_4_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + zig_struct_array_4_f64((struct Struct_array_4_f64){ .a = { 5, 6, 7, 8 } }, 9); +} + +struct Struct_array_5_f64 { + double a[5]; +}; + +struct Struct_array_5_f64 zig_ret_struct_array_5_f64(void); +void zig_struct_array_5_f64(struct Struct_array_5_f64, size_t); + +struct Struct_array_5_f64 c_ret_struct_array_5_f64(void) { + return (struct Struct_array_5_f64){ .a = { 12, 13, 14, 15, 16 } }; +} +void c_struct_array_5_f64(struct Struct_array_5_f64 s, size_t i) { + assert_or_panic(s.a[0] == 17); + assert_or_panic(s.a[1] == 18); + assert_or_panic(s.a[2] == 19); + assert_or_panic(s.a[3] == 20); + assert_or_panic(s.a[4] == 21); + assert_or_panic(i == 22); +} +void c_test_struct_array_5_f64(void) { + struct Struct_array_5_f64 s = zig_ret_struct_array_5_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + assert_or_panic(s.a[4] == 5); + zig_struct_array_5_f64((struct Struct_array_5_f64){ .a = { 6, 7, 8, 9, 10 } }, 11); +} + +union Union_f64 { + double a; +}; + +union Union_f64 zig_ret_union_f64(void); +void zig_union_f64(union Union_f64, size_t); + +union Union_f64 c_ret_union_f64(void) { + return (union Union_f64){ .a = 4 }; +} +void c_union_f64(union Union_f64 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_union_f64(void) { + union Union_f64 s = zig_ret_union_f64(); + assert_or_panic(s.a == 1); + zig_union_f64((union Union_f64){ .a = 2 }, 3); +} + struct Struct_u32_Union_u32_u32u32 { uint32_t a; union { @@ -15326,9 +15899,6 @@ void run_c_tests(void) { zig_five_integers(12, 34, 56, 78, 90); - zig_f32(12.34f); - zig_f64(56.78); - zig_longdouble(12.34l); zig_five_floats(1.0f, 2.0f, 3.0f, 4.0f, 5.0f); zig_ptr((void *)0xdeadbeefL); @@ -15377,8 +15947,7 @@ void run_c_tests(void) { #if !(defined(__i386__) && defined(_WIN32)) #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct Struct_i32_i32 s = {1, 2}; zig_struct_i32_i32(s); @@ -15387,13 +15956,11 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef __hexagon__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct BigStruct s = {1, 2, 3, 4, 5}; zig_big_struct(s); @@ -15402,7 +15969,6 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef ZIG_NO_I128 { @@ -15426,8 +15992,7 @@ void run_c_tests(void) { #ifndef __i386__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct SplitStructInts s = {1234, 100, 1337}; zig_split_struct_ints(s); @@ -15437,13 +16002,11 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef __hexagon__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct MedStructMixed s = {1234, 100.0f, 1337.0f}; zig_med_struct_mixed(s); @@ -15452,14 +16015,12 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef __hexagon__ #ifndef __i386__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct SplitStructMixed s = {1234, 100, 1337.0f}; zig_split_struct_mixed(s); @@ -15469,13 +16030,11 @@ void run_c_tests(void) { #endif #endif #endif -#endif #ifndef __hexagon__ #ifndef __loongarch__ #ifndef ZIG_MIPS64 -#ifndef __powerpc__ -#ifndef __s390x__ +#ifndef ZIG_PPC32 { struct BigStruct s = {30, 31, 32, 33, 34}; struct BigStruct res = zig_big_struct_both(s); @@ -15488,7 +16047,6 @@ void run_c_tests(void) { #endif #endif #endif -#endif #endif { @@ -15550,18 +16108,6 @@ void c_struct_i128(struct i128 x) { } #endif -void c_f32(float x) { - assert_or_panic(x == 12.34f); -} - -void c_f64(double x) { - assert_or_panic(x == 56.78); -} - -void c_long_double(long double x) { - assert_or_panic(x == 12.34l); -} - void c_ptr(void *x) { assert_or_panic(x == (void *)0xdeadbeefL); } @@ -16078,6 +16624,16 @@ struct ByRef __attribute__((sysv_abi)) c_explict_sys_v(struct ByRef in) { } #endif +#if defined __x86_64__ || defined __aarch64__ +int __attribute__((preserve_none)) c_preserve_none(int x) { + return x + 1; +} +int __attribute__((preserve_none)) zig_preserve_none(int); +void c_preserve_none_check(void) { + assert_or_panic(zig_preserve_none(41) == 42); +} +#endif + struct byval_tail_callsite_attr_Point { double x; double y; @@ -16212,7 +16768,13 @@ void __attribute__((vectorcall)) c_vectorcall_check(int a, float b, double c, vo } #endif -#if defined(__x86_64__) && defined(_WIN64) +void c_x86_64_sysv_uint_int_uint_int(unsigned a, int b, unsigned c, int d) { + assert_or_panic(a == 1); + assert_or_panic(b == -2); + assert_or_panic(c == 3); + assert_or_panic(d == -4); +} + void c_win64_varargs_u64_f64_u64_f64(uint64_t a, double b, uint64_t c, double d) { assert_or_panic(a == UINT64_C(0x3ff0000000000000)); assert_or_panic(b == 2.0); @@ -16225,4 +16787,3 @@ void c_win64_varargs_f64_u64_f64_u64(double a, uint64_t b, double c, uint64_t d) assert_or_panic(c == 7.0); assert_or_panic(d == UINT64_C(0x4020000000000000)); } -#endif diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig index 1fd570b4ed40b6a50d2085c8d65a32fa941b36fc..a481a015117276e8abf7c4393f6d85cf60dd20fb 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -13,7 +13,7 @@ const expectEqual = std.testing.expectEqual; const have_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isArm() and !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPowerPC32() and builtin.cpu.arch != .riscv32 and builtin.cpu.arch != .hexagon and - builtin.cpu.arch != .s390x; // https://github.com/llvm/llvm-project/issues/168460 + builtin.cpu.arch != .s390x; const have_f128 = builtin.cpu.arch.isWasm() or (builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin() and builtin.abi != .msvc); const have_f80 = builtin.cpu.arch.isX86() and builtin.abi != .msvc; @@ -104,10 +104,6 @@ export fn zig_struct_u128(a: U128) void { expect(a.value == 0xfffffffffffffffc) catch @panic("test failure: zig_struct_u128"); } -extern fn c_f32(f32) void; -extern fn c_f64(f64) void; -extern fn c_long_double(c_longdouble) void; - // On windows x64, the first 4 are passed via registers, others on the stack. extern fn c_five_floats(f32, f32, f32, f32, f32) void; @@ -120,28 +116,9 @@ export fn zig_five_floats(a: f32, b: f32, c: f32, d: f32, e: f32) void { } test "floats" { - c_f32(12.34); - c_f64(56.78); c_five_floats(1.0, 2.0, 3.0, 4.0, 5.0); } -test "long double" { - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - - c_long_double(12.34); -} - -export fn zig_f32(x: f32) void { - expect(x == 12.34) catch @panic("test failure: zig_f32"); -} -export fn zig_f64(x: f64) void { - expect(x == 56.78) catch @panic("test failure: zig_f64"); -} -export fn zig_longdouble(x: c_longdouble) void { - if (!builtin.target.cpu.arch.isWasm()) return; // waiting for #1481 - expect(x == 12.34) catch @panic("test failure: zig_longdouble"); -} - extern fn c_ptr(*anyopaque) void; test "pointer" { @@ -184,7 +161,7 @@ extern fn c_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat; extern fn c_cmultd(a: ComplexDouble, b: ComplexDouble) ComplexDouble; const complex_abi_compatible = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isMIPS() and - !builtin.cpu.arch.isArm() and !builtin.cpu.arch.isPowerPC32() and !builtin.cpu.arch.isRISCV() and + !builtin.cpu.arch.isArm() and !builtin.cpu.arch.isPowerPC() and !builtin.cpu.arch.isRISCV() and builtin.cpu.arch != .hexagon and builtin.cpu.arch != .s390x and !(builtin.cpu.arch.isLoongArch() and builtin.abi.float() == .soft); @@ -269,10 +246,217 @@ export fn zig_cmultd_comp(a_r: f64, a_i: f64, b_r: f64, b_i: f64) ComplexDouble return .{ .real = 1.5, .imag = 13.5 }; } +export fn zig_ret_f32() f32 { + return 1; +} +export fn zig_f32(f: f32, i: usize) void { + expect(f == 2) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} +export fn zig_1_f32(_: usize, f: f32, i: usize) void { + expect(f == 3) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} +export fn zig_2_f32(_: usize, _: usize, f: f32, i: usize) void { + expect(f == 4) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} +export fn zig_3_f32(_: usize, _: usize, _: usize, f: f32, i: usize) void { + expect(f == 5) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} +export fn zig_4_f32(_: usize, _: usize, _: usize, _: usize, f: f32, i: usize) void { + expect(f == 6) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} +export fn zig_5_f32(_: usize, _: usize, _: usize, _: usize, _: usize, f: f32, i: usize) void { + expect(f == 7) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} +export fn zig_6_f32(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, f: f32, i: usize) void { + expect(f == 8) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} +export fn zig_7_f32(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, f: f32, i: usize) void { + expect(f == 9) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} +export fn zig_8_f32(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, f: f32, i: usize) void { + expect(f == 10) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_f32() f32; +extern fn c_f32(f32, usize) void; +extern fn c_1_f32(usize, f32, usize) void; +extern fn c_2_f32(usize, usize, f32, usize) void; +extern fn c_3_f32(usize, usize, usize, f32, usize) void; +extern fn c_4_f32(usize, usize, usize, usize, f32, usize) void; +extern fn c_5_f32(usize, usize, usize, usize, usize, f32, usize) void; +extern fn c_6_f32(usize, usize, usize, usize, usize, usize, f32, usize) void; +extern fn c_7_f32(usize, usize, usize, usize, usize, usize, usize, f32, usize) void; +extern fn c_8_f32(usize, usize, usize, usize, usize, usize, usize, usize, f32, usize) void; +extern fn c_test_f32() void; + +test "f32" { + const f = c_ret_f32(); + try expect(f == 11); + c_f32(12, 1); + c_1_f32(0, 13, 2); + c_2_f32(0, 1, 14, 3); + c_3_f32(0, 1, 2, 15, 4); + c_4_f32(0, 1, 2, 3, 16, 5); + c_5_f32(0, 1, 2, 3, 4, 17, 6); + c_6_f32(0, 1, 2, 3, 4, 5, 18, 7); + c_7_f32(0, 1, 2, 3, 4, 5, 6, 19, 8); + c_8_f32(0, 1, 2, 3, 4, 5, 6, 7, 20, 9); + c_test_f32(); +} + +export fn zig_ret_f64() f64 { + return 1; +} +export fn zig_f64(f: f64, i: usize) void { + expect(f == 2) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} +export fn zig_1_f64(_: usize, f: f64, i: usize) void { + expect(f == 3) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} +export fn zig_2_f64(_: usize, _: usize, f: f64, i: usize) void { + expect(f == 4) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} +export fn zig_3_f64(_: usize, _: usize, _: usize, f: f64, i: usize) void { + expect(f == 5) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} +export fn zig_4_f64(_: usize, _: usize, _: usize, _: usize, f: f64, i: usize) void { + expect(f == 6) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} +export fn zig_5_f64(_: usize, _: usize, _: usize, _: usize, _: usize, f: f64, i: usize) void { + expect(f == 7) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} +export fn zig_6_f64(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, f: f64, i: usize) void { + expect(f == 8) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} +export fn zig_7_f64(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, f: f64, i: usize) void { + expect(f == 9) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} +export fn zig_8_f64(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, f: f64, i: usize) void { + expect(f == 10) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_f64() f64; +extern fn c_f64(f64, usize) void; +extern fn c_1_f64(usize, f64, usize) void; +extern fn c_2_f64(usize, usize, f64, usize) void; +extern fn c_3_f64(usize, usize, usize, f64, usize) void; +extern fn c_4_f64(usize, usize, usize, usize, f64, usize) void; +extern fn c_5_f64(usize, usize, usize, usize, usize, f64, usize) void; +extern fn c_6_f64(usize, usize, usize, usize, usize, usize, f64, usize) void; +extern fn c_7_f64(usize, usize, usize, usize, usize, usize, usize, f64, usize) void; +extern fn c_8_f64(usize, usize, usize, usize, usize, usize, usize, usize, f64, usize) void; +extern fn c_test_f64() void; + +test "f64" { + const f = c_ret_f64(); + try expect(f == 11); + c_f64(12, 1); + c_1_f64(0, 13, 2); + c_2_f64(0, 1, 14, 3); + c_3_f64(0, 1, 2, 15, 4); + c_4_f64(0, 1, 2, 3, 16, 5); + c_5_f64(0, 1, 2, 3, 4, 17, 6); + c_6_f64(0, 1, 2, 3, 4, 5, 18, 7); + c_7_f64(0, 1, 2, 3, 4, 5, 6, 19, 8); + c_8_f64(0, 1, 2, 3, 4, 5, 6, 7, 20, 9); + c_test_f64(); +} + +export fn zig_ret_longdouble() c_longdouble { + return 1; +} +export fn zig_longdouble(f: c_longdouble, i: usize) void { + expect(f == 2) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} +export fn zig_1_longdouble(_: usize, f: c_longdouble, i: usize) void { + expect(f == 3) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} +export fn zig_2_longdouble(_: usize, _: usize, f: c_longdouble, i: usize) void { + expect(f == 4) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} +export fn zig_3_longdouble(_: usize, _: usize, _: usize, f: c_longdouble, i: usize) void { + expect(f == 5) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} +export fn zig_4_longdouble(_: usize, _: usize, _: usize, _: usize, f: c_longdouble, i: usize) void { + expect(f == 6) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} +export fn zig_5_longdouble(_: usize, _: usize, _: usize, _: usize, _: usize, f: c_longdouble, i: usize) void { + expect(f == 7) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} +export fn zig_6_longdouble(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, f: c_longdouble, i: usize) void { + expect(f == 8) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} +export fn zig_7_longdouble(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, f: c_longdouble, i: usize) void { + expect(f == 9) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} +export fn zig_8_longdouble(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, f: c_longdouble, i: usize) void { + expect(f == 10) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_longdouble() c_longdouble; +extern fn @"c_longdouble"(c_longdouble, usize) void; +extern fn c_1_longdouble(usize, c_longdouble, usize) void; +extern fn c_2_longdouble(usize, usize, c_longdouble, usize) void; +extern fn c_3_longdouble(usize, usize, usize, c_longdouble, usize) void; +extern fn c_4_longdouble(usize, usize, usize, usize, c_longdouble, usize) void; +extern fn c_5_longdouble(usize, usize, usize, usize, usize, c_longdouble, usize) void; +extern fn c_6_longdouble(usize, usize, usize, usize, usize, usize, c_longdouble, usize) void; +extern fn c_7_longdouble(usize, usize, usize, usize, usize, usize, usize, c_longdouble, usize) void; +extern fn c_8_longdouble(usize, usize, usize, usize, usize, usize, usize, usize, c_longdouble, usize) void; +extern fn c_test_longdouble() void; + +test "long double" { + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + + const f = c_ret_longdouble(); + try expect(f == 11); + @"c_longdouble"(12, 1); + c_1_longdouble(0, 13, 2); + c_2_longdouble(0, 1, 14, 3); + c_3_longdouble(0, 1, 2, 15, 4); + c_4_longdouble(0, 1, 2, 3, 16, 5); + c_5_longdouble(0, 1, 2, 3, 4, 17, 6); + c_6_longdouble(0, 1, 2, 3, 4, 5, 18, 7); + c_7_longdouble(0, 1, 2, 3, 4, 5, 6, 19, 8); + c_8_longdouble(0, 1, 2, 3, 4, 5, 6, 7, 20, 9); + c_test_longdouble(); +} + comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.zig_backend == .stage2_wasm) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_2_bool() @Vector(2, bool) { @@ -294,7 +478,14 @@ extern fn c_vector_2_bool(@Vector(2, bool)) void; extern fn c_test_vector_2_bool() void; test "@Vector(2, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_2_bool(); try expect(vec[0] == true); @@ -308,8 +499,12 @@ test "@Vector(2, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.zig_backend == .stage2_wasm) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_4_bool() @Vector(4, bool) { @@ -335,7 +530,14 @@ extern fn c_vector_4_bool(@Vector(4, bool)) void; extern fn c_test_vector_4_bool() void; test "@Vector(4, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_4_bool(); try expect(vec[0] == true); @@ -353,8 +555,12 @@ test "@Vector(4, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.zig_backend == .stage2_wasm) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_8_bool() @Vector(8, bool) { @@ -388,7 +594,14 @@ extern fn c_vector_8_bool(@Vector(8, bool)) void; extern fn c_test_vector_8_bool() void; test "@Vector(8, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_8_bool(); try expect(vec[0] == false); @@ -414,8 +627,12 @@ test "@Vector(8, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.zig_backend == .stage2_wasm) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_16_bool() @Vector(16, bool) { @@ -465,7 +682,14 @@ extern fn c_vector_16_bool(@Vector(16, bool)) void; extern fn c_test_vector_16_bool() void; test "@Vector(16, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_16_bool(); try expect(vec[0] == true); @@ -507,8 +731,12 @@ test "@Vector(16, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.zig_backend == .stage2_wasm) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_32_bool() @Vector(32, bool) { @@ -590,7 +818,14 @@ extern fn c_vector_32_bool(@Vector(32, bool)) void; extern fn c_test_vector_32_bool() void; test "@Vector(32, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_32_bool(); try expect(vec[0] == true); @@ -664,8 +899,12 @@ test "@Vector(32, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.zig_backend == .stage2_wasm) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_64_bool() @Vector(64, bool) { @@ -811,7 +1050,12 @@ extern fn c_vector_64_bool(@Vector(64, bool)) void; extern fn c_test_vector_64_bool() void; test "@Vector(64, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; const vec = c_ret_vector_64_bool(); try expect(vec[0] == false); @@ -949,8 +1193,12 @@ test "@Vector(64, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.zig_backend == .stage2_wasm) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_128_bool() @Vector(128, bool) { @@ -1224,7 +1472,12 @@ extern fn c_vector_128_bool(@Vector(128, bool)) void; extern fn c_test_vector_128_bool() void; test "@Vector(128, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_128_bool(); try expect(vec[0] == false); @@ -1490,8 +1743,12 @@ test "@Vector(128, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.zig_backend == .stage2_wasm) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_256_bool() @Vector(256, bool) { @@ -2021,7 +2278,12 @@ extern fn c_vector_256_bool(@Vector(256, bool)) void; extern fn c_test_vector_256_bool() void; test "@Vector(256, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_256_bool(); try expect(vec[0] == true); @@ -2543,8 +2805,12 @@ test "@Vector(256, bool)" { comptime { skip: { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) break :skip; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.zig_backend == .stage2_wasm) break :skip; + if (builtin.cpu.arch == .hexagon) break :skip; + if (builtin.cpu.arch == .loongarch64) break :skip; + if (builtin.cpu.arch.isMIPS()) break :skip; + if (builtin.cpu.arch.isPowerPC64()) break :skip; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) break :skip; _ = struct { export fn zig_ret_vector_512_bool() @Vector(512, bool) { @@ -3586,7 +3852,12 @@ extern fn c_vector_512_bool(@Vector(512, bool)) void; extern fn c_test_vector_512_bool() void; test "@Vector(512, bool)" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const vec = c_ret_vector_512_bool(); try expect(vec[0] == false); @@ -4660,7 +4931,7 @@ test "@Vector(2, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; const v = c_ret_vector_2_u8(); try expect(v[0] == 9); @@ -4689,7 +4960,6 @@ test "@Vector(3, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; const v = c_ret_vector_3_u8(); try expect(v[0] == 19); @@ -4732,7 +5002,7 @@ test "@Vector(4, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; const v = c_ret_vector_4_u8(); try expect(v[0] == 41); @@ -4766,7 +5036,6 @@ test "@Vector(6, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; const v = c_ret_vector_6_u8(); try expect(v[0] == 53); @@ -4956,7 +5225,6 @@ test "@Vector(24, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_u8(); try expect(v[0] == 57); @@ -5040,7 +5308,6 @@ test "@Vector(32, u8)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_u8(); try expect(v[0] == 69); @@ -5150,7 +5417,6 @@ test "@Vector(48, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_u8(); try expect(v[0] == 29); @@ -5293,7 +5559,6 @@ test "@Vector(64, u8)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_u8(); try expect(v[0] == 53); @@ -5488,7 +5753,6 @@ test "@Vector(96, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_96_u8(); try expect(v[0] == 82); @@ -5751,7 +6015,6 @@ test "@Vector(128, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_128_u8(); try expect(v[0] == 30); @@ -6116,7 +6379,6 @@ test "@Vector(192, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_192_u8(); try expect(v[0] == 70); @@ -6617,7 +6879,6 @@ test "@Vector(256, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_256_u8(); try expect(v[0] == 66); @@ -7322,7 +7583,6 @@ test "@Vector(384, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_384_u8(); try expect(v[0] == 46); @@ -8299,7 +8559,6 @@ test "@Vector(512, u8)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_512_u8(); try expect(v[0] == 38); @@ -8893,7 +9152,7 @@ test "@Vector(2, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; const v = c_ret_vector_2_u16(); try expect(v[0] == 9); @@ -8921,7 +9180,6 @@ test "@Vector(3, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; const v = c_ret_vector_3_u16(); try expect(v[0] == 19); @@ -9070,7 +9328,6 @@ test "@Vector(12, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_12_u16(); try expect(v[0] == 121); @@ -9120,7 +9377,6 @@ test "@Vector(16, u16)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_u16(); try expect(v[0] == 177); @@ -9186,7 +9442,6 @@ test "@Vector(24, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_u16(); try expect(v[0] == 257); @@ -9270,7 +9525,6 @@ test "@Vector(32, u16)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_u16(); try expect(v[0] == 369); @@ -9380,7 +9634,6 @@ test "@Vector(48, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_u16(); try expect(v[0] == 529); @@ -9524,7 +9777,6 @@ test "@Vector(64, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_u16(); try expect(v[0] == 753); @@ -9719,7 +9971,6 @@ test "@Vector(96, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_96_u16(); try expect(v[0] == 1082); @@ -9982,7 +10233,6 @@ test "@Vector(128, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_128_u16(); try expect(v[0] == 1530); @@ -10347,7 +10597,6 @@ test "@Vector(192, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_192_u16(); try expect(v[0] == 2170); @@ -10848,7 +11097,6 @@ test "@Vector(256, u16)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_256_u16(); try expect(v[0] == 3066); @@ -11265,7 +11513,6 @@ test "@Vector(6, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_6_u32(); try expect(v[0] == 53); @@ -11301,7 +11548,6 @@ test "@Vector(8, u32)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_8_u32(); try expect(v[0] == 81); @@ -11344,7 +11590,6 @@ test "@Vector(12, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_12_u32(); try expect(v[0] == 121); @@ -11394,7 +11639,6 @@ test "@Vector(16, u32)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_u32(); try expect(v[0] == 177); @@ -11460,7 +11704,6 @@ test "@Vector(24, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_u32(); try expect(v[0] == 257); @@ -11545,7 +11788,6 @@ test "@Vector(32, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_u32(); try expect(v[0] == 369); @@ -11655,7 +11897,6 @@ test "@Vector(48, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_u32(); try expect(v[0] == 529); @@ -11799,7 +12040,6 @@ test "@Vector(64, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_u32(); try expect(v[0] == 753); @@ -11994,7 +12234,6 @@ test "@Vector(96, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_96_u32(); try expect(v[0] == 1082); @@ -12257,7 +12496,6 @@ test "@Vector(128, u32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_128_u32(); try expect(v[0] == 1530); @@ -12414,8 +12652,6 @@ extern fn c_vector_1_u64(@Vector(1, u64), usize) void; extern fn c_test_vector_1_u64() void; test "@Vector(1, u64)" { - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; - const v = c_ret_vector_1_u64(); try expect(v[0] == 3); c_vector_1_u64(.{4}, 1); @@ -12464,7 +12700,6 @@ test "@Vector(3, u64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_3_u64(); try expect(v[0] == 19); @@ -12493,7 +12728,6 @@ test "@Vector(4, u64)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_4_u64(); try expect(v[0] == 33); @@ -12560,7 +12794,6 @@ test "@Vector(8, u64)" { if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_8_u64(); try expect(v[0] == 81); @@ -12652,7 +12885,6 @@ test "@Vector(16, u64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_u64(); try expect(v[0] == 177); @@ -12801,7 +13033,6 @@ test "@Vector(32, u64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_u64(); try expect(v[0] == 369); @@ -13053,7 +13284,6 @@ test "@Vector(64, u64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_u64(); try expect(v[0] == 753); @@ -13147,7 +13377,6 @@ test "@Vector(1, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag != .windows) return error.SkipZigTest; const v = c_ret_vector_1_f32(); try expect(v[0] == 3); @@ -13269,7 +13498,6 @@ test "@Vector(6, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_6_f32(); try expect(v[0] == 53); @@ -13306,7 +13534,6 @@ test "@Vector(8, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_8_f32(); try expect(v[0] == 81); @@ -13349,7 +13576,6 @@ test "@Vector(12, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_12_f32(); try expect(v[0] == 121); @@ -13400,7 +13626,6 @@ test "@Vector(16, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_f32(); try expect(v[0] == 177); @@ -13466,7 +13691,6 @@ test "@Vector(24, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_f32(); try expect(v[0] == 257); @@ -13551,7 +13775,6 @@ test "@Vector(32, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_f32(); try expect(v[0] == 369); @@ -13661,7 +13884,6 @@ test "@Vector(48, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_f32(); try expect(v[0] == 529); @@ -13805,7 +14027,6 @@ test "@Vector(64, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_f32(); try expect(v[0] == 753); @@ -14000,7 +14221,6 @@ test "@Vector(96, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_96_f32(); try expect(v[0] == 1082); @@ -14263,7 +14483,6 @@ test "@Vector(128, f32)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_128_f32(); try expect(v[0] == 1530); @@ -14471,7 +14690,6 @@ test "@Vector(3, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_3_f64(); try expect(v[0] == 19); @@ -14500,8 +14718,6 @@ test "@Vector(4, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35899 const v = c_ret_vector_4_f64(); try expect(v[0] == 33); @@ -14534,7 +14750,6 @@ test "@Vector(6, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_6_f64(); try expect(v[0] == 53); @@ -14570,8 +14785,6 @@ test "@Vector(8, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35899 const v = c_ret_vector_8_f64(); try expect(v[0] == 81); @@ -14614,7 +14827,6 @@ test "@Vector(12, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_12_f64(); try expect(v[0] == 121); @@ -14665,7 +14877,6 @@ test "@Vector(16, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_16_f64(); try expect(v[0] == 177); @@ -14731,7 +14942,6 @@ test "@Vector(24, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_24_f64(); try expect(v[0] == 257); @@ -14816,7 +15026,6 @@ test "@Vector(32, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_32_f64(); try expect(v[0] == 369); @@ -14926,7 +15135,6 @@ test "@Vector(48, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_48_f64(); try expect(v[0] == 529); @@ -15070,7 +15278,6 @@ test "@Vector(64, f64)" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS32()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const v = c_ret_vector_64_f64(); try expect(v[0] == 753); @@ -15165,7 +15372,6 @@ extern fn c_test_struct_u8() void; test "struct u8" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u8(); @@ -15196,8 +15402,7 @@ test "struct u8, u8" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u8_u8(); @@ -15231,8 +15436,7 @@ test "struct u8, u8, u8" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u8_u8_u8(); @@ -15269,8 +15473,7 @@ test "struct u8, u8, u8, u8" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u8_u8_u8_u8(); @@ -15301,7 +15504,6 @@ extern fn c_test_struct_u16() void; test "struct u16" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u16(); @@ -15332,8 +15534,7 @@ test "struct u16, u16" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u16_u16(); @@ -15367,9 +15568,8 @@ test "struct u16, u16, u16" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u16_u16_u16(); @@ -15406,9 +15606,8 @@ test "struct u16, u16, u16, u16" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_u16_u16_u16_u16(); @@ -15439,7 +15638,6 @@ extern fn c_test_struct_u32() void; test "struct u32" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u32(); @@ -15469,9 +15667,8 @@ extern fn c_test_struct_u32_u32() void; test "struct u32, u32" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u32_u32(); @@ -15505,8 +15702,7 @@ test "struct u32, u32, u32" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u32_u32_u32(); try expect(s.a == 8); @@ -15542,8 +15738,7 @@ test "struct u32, u32, u32, u32" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u32_u32_u32_u32(); try expect(s.a == 10); @@ -15573,7 +15768,6 @@ extern fn c_test_struct_u64() void; test "struct u64" { if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_u64(); @@ -15651,7 +15845,6 @@ extern fn c_test_struct_u64_u64() void; test "struct u64, u64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const s = c_ret_struct_u64_u64(); try expect(s.a == 21); @@ -15691,8 +15884,7 @@ extern fn c_test_struct_u64_u64_u64() void; test "struct u64, u64, u64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u64_u64_u64(); try expect(s.a == 8); @@ -15727,8 +15919,7 @@ extern fn c_test_struct_u64_u64_u64_u64() void; test "struct u64, u64, u64, u64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u64_u64_u64_u64(); try expect(s.a == 10); @@ -15757,8 +15948,7 @@ extern fn c_test_struct_f32() void; test "struct f32" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_f32(); @@ -15791,7 +15981,6 @@ test "struct f32, f32" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_f32_f32(); @@ -15827,7 +16016,6 @@ test "struct f32, f32, f32" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const s = c_ret_struct_f32_f32_f32(); try expect(s.a == 8); @@ -15865,7 +16053,6 @@ test "struct f32, f32, f32, f32" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const s = c_ret_struct_f32_f32_f32_f32(); try expect(s.a == 10); @@ -15905,7 +16092,6 @@ test "struct f32, f32, f32, f32, f32" { if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const s = c_ret_struct_f32_f32_f32_f32_f32(); try expect(s.a == 12); @@ -15917,6 +16103,384 @@ test "struct f32, f32, f32, f32, f32" { c_test_struct_f32_f32_f32_f32_f32(); } +const Struct_void_f32 = extern struct { + _: void = {}, + a: f32, +}; + +export fn zig_ret_struct_void_f32() Struct_void_f32 { + return .{ .a = 1 }; +} +export fn zig_struct_void_f32(s: Struct_void_f32, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_void_f32() Struct_void_f32; +extern fn c_struct_void_f32(Struct_void_f32, usize) void; +extern fn c_test_struct_void_f32() void; + +test "struct void, f32" { + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; + + const s = c_ret_struct_void_f32(); + try expect(s.a == 4); + c_struct_void_f32(.{ .a = 5 }, 6); + c_test_struct_void_f32(); +} + +const Struct_array_1_f32 = extern struct { + a: [1]f32, +}; + +export fn zig_ret_struct_array_1_f32() Struct_array_1_f32 { + return .{ .a = .{1} }; +} +export fn zig_struct_array_1_f32(s: Struct_array_1_f32, i: usize) void { + expect(s.a[0] == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_1_f32() Struct_array_1_f32; +extern fn c_struct_array_1_f32(Struct_array_1_f32, usize) void; +extern fn c_test_struct_array_1_f32() void; + +test "struct [1]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + const s = c_ret_struct_array_1_f32(); + try expect(s.a[0] == 4); + c_struct_array_1_f32(.{ .a = .{5} }, 6); + c_test_struct_array_1_f32(); +} + +const Struct_array_2_f32 = extern struct { + a: [2]f32, +}; + +export fn zig_ret_struct_array_2_f32() Struct_array_2_f32 { + return .{ .a = .{ 1, 2 } }; +} +export fn zig_struct_array_2_f32(s: Struct_array_2_f32, i: usize) void { + expect(s.a[0] == 3) catch @panic("test failure"); + expect(s.a[1] == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_2_f32() Struct_array_2_f32; +extern fn c_struct_array_2_f32(Struct_array_2_f32, usize) void; +extern fn c_test_struct_array_2_f32() void; + +test "struct [2]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64 and builtin.abi.float() == .hard) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + const s = c_ret_struct_array_2_f32(); + try expect(s.a[0] == 6); + try expect(s.a[1] == 7); + c_struct_array_2_f32(.{ .a = .{ 8, 9 } }, 10); + c_test_struct_array_2_f32(); +} + +const Struct_array_3_f32 = extern struct { + a: [3]f32, +}; + +export fn zig_ret_struct_array_3_f32() Struct_array_3_f32 { + return .{ .a = .{ 1, 2, 3 } }; +} +export fn zig_struct_array_3_f32(s: Struct_array_3_f32, i: usize) void { + expect(s.a[0] == 4) catch @panic("test failure"); + expect(s.a[1] == 5) catch @panic("test failure"); + expect(s.a[2] == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_3_f32() Struct_array_3_f32; +extern fn c_struct_array_3_f32(Struct_array_3_f32, usize) void; +extern fn c_test_struct_array_3_f32() void; + +test "struct [3]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_3_f32(); + try expect(s.a[0] == 8); + try expect(s.a[1] == 9); + try expect(s.a[2] == 10); + c_struct_array_3_f32(.{ .a = .{ 11, 12, 13 } }, 14); + c_test_struct_array_3_f32(); +} + +const Struct_array_4_f32 = extern struct { + a: [4]f32, +}; + +export fn zig_ret_struct_array_4_f32() Struct_array_4_f32 { + return .{ .a = .{ 1, 2, 3, 4 } }; +} +export fn zig_struct_array_4_f32(s: Struct_array_4_f32, i: usize) void { + expect(s.a[0] == 5) catch @panic("test failure"); + expect(s.a[1] == 6) catch @panic("test failure"); + expect(s.a[2] == 7) catch @panic("test failure"); + expect(s.a[3] == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_4_f32() Struct_array_4_f32; +extern fn c_struct_array_4_f32(Struct_array_4_f32, usize) void; +extern fn c_test_struct_array_4_f32() void; + +test "struct [4]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_4_f32(); + try expect(s.a[0] == 10); + try expect(s.a[1] == 11); + try expect(s.a[2] == 12); + try expect(s.a[3] == 13); + c_struct_array_4_f32(.{ .a = .{ 14, 15, 16, 17 } }, 18); + c_test_struct_array_4_f32(); +} + +const Struct_array_5_f32 = extern struct { + a: [5]f32, +}; + +export fn zig_ret_struct_array_5_f32() Struct_array_5_f32 { + return .{ .a = .{ 1, 2, 3, 4, 5 } }; +} +export fn zig_struct_array_5_f32(s: Struct_array_5_f32, i: usize) void { + expect(s.a[0] == 6) catch @panic("test failure"); + expect(s.a[1] == 7) catch @panic("test failure"); + expect(s.a[2] == 8) catch @panic("test failure"); + expect(s.a[3] == 9) catch @panic("test failure"); + expect(s.a[4] == 10) catch @panic("test failure"); + expect(i == 11) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_5_f32() Struct_array_5_f32; +extern fn c_struct_array_5_f32(Struct_array_5_f32, usize) void; +extern fn c_test_struct_array_5_f32() void; + +test "struct [5]f32" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_5_f32(); + try expect(s.a[0] == 12); + try expect(s.a[1] == 13); + try expect(s.a[2] == 14); + try expect(s.a[3] == 15); + try expect(s.a[4] == 16); + c_struct_array_5_f32(.{ .a = .{ 17, 18, 19, 20, 21 } }, 22); + c_test_struct_array_5_f32(); +} + +const Struct_array_0_sentinel_f32 = extern struct { + a: [0:0x1e1]f32, +}; + +export fn zig_ret_struct_array_0_sentinel_f32() Struct_array_0_sentinel_f32 { + return .{ .a = .{} }; +} +export fn zig_struct_array_0_sentinel_f32(s: Struct_array_0_sentinel_f32, i: usize) void { + var sentinel_index: usize = 0; + _ = &sentinel_index; + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_0_sentinel_f32() Struct_array_0_sentinel_f32; +extern fn c_struct_array_0_sentinel_f32(Struct_array_0_sentinel_f32, usize) void; +extern fn c_test_struct_array_0_sentinel_f32() void; + +test "struct [0:sentinel]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + var sentinel_index: usize = 0; + _ = &sentinel_index; + const s = c_ret_struct_array_0_sentinel_f32(); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_0_sentinel_f32(.{ .a = .{} }, 2); + c_test_struct_array_0_sentinel_f32(); +} + +const Struct_array_1_sentinel_f32 = extern struct { + a: [1:0x1e1]f32, +}; + +export fn zig_ret_struct_array_1_sentinel_f32() Struct_array_1_sentinel_f32 { + return .{ .a = .{1} }; +} +export fn zig_struct_array_1_sentinel_f32(s: Struct_array_1_sentinel_f32, i: usize) void { + var sentinel_index: usize = 1; + _ = &sentinel_index; + expect(s.a[0] == 2) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_1_sentinel_f32() Struct_array_1_sentinel_f32; +extern fn c_struct_array_1_sentinel_f32(Struct_array_1_sentinel_f32, usize) void; +extern fn c_test_struct_array_1_sentinel_f32() void; + +test "struct [1:sentinel]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64 and builtin.abi.float() == .hard) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + var sentinel_index: usize = 1; + _ = &sentinel_index; + const s = c_ret_struct_array_1_sentinel_f32(); + try expect(s.a[0] == 4); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_1_sentinel_f32(.{ .a = .{5} }, 6); + c_test_struct_array_1_sentinel_f32(); +} + +const Struct_array_2_sentinel_f32 = extern struct { + a: [2:0x1e1]f32, +}; + +export fn zig_ret_struct_array_2_sentinel_f32() Struct_array_2_sentinel_f32 { + return .{ .a = .{ 1, 2 } }; +} +export fn zig_struct_array_2_sentinel_f32(s: Struct_array_2_sentinel_f32, i: usize) void { + var sentinel_index: usize = 2; + _ = &sentinel_index; + expect(s.a[0] == 3) catch @panic("test failure"); + expect(s.a[1] == 4) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_2_sentinel_f32() Struct_array_2_sentinel_f32; +extern fn c_struct_array_2_sentinel_f32(Struct_array_2_sentinel_f32, usize) void; +extern fn c_test_struct_array_2_sentinel_f32() void; + +test "struct [2:sentinel]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + var sentinel_index: usize = 2; + _ = &sentinel_index; + const s = c_ret_struct_array_2_sentinel_f32(); + try expect(s.a[0] == 6); + try expect(s.a[1] == 7); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_2_sentinel_f32(.{ .a = .{ 8, 9 } }, 10); + c_test_struct_array_2_sentinel_f32(); +} + +const Struct_array_3_sentinel_f32 = extern struct { + a: [3:0x1e1]f32, +}; + +export fn zig_ret_struct_array_3_sentinel_f32() Struct_array_3_sentinel_f32 { + return .{ .a = .{ 1, 2, 3 } }; +} +export fn zig_struct_array_3_sentinel_f32(s: Struct_array_3_sentinel_f32, i: usize) void { + var sentinel_index: usize = 3; + _ = &sentinel_index; + expect(s.a[0] == 4) catch @panic("test failure"); + expect(s.a[1] == 5) catch @panic("test failure"); + expect(s.a[2] == 6) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_3_sentinel_f32() Struct_array_3_sentinel_f32; +extern fn c_struct_array_3_sentinel_f32(Struct_array_3_sentinel_f32, usize) void; +extern fn c_test_struct_array_3_sentinel_f32() void; + +test "struct [3:sentinel]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + var sentinel_index: usize = 3; + _ = &sentinel_index; + const s = c_ret_struct_array_3_sentinel_f32(); + try expect(s.a[0] == 8); + try expect(s.a[1] == 9); + try expect(s.a[2] == 10); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_3_sentinel_f32(.{ .a = .{ 11, 12, 13 } }, 14); + c_test_struct_array_3_sentinel_f32(); +} + +const Struct_array_4_sentinel_f32 = extern struct { + a: [4:0x1e1]f32, +}; + +export fn zig_ret_struct_array_4_sentinel_f32() Struct_array_4_sentinel_f32 { + return .{ .a = .{ 1, 2, 3, 4 } }; +} +export fn zig_struct_array_4_sentinel_f32(s: Struct_array_4_sentinel_f32, i: usize) void { + var sentinel_index: usize = 4; + _ = &sentinel_index; + expect(s.a[0] == 5) catch @panic("test failure"); + expect(s.a[1] == 6) catch @panic("test failure"); + expect(s.a[2] == 7) catch @panic("test failure"); + expect(s.a[3] == 8) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_4_sentinel_f32() Struct_array_4_sentinel_f32; +extern fn c_struct_array_4_sentinel_f32(Struct_array_4_sentinel_f32, usize) void; +extern fn c_test_struct_array_4_sentinel_f32() void; + +test "struct [4:sentinel]f32" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + var sentinel_index: usize = 4; + _ = &sentinel_index; + const s = c_ret_struct_array_4_sentinel_f32(); + try expect(s.a[0] == 10); + try expect(s.a[1] == 11); + try expect(s.a[2] == 12); + try expect(s.a[3] == 13); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_4_sentinel_f32(.{ .a = .{ 14, 15, 16, 17 } }, 18); + c_test_struct_array_4_sentinel_f32(); +} + const Struct_f32a8 = extern struct { a: f32 align(8), }; @@ -15940,7 +16504,6 @@ test "struct f32 align(8)" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_f32a8(); @@ -15974,7 +16537,6 @@ test "struct f32 align(8), f32 align(8)" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = c_ret_struct_f32a8_f32a8(); @@ -16007,8 +16569,7 @@ test "struct {f32, f32}, f32" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f32f32_f32(); try expect(s.a.b == 1.0); @@ -16041,8 +16602,7 @@ test "struct f32, {f32, f32}" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f32_f32f32(); try expect(s.a == 1.0); @@ -16070,9 +16630,8 @@ extern fn c_test_struct_f64() void; test "struct f64" { if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s = c_ret_struct_f64(); @@ -16102,8 +16661,7 @@ extern fn c_test_struct_f64_f64() void; test "struct f64, f64" { if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f64_f64(); try expect(s.a == 6); @@ -16135,8 +16693,7 @@ extern fn c_test_struct_f64_f64_f64() void; test "struct f64, f64, f64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f64_f64_f64(); try expect(s.a == 8); @@ -16171,8 +16728,7 @@ extern fn c_test_struct_f64_f64_f64_f64() void; test "struct f64, f64, f64, f64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f64_f64_f64_f64(); try expect(s.a == 10); @@ -16210,8 +16766,7 @@ extern fn c_test_struct_f64_f64_f64_f64_f64() void; test "struct f64, f64, f64, f64, f64" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; const s = c_ret_struct_f64_f64_f64_f64_f64(); try expect(s.a == 12); @@ -16223,6 +16778,201 @@ test "struct f64, f64, f64, f64, f64" { c_test_struct_f64_f64_f64_f64_f64(); } +const Struct_array_1_f64 = extern struct { + a: [1]f64, +}; + +export fn zig_ret_struct_array_1_f64() Struct_array_1_f64 { + return .{ .a = .{1} }; +} +export fn zig_struct_array_1_f64(s: Struct_array_1_f64, i: usize) void { + expect(s.a[0] == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_1_f64() Struct_array_1_f64; +extern fn c_struct_array_1_f64(Struct_array_1_f64, usize) void; +extern fn c_test_struct_array_1_f64() void; + +test "struct [1]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + const s = c_ret_struct_array_1_f64(); + try expect(s.a[0] == 4); + c_struct_array_1_f64(.{ .a = .{5} }, 6); + c_test_struct_array_1_f64(); +} + +const Struct_array_2_f64 = extern struct { + a: [2]f64, +}; + +export fn zig_ret_struct_array_2_f64() Struct_array_2_f64 { + return .{ .a = .{ 1, 2 } }; +} +export fn zig_struct_array_2_f64(s: Struct_array_2_f64, i: usize) void { + expect(s.a[0] == 3) catch @panic("test failure"); + expect(s.a[1] == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_2_f64() Struct_array_2_f64; +extern fn c_struct_array_2_f64(Struct_array_2_f64, usize) void; +extern fn c_test_struct_array_2_f64() void; + +test "struct [2]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64 and builtin.abi.float() == .hard) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + const s = c_ret_struct_array_2_f64(); + try expect(s.a[0] == 6); + try expect(s.a[1] == 7); + c_struct_array_2_f64(.{ .a = .{ 8, 9 } }, 10); + c_test_struct_array_2_f64(); +} + +const Struct_array_3_f64 = extern struct { + a: [3]f64, +}; + +export fn zig_ret_struct_array_3_f64() Struct_array_3_f64 { + return .{ .a = .{ 1, 2, 3 } }; +} +export fn zig_struct_array_3_f64(s: Struct_array_3_f64, i: usize) void { + expect(s.a[0] == 4) catch @panic("test failure"); + expect(s.a[1] == 5) catch @panic("test failure"); + expect(s.a[2] == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_3_f64() Struct_array_3_f64; +extern fn c_struct_array_3_f64(Struct_array_3_f64, usize) void; +extern fn c_test_struct_array_3_f64() void; + +test "struct [3]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_3_f64(); + try expect(s.a[0] == 8); + try expect(s.a[1] == 9); + try expect(s.a[2] == 10); + c_struct_array_3_f64(.{ .a = .{ 11, 12, 13 } }, 14); + c_test_struct_array_3_f64(); +} + +const Struct_array_4_f64 = extern struct { + a: [4]f64, +}; + +export fn zig_ret_struct_array_4_f64() Struct_array_4_f64 { + return .{ .a = .{ 1, 2, 3, 4 } }; +} +export fn zig_struct_array_4_f64(s: Struct_array_4_f64, i: usize) void { + expect(s.a[0] == 5) catch @panic("test failure"); + expect(s.a[1] == 6) catch @panic("test failure"); + expect(s.a[2] == 7) catch @panic("test failure"); + expect(s.a[3] == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_4_f64() Struct_array_4_f64; +extern fn c_struct_array_4_f64(Struct_array_4_f64, usize) void; +extern fn c_test_struct_array_4_f64() void; + +test "struct [4]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_4_f64(); + try expect(s.a[0] == 10); + try expect(s.a[1] == 11); + try expect(s.a[2] == 12); + try expect(s.a[3] == 13); + c_struct_array_4_f64(.{ .a = .{ 14, 15, 16, 17 } }, 18); + c_test_struct_array_4_f64(); +} + +const Struct_array_5_f64 = extern struct { + a: [5]f64, +}; + +export fn zig_ret_struct_array_5_f64() Struct_array_5_f64 { + return .{ .a = .{ 1, 2, 3, 4, 5 } }; +} +export fn zig_struct_array_5_f64(s: Struct_array_5_f64, i: usize) void { + expect(s.a[0] == 6) catch @panic("test failure"); + expect(s.a[1] == 7) catch @panic("test failure"); + expect(s.a[2] == 8) catch @panic("test failure"); + expect(s.a[3] == 9) catch @panic("test failure"); + expect(s.a[4] == 10) catch @panic("test failure"); + expect(i == 11) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_5_f64() Struct_array_5_f64; +extern fn c_struct_array_5_f64(Struct_array_5_f64, usize) void; +extern fn c_test_struct_array_5_f64() void; + +test "struct [5]f64" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_5_f64(); + try expect(s.a[0] == 12); + try expect(s.a[1] == 13); + try expect(s.a[2] == 14); + try expect(s.a[3] == 15); + try expect(s.a[4] == 16); + c_struct_array_5_f64(.{ .a = .{ 17, 18, 19, 20, 21 } }, 22); + c_test_struct_array_5_f64(); +} + +const Union_f64 = extern union { + a: f64, +}; + +export fn zig_ret_union_f64() Union_f64 { + return .{ .a = 1 }; +} +export fn zig_union_f64(s: Union_f64, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_union_f64() Union_f64; +extern fn c_union_f64(Union_f64, usize) void; +extern fn c_test_union_f64() void; + +test "union f64" { + if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; + if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; + + const s = c_ret_union_f64(); + try expect(s.a == 4); + c_union_f64(.{ .a = 5 }, 6); + c_test_union_f64(); +} + const Struct_u32_Union_u32_u32u32 = extern struct { a: u32, b: extern union { @@ -16250,8 +17000,7 @@ test "struct{u32,union{u32,struct{u32,u32}}}" { if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = c_ret_struct_u32_union_u32_u32u32(); try expect(s.a == 1); @@ -16269,11 +17018,10 @@ extern fn c_mut_struct_i32_i32(Struct_i32_i32) Struct_i32_i32; extern fn c_struct_i32_i32(Struct_i32_i32) void; test "struct i32 i32" { + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const s: Struct_i32_i32 = .{ @@ -16303,11 +17051,10 @@ const BigStruct = extern struct { extern fn c_big_struct(BigStruct) void; test "big struct" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = BigStruct{ .a = 1, @@ -16333,10 +17080,9 @@ const BigUnion = extern union { extern fn c_big_union(BigUnion) void; test "big union" { - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const x = BigUnion{ .a = BigStruct{ @@ -16368,11 +17114,10 @@ extern fn c_med_struct_mixed(MedStructMixed) void; extern fn c_ret_med_struct_mixed() MedStructMixed; test "medium struct of ints and floats" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = MedStructMixed{ .a = 1234, @@ -16448,12 +17193,11 @@ const SplitStructInt = extern struct { extern fn c_split_struct_ints(SplitStructInt) void; test "split struct of ints" { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = SplitStructInt{ .a = 1234, @@ -16478,12 +17222,11 @@ extern fn c_split_struct_mixed(SplitStructMixed) void; extern fn c_ret_split_struct_mixed() SplitStructMixed; test "split struct of ints and floats" { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; const s = SplitStructMixed{ .a = 1234, @@ -16506,11 +17249,10 @@ export fn zig_split_struct_mixed(x: SplitStructMixed) void { extern fn c_big_struct_both(BigStruct) BigStruct; test "sret and byval together" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const s = BigStruct{ .a = 1, @@ -16620,12 +17362,11 @@ extern fn c_struct_with_array(StructWithArray) void; extern fn c_ret_struct_with_array() StructWithArray; test "Struct with array as padding." { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2 }); @@ -16649,11 +17390,10 @@ extern fn c_float_array_struct(FloatArrayStruct) void; extern fn c_ret_float_array_struct() FloatArrayStruct; test "Float array like struct" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; c_float_array_struct(.{ .origin = .{ @@ -16684,37 +17424,37 @@ pub inline fn expectOk(c_err: c_int) !void { /// Tests for Double + Char struct const DC = extern struct { v1: f64, v2: u8 }; test "DC: Zig passes to C" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_assert_DC(.{ .v1 = -0.25, .v2 = 15 })); } test "DC: Zig returns to C" { + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_assert_ret_DC()); } test "DC: C passes to Zig" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_send_DC()); } test "DC: C returns to Zig" { + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectEqual(DC{ .v1 = -0.25, .v2 = 15 }, c_ret_DC()); } @@ -16739,36 +17479,35 @@ const CFF = extern struct { v1: u8, v2: f32, v3: f32 }; test "CFF: Zig passes to C" { if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_assert_CFF(.{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 })); } test "CFF: Zig returns to C" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + try expectOk(c_assert_ret_CFF()); } test "CFF: C passes to Zig" { - if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch.isRISCV() and builtin.mode != .Debug) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV() and builtin.mode != .debug) return error.SkipZigTest; + if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; try expectOk(c_send_CFF()); } test "CFF: C returns to Zig" { - if (builtin.cpu.arch.isRISCV() and builtin.mode != .Debug) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV() and builtin.mode != .debug) return error.SkipZigTest; + try expectEqual(CFF{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 }, c_ret_CFF()); } pub extern fn c_assert_CFF(lv: CFF) c_int; @@ -16791,35 +17530,35 @@ pub export fn zig_ret_CFF() CFF { const PD = extern struct { v1: ?*anyopaque, v2: f64 }; test "PD: Zig passes to C" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; + try expectOk(c_assert_PD(.{ .v1 = null, .v2 = 0.5 })); } test "PD: Zig returns to C" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + try expectOk(c_assert_ret_PD()); } test "PD: C passes to Zig" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; + try expectOk(c_send_PD()); } test "PD: C returns to Zig" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; + try expectEqual(PD{ .v1 = null, .v2 = 0.5 }, c_ret_PD()); } pub extern fn c_assert_PD(lv: PD) c_int; @@ -16853,7 +17592,6 @@ extern fn c_modify_by_ref_param(ByRef) ByRef; test "C function modifies by ref param" { if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined }); try expect(res.val == 42); @@ -16874,11 +17612,10 @@ const ByVal = extern struct { extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void; test "C function that takes byval struct called via function pointer" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; var fn_ptr = &c_func_ptr_byval; _ = &fn_ptr; @@ -16897,17 +17634,16 @@ test "C function that takes byval struct called via function pointer" { extern fn c_f16(f16) f16; test "f16 bare" { - if (builtin.cpu.arch == .x86_64) return error.SkipZigTest; - if (builtin.cpu.arch == .x86) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - - if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) return error.SkipZigTest; + if (builtin.cpu.arch == .x86_64) return error.SkipZigTest; const a = c_f16(12); try expect(a == 34); @@ -16918,9 +17654,9 @@ const f16_struct = extern struct { }; extern fn c_f16_struct(f16_struct) f16_struct; test "f16 struct" { + if (builtin.cpu.arch.isArm() and builtin.mode != .debug) return error.SkipZigTest; if (builtin.target.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.target.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isArm() and builtin.mode != .Debug) return error.SkipZigTest; if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; @@ -17027,11 +17763,10 @@ const Coord2 = extern struct { extern fn stdcall_coord2(Coord2, Coord2, Coord2) callconv(stdcall_callconv) Coord2; test "Stdcall ABI structs" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; const res = stdcall_coord2( @@ -17045,10 +17780,9 @@ test "Stdcall ABI structs" { extern fn stdcall_big_union(BigUnion) callconv(stdcall_callconv) void; test "Stdcall ABI big union" { - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; const x = BigUnion{ .a = BigStruct{ @@ -17120,11 +17854,10 @@ const byval_tail_callsite_attr = struct { }; test "byval tail callsite attribute" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; // Originally reported at https://github.com/ziglang/zig/issues/16290 // the bug was that the extern function had the byval attribute, but @@ -17268,11 +18001,19 @@ test "x86 vectorcall calling convention" { static.c_vectorcall_check(1, 2.0, 3.0, @ptrFromInt(4), 5.0, 6.0, 7.0, 8.0, 9.0, 10); } +extern fn c_x86_64_sysv_uint_int_uint_int(a: u8, b: i8, c: u16, d: i16) void; + +test "x86_64 sysv args" { + if (std.lang.CallingConvention.c != .x86_64_sysv) return error.SkipZigTest; + + c_x86_64_sysv_uint_int_uint_int(1, -2, 3, -4); +} + extern fn c_win64_varargs_u64_f64_u64_f64(...) void; extern fn c_win64_varargs_f64_u64_f64_u64(...) void; test "win64 varargs" { - if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .windows) return error.SkipZigTest; + if (std.lang.CallingConvention.c != .x86_64_win) return error.SkipZigTest; const Opv = extern struct {}; c_win64_varargs_u64_f64_u64_f64( @@ -17298,3 +18039,25 @@ test "win64 varargs" { @as(Opv, .{}), ); } + +const preserve_none_cc: ?std.lang.CallingConvention = if (builtin.zig_backend != .stage2_llvm) + null +else switch (builtin.cpu.arch) { + .x86_64 => .{ .x86_64_preserve_none = .{} }, + .aarch64, .aarch64_be => .{ .aarch64_preserve_none = .{} }, + else => null, +}; + +export fn zig_preserve_none(x: i32) callconv(preserve_none_cc orelse .c) i32 { + return x + 1; +} + +test "preserve_none calling convention" { + if (preserve_none_cc == null) return error.SkipZigTest; + const static = struct { + extern fn c_preserve_none(x: i32) callconv(preserve_none_cc.?) i32; + extern fn c_preserve_none_check() void; + }; + try expect(static.c_preserve_none(41) == 42); + static.c_preserve_none_check(); +} diff --git a/test/cases/compile_errors/bad_panic_call_signature.zig b/test/cases/compile_errors/bad_panic_call_signature.zig index 6d88f1b8781c6db162037a42564cbe3fefc06179..fdfc8a8c3bad266235f5458dbe476bded279352c 100644 --- a/test/cases/compile_errors/bad_panic_call_signature.zig +++ b/test/cases/compile_errors/bad_panic_call_signature.zig @@ -15,6 +15,7 @@ pub const panic = struct { pub const castToNull = simple_panic.castToNull; pub const incorrectAlignment = simple_panic.incorrectAlignment; pub const invalidErrorCode = simple_panic.invalidErrorCode; + pub const unexpectedErrorCode = simple_panic.unexpectedErrorCode; pub const integerOutOfBounds = simple_panic.integerOutOfBounds; pub const integerOverflow = simple_panic.integerOverflow; pub const shlOverflow = simple_panic.shlOverflow; diff --git a/test/cases/compile_errors/bad_panic_generic_signature.zig b/test/cases/compile_errors/bad_panic_generic_signature.zig index 8ef4810745ce45855bad0262e1a1bef0ca5db414..0dba45036e36bb73e44c046a8a3b0a8dd645dab9 100644 --- a/test/cases/compile_errors/bad_panic_generic_signature.zig +++ b/test/cases/compile_errors/bad_panic_generic_signature.zig @@ -11,6 +11,7 @@ pub const panic = struct { pub const castToNull = simple_panic.castToNull; pub const incorrectAlignment = simple_panic.incorrectAlignment; pub const invalidErrorCode = simple_panic.invalidErrorCode; + pub const unexpectedErrorCode = simple_panic.unexpectedErrorCode; pub const integerOutOfBounds = simple_panic.integerOutOfBounds; pub const integerOverflow = simple_panic.integerOverflow; pub const shlOverflow = simple_panic.shlOverflow; diff --git a/test/cases/compile_errors/callconv_preserve_none_on_unsupported_platform.zig b/test/cases/compile_errors/callconv_preserve_none_on_unsupported_platform.zig new file mode 100644 index 0000000000000000000000000000000000000000..3997609595403f793e1aae1ac0f5c935e320a5c7 --- /dev/null +++ b/test/cases/compile_errors/callconv_preserve_none_on_unsupported_platform.zig @@ -0,0 +1,16 @@ +const F1 = fn () callconv(.{ .x86_64_preserve_none = .{} }) void; +const F2 = fn () callconv(.{ .aarch64_preserve_none = .{} }) void; +export fn entry1() void { + const a: F1 = undefined; + _ = a; +} +export fn entry2() void { + const a: F2 = undefined; + _ = a; +} + +// error +// target=riscv64-linux-none +// +// :1:28: error: calling convention 'x86_64_preserve_none' only available on architectures 'x86_64' +// :2:28: error: calling convention 'aarch64_preserve_none' only available on architectures 'aarch64', 'aarch64_be' diff --git a/test/cases/compile_errors/capture_by_ref_discard.zig b/test/cases/compile_errors/capture_by_ref_discard.zig index 1779936d34fc04ef7f29a275886b1e8e47635d10..c407ede6c9dc4ba9a1db6aea344e5b34d06d5871 100644 --- a/test/cases/compile_errors/capture_by_ref_discard.zig +++ b/test/cases/compile_errors/capture_by_ref_discard.zig @@ -16,9 +16,14 @@ export fn d() void { while (null) |*_| {} } +export fn e() void { + if (0) |*_| {} else |err| switch (err) {} +} + // error // // :2:16: error: pointer modifier invalid on discard // :7:18: error: pointer modifier invalid on discard // :12:16: error: pointer modifier invalid on discard // :16:19: error: pointer modifier invalid on discard +// :20:13: error: pointer modifier invalid on discard diff --git a/test/cases/compile_errors/coerce_pointers_with_uncoercable_child_pointers.zig b/test/cases/compile_errors/coerce_pointers_with_uncoercable_child_pointers.zig index bef21b2777ff5503899741f812dcbf7bc3b61b68..77f48e656c0a81c94353a555542a4b3e73ace4e8 100644 --- a/test/cases/compile_errors/coerce_pointers_with_uncoercable_child_pointers.zig +++ b/test/cases/compile_errors/coerce_pointers_with_uncoercable_child_pointers.zig @@ -28,6 +28,16 @@ export fn entry5() void { _ = q; } +export fn entry6(p: **[3]u8) void { + const q: *[]u8 = p; + _ = q; +} + +export fn entry7(p: *[]u8) void { + const q: **[3]u8 = p; + _ = q; +} + // error // // :3:22: error: expected type '**i32', found '**u32' @@ -50,3 +60,7 @@ export fn entry5() void { // :27:24: note: pointer type child '*[1:42]u8' cannot cast into pointer type child '*[1]u8' // :27:24: note: pointer type child '[1:42]u8' cannot cast into pointer type child '[1]u8' // :27:24: note: source array cannot be guaranteed to maintain '42' sentinel +// :32:22: error: expected type '*[]u8', found '**[3]u8' +// :32:22: note: pointer type child '*[3]u8' cannot cast into pointer type child '[]u8' +// :37:24: error: expected type '**[3]u8', found '*[]u8' +// :37:24: note: pointer type child '[]u8' cannot cast into pointer type child '*[3]u8' diff --git a/test/cases/compile_errors/coercion_from_vector_element_to_c_ptr.zig b/test/cases/compile_errors/coercion_from_vector_element_to_c_ptr.zig new file mode 100644 index 0000000000000000000000000000000000000000..8bf69016a6a8e0c7e51ef50f84dd632f9232037e --- /dev/null +++ b/test/cases/compile_errors/coercion_from_vector_element_to_c_ptr.zig @@ -0,0 +1,11 @@ +export fn foo() void { + var size: @Vector(4, c_int) = undefined; + bar(&size[0]); +} +extern fn bar([*c]c_int) void; + +// error +// +// 3:9: error: expected type '[*c]c_int', found '*align(4:0:4:0) c_int' +// 3:9: note: pointer host size '4' cannot cast into pointer host size '0' +// 5:15: note: parameter type declared here diff --git a/test/cases/compile_errors/deref_slice_and_get_len_field.zig b/test/cases/compile_errors/deref_slice_and_get_len_field.zig index 57459f488eca026cb7a4f27bc82d7d2ef13e4c5b..8917259ccbce1c5c31d13ae9722cc38d6fb7b03f 100644 --- a/test/cases/compile_errors/deref_slice_and_get_len_field.zig +++ b/test/cases/compile_errors/deref_slice_and_get_len_field.zig @@ -6,4 +6,4 @@ export fn entry() void { // error // -// :3:10: error: index syntax required for slice type '[]u8' +// :3:10: error: index syntax required to access runtime-known slice diff --git a/test/cases/compile_errors/deref_slice_with_undef_len.zig b/test/cases/compile_errors/deref_slice_with_undef_len.zig new file mode 100644 index 0000000000000000000000000000000000000000..e3dcd2e158719cff1b14213c5b1cc2c05ef333e4 --- /dev/null +++ b/test/cases/compile_errors/deref_slice_with_undef_len.zig @@ -0,0 +1,23 @@ +export fn entry2() void { + comptime var slice: []const u16 = &.{ 1, 2, 3 }; + slice.len = undefined; + _ = slice.*; +} + +export fn entry3() void { + comptime var slice: []const u16 = &.{ 1, 2, 3 }; + slice.len = undefined; + _ = &slice.*; +} + +export fn entry4() void { + comptime var slice: []const u8 = "hello"; + slice.len = undefined; + @compileError(slice); +} + +// error +// +// :4:14: error: cannot dereference slice with undefined length +// :10:15: error: cannot dereference slice with undefined length +// :16:19: error: use of slice with undefined length here causes illegal behavior diff --git a/test/cases/compile_errors/dereference_slice.zig b/test/cases/compile_errors/dereference_slice.zig index e2221ea609bf5c36a0304360dabd2e35aedd998f..73db0ff950e63718421846e645aba6ac7f19a23f 100644 --- a/test/cases/compile_errors/dereference_slice.zig +++ b/test/cases/compile_errors/dereference_slice.zig @@ -7,4 +7,4 @@ comptime { // error // -// :2:13: error: index syntax required for slice type '[]i32' +// :2:13: error: index syntax required to access runtime-known slice diff --git a/test/cases/compile_errors/duplicate_boolean_switch_value.zig b/test/cases/compile_errors/duplicate_boolean_switch_value.zig index d3b7dba6e88e77e75b01861d691d02da4f9847e6..700851ec77b1c9dc6d10eb0cd9f37f1aa0a69bcb 100644 --- a/test/cases/compile_errors/duplicate_boolean_switch_value.zig +++ b/test/cases/compile_errors/duplicate_boolean_switch_value.zig @@ -17,7 +17,7 @@ comptime { // error // -// :5:9: error: duplicate switch value +// :5:9: error: duplicate switch value 'true' // :3:9: note: previous value here -// :13:9: error: duplicate switch value +// :13:9: error: duplicate switch value 'false' // :11:9: note: previous value here diff --git a/test/cases/compile_errors/duplicate_error_in_switch.zig b/test/cases/compile_errors/duplicate_error_in_switch.zig index 91f6f13c7ea158195da1aa16993f7982f9ef010f..6a2da7672e1d0851b975858e414c333313fb93fd 100644 --- a/test/cases/compile_errors/duplicate_error_in_switch.zig +++ b/test/cases/compile_errors/duplicate_error_in_switch.zig @@ -16,5 +16,5 @@ fn foo(x: i32) !void { // error // -// :5:9: error: duplicate switch value +// :5:9: error: duplicate switch value 'error.Foo' // :3:9: note: previous value here diff --git a/test/cases/compile_errors/ignored_deferred_function_call.zig b/test/cases/compile_errors/ignored_deferred_function_call.zig index 9980128f90de825fe1dc542d35357cea925db948..63a7f489f1b01fedbfdf6354a6a87671ddd7bb20 100644 --- a/test/cases/compile_errors/ignored_deferred_function_call.zig +++ b/test/cases/compile_errors/ignored_deferred_function_call.zig @@ -14,6 +14,6 @@ fn bar2() anyerror { // error // -// :2:14: error: error union is ignored +// :2:14: error: error union of type 'anyerror!i32' is ignored // :2:14: note: consider using 'try', 'catch', or 'if' -// :9:15: error: error set is ignored +// :9:15: error: error set of type 'anyerror' is ignored diff --git a/test/cases/compile_errors/ignored_expression_in_while_continuation.zig b/test/cases/compile_errors/ignored_expression_in_while_continuation.zig index 4d4441fa9bc9309e03ce43fbb5ac52a90a478f62..79553e16049c44e30f11a1eb587120843693e79a 100644 --- a/test/cases/compile_errors/ignored_expression_in_while_continuation.zig +++ b/test/cases/compile_errors/ignored_expression_in_while_continuation.zig @@ -24,10 +24,10 @@ fn bad2() anyerror { // error // -// :2:24: error: error union is ignored +// :2:24: error: error union of type 'anyerror!void' is ignored // :2:24: note: consider using 'try', 'catch', or 'if' -// :7:25: error: error union is ignored +// :7:25: error: error union of type 'anyerror!void' is ignored // :7:25: note: consider using 'try', 'catch', or 'if' -// :12:25: error: error union is ignored +// :12:25: error: error union of type 'anyerror!void' is ignored // :12:25: note: consider using 'try', 'catch', or 'if' -// :19:25: error: error set is ignored +// :19:25: error: error set of type 'anyerror' is ignored diff --git a/test/cases/compile_errors/initialize_empty_union.zig b/test/cases/compile_errors/initialize_empty_union.zig index a7945a105b6d973411f6d2e31810ae6e5f7e595e..fe8203c1ed1873c2c4634eae13ab177ea079474d 100644 --- a/test/cases/compile_errors/initialize_empty_union.zig +++ b/test/cases/compile_errors/initialize_empty_union.zig @@ -28,25 +28,6 @@ export fn init5() void { _ = @as(U5, undefined); } -export fn deref0(ptr: *const U0) void { - _ = ptr.*; -} -export fn deref1(ptr: *const U1) void { - _ = ptr.*; -} -export fn deref2(ptr: *const U2) void { - _ = ptr.*; -} -export fn deref3(ptr: *const U3) void { - _ = ptr.*; -} -export fn deref4(ptr: *const U4) void { - _ = ptr.*; -} -export fn deref5(ptr: *const U5) void { - _ = ptr.*; -} - // error // // :13:17: error: expected type 'tmp.U0', found '@TypeOf(undefined)' @@ -67,15 +48,3 @@ export fn deref5(ptr: *const U5) void { // :28:17: error: expected type 'tmp.U5', found '@TypeOf(undefined)' // :28:17: note: cannot coerce to uninstantiable type 'tmp.U5' // :10:12: note: union declared here -// :32:12: error: cannot load uninstantiable type 'tmp.U0' -// :5:12: note: union declared here -// :35:12: error: cannot load uninstantiable type 'tmp.U1' -// :6:12: note: union declared here -// :38:12: error: cannot load uninstantiable type 'tmp.U2' -// :7:12: note: union declared here -// :41:12: error: cannot load uninstantiable type 'tmp.U3' -// :8:12: note: union declared here -// :44:12: error: cannot load uninstantiable type 'tmp.U4' -// :9:12: note: union declared here -// :47:12: error: cannot load uninstantiable type 'tmp.U5' -// :10:12: note: union declared here diff --git a/test/cases/compile_errors/invalid_float_casts.zig b/test/cases/compile_errors/invalid_float_casts.zig index f6d077d8a0d370618f41e04c6e63c51f8c11908c..cc2039cea3b05d2c72d9bd09807bb75ab4b79701 100644 --- a/test/cases/compile_errors/invalid_float_casts.zig +++ b/test/cases/compile_errors/invalid_float_casts.zig @@ -22,6 +22,6 @@ export fn qux() void { // error // // :4:40: error: unable to cast runtime value to 'comptime_float' -// :9:18: error: expected integer type, found 'f32' +// :9:18: error: expected integer result type, found 'f32' // :14:32: error: expected integer type, found 'f32' // :19:29: error: expected float or vector type, found 'u32' diff --git a/test/cases/compile_errors/invalid_int_casts.zig b/test/cases/compile_errors/invalid_int_casts.zig index b2c542d0f7697ac0543b4a59ff05bacfd5ca5693..479390c5c3fb9303b5b76968d5b9b8d6d1367f96 100644 --- a/test/cases/compile_errors/invalid_int_casts.zig +++ b/test/cases/compile_errors/invalid_int_casts.zig @@ -8,6 +8,9 @@ export fn bar() void { _ = &a; _ = @as(u32, @floatFromInt(a)); } +export fn bar2() void { + _ = @as(comptime_int, @floatFromInt(2)); +} export fn baz() void { var a: u32 = 2; _ = &a; @@ -22,6 +25,7 @@ export fn qux() void { // error // // :4:36: error: unable to cast runtime value to 'comptime_int' -// :9:18: error: expected float type, found 'u32' -// :14:32: error: expected float type, found 'u32' -// :19:27: error: expected integer or vector, found 'f32' +// :9:18: error: expected float result type, found 'u32' +// :12:27: error: expected float result type, found 'comptime_int' +// :17:32: error: expected float type, found 'u32' +// :22:27: error: expected integer or vector, found 'f32' diff --git a/test/cases/compile_errors/invalid_member_of_builtin_enum.zig b/test/cases/compile_errors/invalid_member_of_builtin_enum.zig index 48f1012c1f6884d6a34c2255edd9e2924743c1b1..9902f027bf45c5db93744caa8242194df29a3f41 100644 --- a/test/cases/compile_errors/invalid_member_of_builtin_enum.zig +++ b/test/cases/compile_errors/invalid_member_of_builtin_enum.zig @@ -6,5 +6,5 @@ export fn entry() void { // error // -// :3:35: error: enum 'lang.OptimizeMode' has no member named 'x86' +// :3:35: error: enum 'lang.Optimize' has no member named 'x86' // : note: enum declared here diff --git a/test/cases/compile_errors/slice_to_array_pointer.zig b/test/cases/compile_errors/slice_to_array_pointer.zig new file mode 100644 index 0000000000000000000000000000000000000000..9e4750a3645820240e505ab6d471be99d18877cc --- /dev/null +++ b/test/cases/compile_errors/slice_to_array_pointer.zig @@ -0,0 +1,70 @@ +export fn entry1() void { + var array: [2]u16 = .{ 1, 2 }; + const slice: []const u16 = &array; + foo(slice); +} + +export fn entry2() void { + const slice: []const u16 = undefined; + foo(slice); +} + +export fn entry3() void { + comptime var slice: []const u16 = &.{ 1, 2 }; + slice.len = undefined; + foo(slice); +} + +export fn entry4() void { + const slice: []const u16 = &.{ 1, 2, 3 }; + foo(slice); +} + +export fn entry5() void { + const slice: []const u8 = &.{ 1, 2 }; + foo(slice); +} + +fn foo(x: *const [2]u16) void { + _ = x; +} + +export fn entry6() void { + const slice: [:0]const u16 = &.{ 1, 2, 3 }; + bar(slice); +} + +export fn entry7() void { + const slice: [:1]const u16 = &.{ 1, 2 }; + bar(slice); +} + +export fn entry8() void { + const slice: []const u16 = &.{ 1, 2 }; + bar(slice); +} + +fn bar(x: *const [2:0]u16) void { + _ = x; +} + +// error +// +// :4:9: error: coercion from slice to array pointer type '*const [2]u16' requires length to be known at compile-time +// :9:9: error: slice with undefined length cannot cast into array pointer type '*const [2]u16' +// :9:9: note: length of slice must be defined and match length of array type +// :15:9: error: slice with undefined length cannot cast into array pointer type '*const [2]u16' +// :15:9: note: length of slice must be defined and match length of array type +// :20:9: error: slice of length 3 cannot cast into array pointer type '*const [2]u16' +// :20:9: note: length of slice must match length of array type +// :25:9: error: expected type '*const [2]u16', found '[]const u8' +// :25:9: note: pointer type child 'u8' cannot cast into pointer type child 'u16' +// :28:11: note: parameter type declared here +// :34:9: error: slice of length 3 cannot cast into array pointer type '*const [2:0]u16' +// :34:9: note: length of slice must match length of array type +// :39:9: error: expected type '*const [2:0]u16', found '[:1]const u16' +// :39:9: note: pointer sentinel '1' cannot cast into pointer sentinel '0' +// :47:11: note: parameter type declared here +// :44:9: error: expected type '*const [2:0]u16', found '[]const u16' +// :44:9: note: destination pointer requires '0' sentinel +// :47:11: note: parameter type declared here diff --git a/test/cases/compile_errors/switch_expression-duplicate_enumeration_prong.zig b/test/cases/compile_errors/switch_expression-duplicate_enumeration_prong.zig index 754451321c91d75d0d465e18d475ff08bae9865a..5c69bd922f2011cc900c50e891e4ee387a49b47f 100644 --- a/test/cases/compile_errors/switch_expression-duplicate_enumeration_prong.zig +++ b/test/cases/compile_errors/switch_expression-duplicate_enumeration_prong.zig @@ -20,5 +20,6 @@ export fn entry() usize { // error // -// :13:15: error: duplicate switch value +// :13:15: error: duplicate switch value '.Two' // :10:15: note: previous value here +// :1:16: note: enum declared here diff --git a/test/cases/compile_errors/switch_expression-duplicate_enumeration_prong_when_else_present.zig b/test/cases/compile_errors/switch_expression-duplicate_enumeration_prong_when_else_present.zig index 3cba599968fd15a1abdc9b64e1fd4fb984bd363b..24627b6282194defe031d9db2693026b8c381984 100644 --- a/test/cases/compile_errors/switch_expression-duplicate_enumeration_prong_when_else_present.zig +++ b/test/cases/compile_errors/switch_expression-duplicate_enumeration_prong_when_else_present.zig @@ -21,5 +21,6 @@ export fn entry() usize { // error // -// :13:15: error: duplicate switch value +// :13:15: error: duplicate switch value '.Two' // :10:15: note: previous value here +// :1:16: note: enum declared here diff --git a/test/cases/compile_errors/switch_expression-duplicate_error_prong.zig b/test/cases/compile_errors/switch_expression-duplicate_error_prong.zig index 1ee6add616cc0c0546a0b9f3833ed13072eb0d65..3df559cf03a73bae9f06d6c84642952e805a1a5e 100644 --- a/test/cases/compile_errors/switch_expression-duplicate_error_prong.zig +++ b/test/cases/compile_errors/switch_expression-duplicate_error_prong.zig @@ -25,7 +25,7 @@ export fn entry() usize { // error // -// :8:9: error: duplicate switch value +// :8:9: error: duplicate switch value 'error.Foo' // :5:9: note: previous value here -// :16:9: error: duplicate switch value +// :16:9: error: duplicate switch value 'error.Foo' // :13:9: note: previous value here diff --git a/test/cases/compile_errors/switch_expression-duplicate_error_prong_when_else_present.zig b/test/cases/compile_errors/switch_expression-duplicate_error_prong_when_else_present.zig index 38ae0099b3e4a240a4bd8940e472b5d64985089f..d21e144704131ac2b6921e7cc0337c053487b96f 100644 --- a/test/cases/compile_errors/switch_expression-duplicate_error_prong_when_else_present.zig +++ b/test/cases/compile_errors/switch_expression-duplicate_error_prong_when_else_present.zig @@ -27,7 +27,7 @@ export fn entry() usize { // error // -// :8:9: error: duplicate switch value +// :8:9: error: duplicate switch value 'error.Foo' // :5:9: note: previous value here -// :17:9: error: duplicate switch value +// :17:9: error: duplicate switch value 'error.Foo' // :14:9: note: previous value here diff --git a/test/cases/compile_errors/switch_expression-duplicate_or_overlapping_integer_value.zig b/test/cases/compile_errors/switch_expression-duplicate_or_overlapping_integer_value.zig deleted file mode 100644 index d970393450d1399b985ead356f5f21a138561850..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/switch_expression-duplicate_or_overlapping_integer_value.zig +++ /dev/null @@ -1,16 +0,0 @@ -fn foo(x: u8) u8 { - return switch (x) { - 0...100 => @as(u8, 0), - 101...200 => 1, - 201, 203...207 => 2, - 206...255 => 3, - }; -} -export fn entry() usize { - return @sizeOf(@TypeOf(&foo)); -} - -// error -// -// :6:12: error: duplicate switch value -// :5:17: note: previous value here diff --git a/test/cases/compile_errors/switch_expression-duplicate_type.zig b/test/cases/compile_errors/switch_expression-duplicate_type.zig index 4b553989808cb04e52dba2b2207bced6b8f090bc..7b8f277480b71bf708eba135896f5d61f48ad1b5 100644 --- a/test/cases/compile_errors/switch_expression-duplicate_type.zig +++ b/test/cases/compile_errors/switch_expression-duplicate_type.zig @@ -13,5 +13,5 @@ export fn entry() usize { // error // -// :6:9: error: duplicate switch value +// :6:9: error: duplicate switch value 'u32' // :4:9: note: previous value here diff --git a/test/cases/compile_errors/switch_expression-duplicate_type_struct_alias.zig b/test/cases/compile_errors/switch_expression-duplicate_type_struct_alias.zig index 0b67e2107d452df6a4e19a11a3ed7d8f6c8e6f64..f2919239c82c3a68d459b686c33a35f027f36f32 100644 --- a/test/cases/compile_errors/switch_expression-duplicate_type_struct_alias.zig +++ b/test/cases/compile_errors/switch_expression-duplicate_type_struct_alias.zig @@ -17,5 +17,6 @@ export fn entry() usize { // error // -// :10:9: error: duplicate switch value +// :10:9: error: duplicate switch value 'tmp.Test' // :8:9: note: previous value here +// :1:14: note: struct declared here diff --git a/test/cases/compile_errors/switch_on_invalid_type.zig b/test/cases/compile_errors/switch_on_invalid_type.zig new file mode 100644 index 0000000000000000000000000000000000000000..8d10d75a66c4b4f082bc83628cbc741090ff8428 --- /dev/null +++ b/test/cases/compile_errors/switch_on_invalid_type.zig @@ -0,0 +1,103 @@ +const AutoUnion = union { a: u8 }; +export fn entry1() void { + switch (@as(AutoUnion, .{ .a = 123 })) { + else => {}, + } +} + +const ExternUnion = union { a: u8 }; +export fn entry2() void { + switch (@as(ExternUnion, .{ .a = 123 })) { + else => {}, + } +} + +const AutoStruct = struct { a: u8 }; +export fn entry3() void { + switch (@as(AutoStruct, .{ .a = 123 })) { + else => {}, + } +} + +const ExternStruct = extern struct { a: u8 }; +export fn entry4() void { + switch (@as(ExternStruct, .{ .a = 123 })) { + else => {}, + } +} + +export fn entry5() void { + switch (@as([]const u16, &.{ 1, 2, 3 })) { + else => {}, + } +} + +export fn entry6() void { + switch (@as([3]u16, .{ 1, 2, 3 })) { + else => {}, + } +} + +export fn entry7() void { + switch (@as(@Vector(3, u16), .{ 1, 2, 3 })) { + else => {}, + } +} + +export fn entry8() void { + switch (@as(?u16, 123)) { + else => {}, + } +} + +export fn entry9() void { + switch (@as(anyerror!u16, 123)) { + else => {}, + } +} + +export fn entry10() void { + switch (@as(f32, 123)) { + else => {}, + } +} + +export fn entry11() void { + switch (@as(comptime_float, 123)) { + else => {}, + } +} + +export fn entry12() void { + switch (undefined) { + else => {}, + } +} + +export fn entry13() void { + switch (null) { + else => {}, + } +} + +// error +// +// :3:13: error: switch on union with no attached enum +// :1:19: note: consider 'union(enum)' here +// :10:13: error: switch on union with no attached enum +// :8:21: note: consider 'union(enum)' here +// :17:13: error: switch on non-packed struct +// :15:20: note: struct declared here +// :24:13: error: switch on non-packed struct +// :22:29: note: struct declared here +// :30:13: error: switch on type '[]const u16' +// :36:13: error: switch on type '[3]u16' +// :42:13: error: switch on type '@Vector(3, u16)' +// :48:13: error: switch on optional type '?u16' +// :48:13: note: consider using '.?', 'orelse', or 'if' +// :54:13: error: switch on error union type 'anyerror!u16' +// :54:13: note: consider using 'try', 'catch', or 'if' +// :60:13: error: switch on type 'f32' +// :66:13: error: switch on type 'comptime_float' +// :72:13: error: switch on type '@TypeOf(undefined)' +// :78:13: error: switch on type '@TypeOf(null)' diff --git a/test/cases/compile_errors/switch_on_non_packed_struct.zig b/test/cases/compile_errors/switch_on_non_packed_struct.zig deleted file mode 100644 index ef17bb3ca533361c38f1cb9caae5b391c1f4ab54..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/switch_on_non_packed_struct.zig +++ /dev/null @@ -1,25 +0,0 @@ -const Auto = struct { - a: u8, -}; -export fn entry1(a: u8) void { - const s: Auto = .{ .a = a }; - switch (s) { - else => {}, - } -} - -const Extern = extern struct { - a: u8, -}; -export fn entry2(s: Extern) void { - switch (s) { - else => {}, - } -} - -// error -// -// :6:13: error: switch on struct with auto layout -// :1:14: note: consider 'packed struct' here -// :15:13: error: switch on struct with extern layout -// :11:23: note: consider 'packed struct' here diff --git a/test/cases/compile_errors/switch_on_union_with_nonexhaustive_tag_is_exhaustive.zig b/test/cases/compile_errors/switch_on_union_with_nonexhaustive_tag_is_exhaustive.zig new file mode 100644 index 0000000000000000000000000000000000000000..fc289fb55fb2c7fb0db1dd990fea16f431509595 --- /dev/null +++ b/test/cases/compile_errors/switch_on_union_with_nonexhaustive_tag_is_exhaustive.zig @@ -0,0 +1,56 @@ +const E = enum(u8) { + a, + b, + _, +}; +const U = union(E) { + a, + b, +}; +fn foo() U { + return undefined; +} + +export fn entry1() void { + const u = foo(); + switch (u) { + .a => {}, + } +} +export fn entry2() void { + const u = foo(); + switch (u) { + .a => {}, + .b => {}, + else => {}, + } +} +export fn entry3() void { + const u = foo(); + switch (u) { + .a => {}, + .b => {}, + _ => {}, + } +} +export fn entry4() void { + const u = foo(); + switch (u) { + .a => {}, + else => {}, + _ => {}, + } +} + +// error +// +// :16:5: error: switch must handle all possibilities +// :3:5: note: unhandled enumeration value: 'b' +// :1:11: note: enum 'tmp.E' declared here +// :25:14: error: unreachable else prong; all cases already handled +// :30:5: error: '_' prong only allowed when switching on non-exhaustive enums +// :33:9: note: '_' prong here +// :30:5: note: consider using 'else' +// :38:5: error: '_' prong only allowed when switching on non-exhaustive enums +// :41:9: note: '_' prong here +// :38:5: note: consider using 'else' diff --git a/test/cases/compile_errors/switch_with_overlapping_case_ranges.zig b/test/cases/compile_errors/switch_with_overlapping_case_ranges.zig index 619875c7970ba869cb84ac43cdd1f0789724ec4f..6d7ffc0e1c9728c0c9ea5ac788263945d156c823 100644 --- a/test/cases/compile_errors/switch_with_overlapping_case_ranges.zig +++ b/test/cases/compile_errors/switch_with_overlapping_case_ranges.zig @@ -28,13 +28,43 @@ export fn entry4(x: u8) void { } } +export fn entry5(x: u8) void { + switch (x) { + 0...255 => {}, + 4...120 => {}, + } +} + +export fn entry6(x: u8) void { + switch (x) { + 0...130 => {}, + 120...255 => {}, + } +} + +export fn entry7(x: u8) void { + switch (x) { + 2 => {}, + 0...255 => {}, + } +} + // error // -// :4:10: error: duplicate switch value -// :3:10: note: previous value here -// :11:10: error: duplicate switch value -// :10:13: note: previous value here -// :17:10: error: duplicate switch value +// :4:10: error: duplicate switch ranges +// :3:10: note: overlaps with previous range here +// :3:10: note: ranges overlap from '1' to '2' +// :11:10: error: duplicate switch value '5' +// :10:13: note: previous value inside range here +// :17:10: error: duplicate switch value '5' // :18:9: note: previous value here -// :27:10: error: duplicate switch value +// :27:10: error: duplicate switch value '6' // :26:9: note: previous value here +// :34:10: error: duplicate switch ranges +// :33:10: note: overlaps with previous range here +// :33:10: note: ranges overlap from '4' to '120' +// :41:12: error: duplicate switch ranges +// :40:10: note: overlaps with previous range here +// :40:10: note: ranges overlap from '120' to '130' +// :48:10: error: duplicate switch value '2' +// :47:9: note: previous value here diff --git a/test/cases/safety/@errorCast error not present in destination.zig b/test/cases/safety/@errorCast error not present in destination.zig index 3ae83186023587a707594a45f89e723c338265c9..2e0e4f22538db11499f89cc82b996ff20a582c34 100644 --- a/test/cases/safety/@errorCast error not present in destination.zig +++ b/test/cases/safety/@errorCast error not present in destination.zig @@ -2,7 +2,7 @@ const std = @import("std"); pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; - if (std.mem.eql(u8, message, "invalid error code")) { + if (std.mem.eql(u8, message, "unexpected error code, found error.B")) { std.process.exit(0); } std.process.exit(1); diff --git a/test/cases/safety/@errorCast error union casted to disjoint set.zig b/test/cases/safety/@errorCast error union casted to disjoint set.zig index 0bf9311be764390a109d85f146868a1ab6a5b265..2f8238698a8afee3d9cdd7ba05f0f274b05b6241 100644 --- a/test/cases/safety/@errorCast error union casted to disjoint set.zig +++ b/test/cases/safety/@errorCast error union casted to disjoint set.zig @@ -2,7 +2,7 @@ const std = @import("std"); pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; - if (std.mem.eql(u8, message, "invalid error code")) { + if (std.mem.eql(u8, message, "unexpected error code, found error.Bar")) { std.process.exit(0); } std.process.exit(1); diff --git a/test/cases/safety/load_uninstantiable_enum.zig b/test/cases/safety/load_uninstantiable_enum.zig new file mode 100644 index 0000000000000000000000000000000000000000..91a26417b689a0f06ae1ed1462bffdab5366cd30 --- /dev/null +++ b/test/cases/safety/load_uninstantiable_enum.zig @@ -0,0 +1,20 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const E = enum {}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const E = @ptrCast(&bytes); + _ = ptr.*; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/cases/safety/load_uninstantiable_enum_from_slice.zig b/test/cases/safety/load_uninstantiable_enum_from_slice.zig new file mode 100644 index 0000000000000000000000000000000000000000..57c308f8f6b15ca4f61eb36a3da0c246b6831dd8 --- /dev/null +++ b/test/cases/safety/load_uninstantiable_enum_from_slice.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const E = enum {}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]E = @ptrCast(&bytes); + const slice: []const E = ptr; + _ = slice[0]; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/cases/safety/load_uninstantiable_union.zig b/test/cases/safety/load_uninstantiable_union.zig new file mode 100644 index 0000000000000000000000000000000000000000..87f84e07c7f624104d797b94037fc6148491265b --- /dev/null +++ b/test/cases/safety/load_uninstantiable_union.zig @@ -0,0 +1,23 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const U = union { + foo: struct { a: u8, b: noreturn, }, + bar: enum {}, +}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const U = @ptrCast(&bytes); + _ = ptr.*; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/cases/safety/load_uninstantiable_union_from_slice.zig b/test/cases/safety/load_uninstantiable_union_from_slice.zig new file mode 100644 index 0000000000000000000000000000000000000000..844bfd0b7d766bfb9e5eb0f911061eda7bace0d6 --- /dev/null +++ b/test/cases/safety/load_uninstantiable_union_from_slice.zig @@ -0,0 +1,24 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const U = union { + foo: struct { a: u8, b: noreturn, }, + bar: enum {}, +}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]U = @ptrCast(&bytes); + const slice: []const U = ptr; + _ = slice[0]; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/error_traces.zig b/test/error_traces.zig index 071e4e8df53b7f017f988f6759db5adc30cebef0..5f84202fcfa5268094a5b625c10e30cda2bc3725 100644 --- a/test/error_traces.zig +++ b/test/error_traces.zig @@ -1,7 +1,10 @@ const std = @import("std"); +const Context = @import("tests.zig").ErrorTracesContext; -pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.Os.Tag) void { +pub fn addCases(cases: *Context, params: *const Context.CaseParameters, target: *const std.Target) void { cases.addCase(.{ + .params = params, + .target = target, .name = "return", .source = \\pub fn main() !void { @@ -17,6 +20,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try return", .source = \\fn foo() !void { @@ -44,6 +49,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }, }); cases.addCase(.{ + .params = params, + .target = target, .name = "non-error return pops error trace", .source = \\fn bar() !void { @@ -70,6 +77,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "continue in while loop", .source = \\fn foo() !void { @@ -93,6 +102,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "for loop pops error return trace", .source = \\fn foo() !void { return error.FooError; } @@ -123,6 +134,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "implicit continue in for loop pops stale error return trace", .source = \\fn foo() !void { return error.FooError; } @@ -154,6 +167,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "while loop pops error return trace", .source = \\fn foo() !void { return error.FooError; } @@ -186,6 +201,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "implicit continue in while loop pops stale error return trace", .source = \\fn foo() !void { return error.FooError; } @@ -219,6 +236,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try return + handled catch/if-else", .source = \\fn foo() !void { @@ -251,6 +270,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "break from inline loop pops error return trace", .source = \\fn foo() !void { return error.FooBar; } @@ -276,6 +297,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "catch and re-throw error", .source = \\fn foo() !void { @@ -304,6 +327,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "errors stored in var do not contribute to error trace", .source = \\fn foo() !void { @@ -328,6 +353,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "error stored in const has trace preserved for duration of block", .source = \\fn foo() !void { return error.TheSkyIsFalling; } @@ -376,6 +403,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "error passed to function has its trace preserved for duration of the call", .source = \\pub fn expectError(expected_error: anyerror, actual_error: anyerror!void) !void { @@ -418,6 +447,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try return from within catch", .source = \\fn foo() !void { @@ -455,6 +486,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try return from within if-else", .source = \\fn foo() !void { @@ -492,6 +525,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try try return return", .source = \\fn foo() !void { @@ -534,6 +569,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "error union switch with call operand", .source = \\pub fn main() !void { @@ -579,6 +616,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "trace through inline call", // The main function has two inline calls to ensure // that inlinees in PDBs are properly deduplicated. @@ -595,7 +634,7 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. \\} , .expect_error = "ThisIsSoSad", - .expect_trace = switch (os) { + .expect_trace = switch (target.os.tag) { // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs, // so our expected result is slightly different for Windows than on other operating // systems. diff --git a/test/incremental/change_panic_handler_explicit b/test/incremental/change_panic_handler_explicit index 662d13847f9800553b41fca4e9545e3bc07dbb17..3735cfd86c0116ce130481c56f60d6816174d00f 100644 --- a/test/incremental/change_panic_handler_explicit +++ b/test/incremental/change_panic_handler_explicit @@ -23,6 +23,7 @@ pub const panic = struct { pub const castToNull = no_panic.castToNull; pub const incorrectAlignment = no_panic.incorrectAlignment; pub const invalidErrorCode = no_panic.invalidErrorCode; + pub const unexpectedErrorCode = no_panic.unexpectedErrorCode; pub const integerOutOfBounds = no_panic.integerOutOfBounds; pub const shlOverflow = no_panic.shlOverflow; pub const shrOverflow = no_panic.shrOverflow; @@ -36,6 +37,7 @@ pub const panic = struct { pub const copyLenMismatch = no_panic.copyLenMismatch; pub const memcpyAlias = no_panic.memcpyAlias; pub const noreturnReturned = no_panic.noreturnReturned; + pub const loadUninstantiableType = no_panic.loadUninstantiableType; }; fn myPanic(msg: []const u8, _: ?usize) noreturn { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); @@ -71,6 +73,7 @@ pub const panic = struct { pub const castToNull = no_panic.castToNull; pub const incorrectAlignment = no_panic.incorrectAlignment; pub const invalidErrorCode = no_panic.invalidErrorCode; + pub const unexpectedErrorCode = no_panic.unexpectedErrorCode; pub const integerOutOfBounds = no_panic.integerOutOfBounds; pub const shlOverflow = no_panic.shlOverflow; pub const shrOverflow = no_panic.shrOverflow; @@ -84,6 +87,7 @@ pub const panic = struct { pub const copyLenMismatch = no_panic.copyLenMismatch; pub const memcpyAlias = no_panic.memcpyAlias; pub const noreturnReturned = no_panic.noreturnReturned; + pub const loadUninstantiableType = no_panic.loadUninstantiableType; }; fn myPanic(msg: []const u8, _: ?usize) noreturn { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); @@ -119,6 +123,7 @@ pub const panic = struct { pub const castToNull = no_panic.castToNull; pub const incorrectAlignment = no_panic.incorrectAlignment; pub const invalidErrorCode = no_panic.invalidErrorCode; + pub const unexpectedErrorCode = no_panic.unexpectedErrorCode; pub const integerOutOfBounds = no_panic.integerOutOfBounds; pub const shlOverflow = no_panic.shlOverflow; pub const shrOverflow = no_panic.shrOverflow; @@ -132,6 +137,7 @@ pub const panic = struct { pub const copyLenMismatch = no_panic.copyLenMismatch; pub const memcpyAlias = no_panic.memcpyAlias; pub const noreturnReturned = no_panic.noreturnReturned; + pub const loadUninstantiableType = no_panic.loadUninstantiableType; }; fn myPanicNew(msg: []const u8, _: ?usize) noreturn { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); diff --git a/test/incremental/temporary_analysis_error_in_generic_signature b/test/incremental/temporary_analysis_error_in_generic_signature new file mode 100644 index 0000000000000000000000000000000000000000..d8db72050b3af1164a312e1e7a1ed1f89bfc3dae --- /dev/null +++ b/test/incremental/temporary_analysis_error_in_generic_signature @@ -0,0 +1,46 @@ +#update=initial version +#file=main.zig +//! The original repro here depends on re-analysis order, which depends on +//! declaration order, so this exact declaration order must be used. +const Foo = struct { x: u8 }; +pub fn main(init: std.process.Init) !void { + const c = bar('Z').x; + try std.Io.File.stdout().writeStreamingAll(init.io, &.{ c, '\n' }); +} +fn bar(comptime x: u8) @This().Foo { + return .{ .x = x }; +} +const std = @import("std"); +#expect_stdout="Z\n" + +#update=change generic signature to use non-existent member +#file=main.zig +//! The original repro here depends on re-analysis order, which depends on +//! declaration order, so this exact declaration order must be used. +const Foo = struct { x: u8 }; +pub fn main(init: std.process.Init) !void { + const c = bar('Z').x; + try std.Io.File.stdout().writeStreamingAll(init.io, &.{ c, '\n' }); +} +fn bar(comptime x: u8) @This().FooAlias { + return .{ .x = x }; +} +const std = @import("std"); +#expect_error=main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias' +#expect_error=main.zig:1:1: note: struct declared here + +#update=add that member, fixing the error +#file=main.zig +//! The original repro here depends on re-analysis order, which depends on +//! declaration order, so this exact declaration order must be used. +const Foo = struct { x: u8 }; +const FooAlias = Foo; +pub fn main(init: std.process.Init) !void { + const c = bar('Z').x; + try std.Io.File.stdout().writeStreamingAll(init.io, &.{ c, '\n' }); +} +fn bar(comptime x: u8) @This().FooAlias { + return .{ .x = x }; +} +const std = @import("std"); +#expect_stdout="Z\n" diff --git a/test/llvm_ir.zig b/test/llvm_ir.zig index 32221d82878f48be7159a28404dfe3719650c6d9..7949ddab0d19abb763440cdca0d5112cef974da9 100644 --- a/test/llvm_ir.zig +++ b/test/llvm_ir.zig @@ -116,6 +116,26 @@ pub fn addCases(cases: *tests.LlvmIrContext) void { "null_pointer_is_valid", "store i16 42, ptr", }, .{}); + + cases.addMatches("load and store bool", + \\export fn foo(a: *bool, b: *align(2) bool) void { + \\ const tmp = a.*; + \\ a.* = b.*; + \\ b.* = tmp; + \\} + , &.{ + // TODO: this should all be one multiline string literal, but `-femit-llvm-ir` is currently + // emitting CRLF on Windows, which is a pain to handle here. In future that option will emit + // unoptimized LLVM IR emitted directly from Zig, so that bug will go away. + " %3 = load i8, ptr %0, align 1", + " %4 = trunc nuw i8 %3 to i1", + " %5 = load i8, ptr %1, align 2", + " %6 = trunc nuw i8 %5 to i1", + " %7 = zext i1 %6 to i8", + " store i8 %7, ptr %0, align 1", + " %8 = zext i1 %4 to i8", + " store i8 %8, ptr %1, align 2", + }, .{ .strip = true }); } const std = @import("std"); diff --git a/test/llvm_targets.zig b/test/llvm_targets.zig index 480adbcdafe6031de71b9ee42b8d9899c1faf72d..101c56df41624bd92404ddcb47c390eceeacc8e0 100644 --- a/test/llvm_targets.zig +++ b/test/llvm_targets.zig @@ -106,9 +106,9 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .lanai, .os_tag = .freestanding, .abi = .none }, .{ .cpu_arch = .loongarch32, .os_tag = .freestanding, .abi = .none }, - // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnu }, + .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnu }, // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnuf32 }, - // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnusf }, + .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnusf }, // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .musl }, // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .muslf32 }, // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .muslsf }, diff --git a/test/src/Cases.zig b/test/src/Cases.zig index af5dcfdddd6fd1c7671f88ff812637bfbcdfd794..c629f42381afb196a4621d6530ba106e788b52b3 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -491,7 +491,7 @@ pub fn lowerToBuildSteps( for (self.cases.items) |case| { for (options.test_filters) |test_filter| { - if (std.mem.indexOf(u8, case.name, test_filter)) |_| break; + if (std.mem.find(u8, case.name, test_filter)) |_| break; } else if (options.test_filters.len > 0) continue; if (case.case.? == .Error and options.skip_compile_errors) continue; @@ -524,7 +524,7 @@ pub fn lowerToBuildSteps( if (options.test_target_filters.len > 0) { for (options.test_target_filters) |filter| { - if (std.mem.indexOf(u8, triple_txt, filter) != null) break; + if (std.mem.find(u8, triple_txt, filter) != null) break; } else continue; } diff --git a/test/src/Debugger.zig b/test/src/Debugger.zig index b951e3c86595302d1ee16101f4f810bcaf21ab24..0e20799f3949884c437bbd39931c29f93a41d5b5 100644 --- a/test/src/Debugger.zig +++ b/test/src/Debugger.zig @@ -2384,13 +2384,13 @@ fn addTest( ) void { if (db.options.test_filters.len > 0) { for (db.options.test_filters) |test_filter| { - if (std.mem.indexOf(u8, name, test_filter) != null) break; + if (std.mem.find(u8, name, test_filter) != null) break; } else return; } if (db.options.test_target_filters.len > 0) { const triple_txt = target.resolved.query.zigTriple(db.b.allocator) catch @panic("OOM"); for (db.options.test_target_filters) |filter| { - if (std.mem.indexOf(u8, triple_txt, filter) != null) break; + if (std.mem.find(u8, triple_txt, filter) != null) break; } else return; } const files_wf = db.b.addWriteFiles(); diff --git a/test/src/ErrorTrace.zig b/test/src/ErrorTrace.zig index f6f80f8b138d2f7a663b4fe1d5d8d58bc8ef43de..7fda389dc6c295a6c950f95a6551945eab878643 100644 --- a/test/src/ErrorTrace.zig +++ b/test/src/ErrorTrace.zig @@ -1,11 +1,81 @@ +const ErrorTrace = @This(); + +const builtin = @import("builtin"); + +const std = @import("std"); +const Step = std.Build.Step; +const OptimizeMode = std.lang.Optimize; +const mem = std.mem; + +const error_traces_cases = @import("../error_traces.zig"); + b: *std.Build, step: *Step, test_filters: []const []const u8, -targets: []const std.Build.ResolvedTarget, +skip_non_native: bool, optimize_modes: []const OptimizeMode, convert_exe: *std.Build.Step.Compile, +pub const CaseParameters = @import("StackTrace.zig").CaseParameters; + +const param_sets = [_]CaseParameters{ + .{}, + .{ + .link_libc = true, + }, + .{ + .use_llvm = true, + .use_lld = true, + }, + .{ + .pie = true, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .windows, + .abi = .msvc, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86, + .os_tag = .windows, + .abi = .msvc, + }, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .macos, + }, + }, + .{ + .target = .{ + .cpu_arch = .s390x, + .os_tag = .linux, + .abi = .none, + }, + }, + .{ + .target = .{ + .cpu_arch = .loongarch32, + .os_tag = .linux, + .abi = .none, + }, + }, +}; + pub const Case = struct { + params: *const CaseParameters, + target: *const std.Target, name: []const u8, source: []const u8, expect_error: []const u8, @@ -22,50 +92,47 @@ pub const Case = struct { pub const Backend = enum { llvm, selfhosted }; }; -pub fn addCase(self: *ErrorTrace, case: Case) void { - for (self.targets) |*target| { - const triple: ?[]const u8 = if (target.query.isNative()) null else t: { - break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM"); - }; +pub fn addCases(self: *ErrorTrace) void { + const b = self.b; + + for (¶m_sets) |*params| { + const resolved_target = b.resolveTargetQuery(params.target); + + if (self.skip_non_native and !resolved_target.query.isNative()) continue; + + // To avoid redundant testing, skip cross-compilation targets matching the host. + if (resolved_target.result.os.tag == builtin.target.os.tag and + resolved_target.result.cpu.arch == builtin.target.cpu.arch) + { + continue; + } + for (self.optimize_modes) |optimize| { - self.addCaseConfig(case, target, triple, optimize, .llvm); - } - if (shouldTestNonLlvm(&target.result)) { - for (self.optimize_modes) |optimize| { - self.addCaseConfig(case, target, triple, optimize, .selfhosted); - } - } + if (optimize == params.optimize) break; + } else return; + + error_traces_cases.addCases(self, params, &resolved_target.result); } } -fn shouldTestNonLlvm(target: *const std.Target) bool { - if (comptime builtin.cpu.arch.endian() == .big) return false; // https://github.com/ziglang/zig/issues/25961 - return switch (target.cpu.arch) { - .x86_64 => switch (target.ofmt) { - .elf => !target.os.tag.isBSD() and target.os.tag != .illumos, - else => false, - }, - else => false, - }; -} - -fn addCaseConfig( - self: *ErrorTrace, - case: Case, - target: *const std.Build.ResolvedTarget, - triple: ?[]const u8, - optimize: OptimizeMode, - backend: Case.Backend, -) void { +/// Called from test/error_traces.zig +pub fn addCase(self: *ErrorTrace, case: Case) void { const b = self.b; + const params = case.params; + const target = case.target; + const target_query = params.target; + + const triple: ?[]const u8 = if (target_query.isNative()) null else t: { + break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM"); + }; const error_tracing: bool = tracing: { - if (optimize == .Debug) break :tracing true; - if (backend != .llvm) break :tracing true; - if (optimize == .ReleaseSmall) break :tracing false; + if (params.optimize == .debug) break :tracing true; + if (params.use_llvm == false) break :tracing true; + if (params.optimize == .small) break :tracing false; for (case.disable_trace_optimized) |disable| { const d_arch, const d_os = disable; - if (target.result.cpu.arch == d_arch and target.result.os.tag == d_os) { + if (target.cpu.arch == d_arch and target.os.tag == d_os) { // This particular configuration cannot do error tracing in optimized LLVM builds. break :tracing false; } @@ -73,16 +140,23 @@ fn addCaseConfig( break :tracing true; }; - const annotated_case_name = b.fmt("check {s} ({s}{s}{s} {s})", .{ + const backend_string = if (params.use_llvm == true) + "-llvm" + else if (params.use_llvm == false) + "-selfhosted" + else + ""; + + const annotated_case_name = b.fmt("check {s} ({s}{s}{t}{s})", .{ case.name, triple orelse "", if (triple != null) " " else "", - @tagName(optimize), - @tagName(backend), + params.optimize, + backend_string, }); if (self.test_filters.len > 0) { for (self.test_filters) |test_filter| { - if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + if (mem.find(u8, annotated_case_name, test_filter)) |_| break; } else return; } @@ -92,19 +166,18 @@ fn addCaseConfig( .name = "test", .root_module = b.createModule(.{ .root_source_file = source_zig, - .optimize = optimize, - .target = target.*, + .optimize = params.optimize, + .target = .{ .result = target.*, .query = target_query }, .error_tracing = error_tracing, .strip = false, }), - .use_llvm = switch (backend) { - .llvm => true, - .selfhosted => false, - }, + .use_llvm = params.use_llvm, + .use_lld = params.use_lld, }); exe.bundle_ubsan_rt = false; const run = b.addRunArtifact(exe); + run.skip_foreign_checks = true; run.removeEnvironmentVariable("CLICOLOR_FORCE"); run.setEnvironmentVariable("NO_COLOR", "1"); run.expectExitCode(1); @@ -116,16 +189,10 @@ fn addCaseConfig( }; const check_run = b.addRunArtifact(self.convert_exe); + check_run.skip_foreign_checks = true; check_run.setName(annotated_case_name); check_run.addFileArg(run.captureStdErr(.{})); check_run.expectStdOutEqual(expected_stderr); self.step.dependOn(&check_run.step); } - -const ErrorTrace = @This(); -const std = @import("std"); -const builtin = @import("builtin"); -const Step = std.Build.Step; -const OptimizeMode = std.builtin.OptimizeMode; -const mem = std.mem; diff --git a/test/src/Libc.zig b/test/src/Libc.zig index d2113893325821c63a441eba99ea06f1a4610402..12a4468b1f6d33b7494d7fb87b43636533e8ed90 100644 --- a/test/src/Libc.zig +++ b/test/src/Libc.zig @@ -49,7 +49,7 @@ pub fn addTarget(libc: *const Libc, target: std.Build.ResolvedTarget) void { if (libc.options.test_target_filters.len > 0) { const triple_txt = target.query.zigTriple(libc.b.allocator) catch @panic("OOM"); for (libc.options.test_target_filters) |filter| { - if (std.mem.indexOf(u8, triple_txt, filter)) |_| break; + if (std.mem.find(u8, triple_txt, filter)) |_| break; } else return; } @@ -82,7 +82,7 @@ pub fn addTarget(libc: *const Libc, target: std.Build.ResolvedTarget) void { const annotated_case_name = libc.b.fmt("run libc-test {s} ({t})", .{ test_case.name, optimize }); for (libc.options.test_filters) |test_filter| { - if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + if (std.mem.find(u8, annotated_case_name, test_filter)) |_| break; } else if (libc.options.test_filters.len > 0) continue; const mod = libc.b.createModule(.{ diff --git a/test/src/Link.zig b/test/src/Link.zig index 0c64ae5648333aabf1bfc56090d929341772294c..f0266923e34a380c1e5547c3f180b2d6febbe71c 100644 --- a/test/src/Link.zig +++ b/test/src/Link.zig @@ -8,7 +8,7 @@ use_lld: bool, link_libc: bool, test_filters: []const []const u8, update_step: ?*Step.UpdateSourceFiles, -updated_snapshots: std.StringArrayHashMapUnmanaged(void), +updated_snapshots: std.array_hash_map.String(void), max_rss: usize, pub fn includeTest(self: *Link, prefix: []const u8) ?Case { diff --git a/test/src/LlvmIr.zig b/test/src/LlvmIr.zig index 310d6426188bba216465b9c0ea126946c47cf9ca..fc0fddeb32f4893af6b38d1ef80c780fdae4676f 100644 --- a/test/src/LlvmIr.zig +++ b/test/src/LlvmIr.zig @@ -77,14 +77,14 @@ pub fn addCase(self: *LlvmIr, case: TestCase) void { if (self.options.test_target_filters.len > 0) { const triple_txt = target.query.zigTriple(self.b.allocator) catch @panic("OOM"); for (self.options.test_target_filters) |filter| { - if (std.mem.indexOf(u8, triple_txt, filter) != null) break; + if (std.mem.find(u8, triple_txt, filter) != null) break; } else return; } const name = std.fmt.allocPrint(self.b.allocator, "check llvm-ir {s}", .{case.name}) catch @panic("OOM"); if (self.options.test_filters.len > 0) { for (self.options.test_filters) |filter| { - if (std.mem.indexOf(u8, name, filter) != null) break; + if (std.mem.find(u8, name, filter) != null) break; } else return; } diff --git a/test/src/RunTranslatedC.zig b/test/src/RunTranslatedC.zig index 74e059cc599f9cb3edac29c1562b5b6d3adc2551..7d147aeceacf88c2658230ef0d48a7e7ae166bb2 100644 --- a/test/src/RunTranslatedC.zig +++ b/test/src/RunTranslatedC.zig @@ -68,7 +68,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void { const annotated_case_name = fmt.allocPrint(self.b.allocator, "run-translated-c {s}", .{case.name}) catch unreachable; for (self.test_filters) |test_filter| { - if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + if (mem.find(u8, annotated_case_name, test_filter)) |_| break; } else if (self.test_filters.len > 0) return; const write_src = b.addWriteFiles(); diff --git a/test/src/StackTrace.zig b/test/src/StackTrace.zig index a10b70fe280d5594a853e2ca37238891d9af41ff..c4e4a5fe391a4141fe167681183b761c8fbf806b 100644 --- a/test/src/StackTrace.zig +++ b/test/src/StackTrace.zig @@ -1,10 +1,91 @@ +const StackTrace = @This(); + +const builtin = @import("builtin"); + +const std = @import("std"); +const Step = std.Build.Step; +const OptimizeMode = std.lang.Optimize; +const mem = std.mem; + +const stack_traces_cases = @import("../stack_traces.zig"); + b: *std.Build, step: *Step, test_filters: []const []const u8, -targets: []const std.Build.ResolvedTarget, +skip_non_native: bool, convert_exe: *std.Build.Step.Compile, +pub const CaseParameters = struct { + target: std.Target.Query = .{}, + optimize: std.builtin.OptimizeMode = .debug, + link_libc: ?bool = null, + use_llvm: ?bool = null, + use_lld: ?bool = null, + pie: ?bool = null, + /// To enable this coverage, one of two things needs to happen: + /// * The compiler needs to gain the ability to strip only debug info (not symbols) + /// * `std.Build.Step.ObjCopy` needs to be un-regressed + strip: ?bool = false, +}; + +const param_sets = [_]CaseParameters{ + .{}, + .{ + .link_libc = true, + }, + .{ + .use_llvm = true, + .use_lld = true, + }, + .{ + .pie = true, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .windows, + .abi = .msvc, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86, + .os_tag = .windows, + .abi = .msvc, + }, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .macos, + }, + }, + .{ + .target = .{ + .cpu_arch = .s390x, + .os_tag = .linux, + .abi = .none, + }, + }, + .{ + .target = .{ + .cpu_arch = .loongarch32, + .os_tag = .linux, + .abi = .none, + }, + }, +}; + const Config = struct { + params: *const CaseParameters, + target: *const std.Target, name: []const u8, source: []const u8, /// Whether this test case expects to have unwind tables / frame pointers. @@ -26,42 +107,37 @@ const Config = struct { expect_strip: []const u8, }; +pub fn addCases(self: *StackTrace) void { + const b = self.b; + + for (¶m_sets) |*params| { + const resolved_target = b.resolveTargetQuery(params.target); + + if (self.skip_non_native and !resolved_target.query.isNative()) continue; + + // To avoid redundant testing, skip cross-compilation targets matching the host. + if (resolved_target.result.os.tag == builtin.target.os.tag and + resolved_target.result.cpu.arch == builtin.target.cpu.arch) + { + continue; + } + + stack_traces_cases.addCases(self, params, &resolved_target.result); + } +} + +/// Called from test/stack_traces.zig pub fn addCase(self: *StackTrace, config: Config) void { - for (self.targets) |*target| { - addCaseTarget( - self, - config, - target, - if (target.query.isNative()) null else t: { - break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM"); - }, - ); - } -} -fn addCaseTarget( - self: *StackTrace, - config: Config, - target: *const std.Build.ResolvedTarget, - triple: ?[]const u8, -) void { - const both_backends = b: { - if (comptime builtin.cpu.arch.endian() == .big) break :b false; // https://github.com/ziglang/zig/issues/25961 - break :b switch (target.result.cpu.arch) { - .x86_64 => switch (target.result.ofmt) { - .elf => !target.result.os.tag.isBSD() and target.result.os.tag != .illumos, - else => false, - }, - else => false, - }; + const params = config.params; + const target = config.target; + const target_query = config.params.target; + + const triple: ?[]const u8 = if (target_query.isNative()) null else t: { + break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM"); }; - const both_pie = switch (target.result.os.tag) { - .fuchsia => false, - else => true, - }; - const both_libc = !std.os.targetRequiresLibC(&target.result); // See `std.debug.StackIterator.fp_usability` logic. - const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.result.cpu.arch) { + const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.cpu.arch) { .alpha, .csky, .microblaze, @@ -83,20 +159,15 @@ fn addCaseTarget( .sparc, .sparc64, => .ideal, - .aarch64 => if (target.result.os.tag.isDarwin()) .safe else .unsafe, + .aarch64 => if (target.os.tag.isDarwin()) .safe else .unsafe, else => .unsafe, }; - const supports_unwind_tables = switch (target.result.os.tag) { + const supports_unwind_tables = switch (target.os.tag) { // x86-windows just has no way to do stack unwinding other then using frame pointers. - .windows => target.result.cpu.arch != .x86, + .windows => target.cpu.arch != .x86, else => true, }; - const use_llvm_vals: []const bool = if (both_backends) &.{ true, false } else &.{true}; - const pie_vals: []const ?bool = if (both_pie) &.{ true, false } else &.{null}; - const link_libc_vals: []const ?bool = if (both_libc) &.{ true, false } else &.{null}; - const strip_debug_vals: []const bool = &.{ true, false }; - const UnwindInfo = packed struct(u2) { tables: bool, fp: bool, @@ -126,43 +197,33 @@ fn addCaseTarget( }, }; - for (use_llvm_vals) |use_llvm| { - for (pie_vals) |pie| { - for (link_libc_vals) |link_libc| { - for (strip_debug_vals) |strip_debug| { - for (unwind_info_vals) |unwind_info| { - if (unwind_info.tables and !supports_unwind_tables) continue; - self.addCaseInstance( - target, - triple, - config.name, - config.source, - use_llvm, - pie, - link_libc, - strip_debug, - !unwind_info.tables and supports_unwind_tables, - !unwind_info.fp, - config.expect_panic, - if (strip_debug) config.expect_strip else config.expect, - ); - } - } - } - } + for (unwind_info_vals) |unwind_info| { + if (unwind_info.tables and !supports_unwind_tables) continue; + const strip = params.strip orelse switch (params.optimize) { + .debug, .fast, .safe => false, + .small => true, + }; + self.addCaseInstance( + .{ .result = target.*, .query = target_query }, + triple, + config.name, + config.source, + params, + !unwind_info.tables and supports_unwind_tables, + !unwind_info.fp, + config.expect_panic, + if (strip) config.expect_strip else config.expect, + ); } } fn addCaseInstance( self: *StackTrace, - target: *const std.Build.ResolvedTarget, + resolved_target: std.Build.ResolvedTarget, triple: ?[]const u8, name: []const u8, source: []const u8, - use_llvm: bool, - pie: ?bool, - link_libc: ?bool, - strip_debug: bool, + params: *const CaseParameters, strip_unwind: bool, omit_frame_pointer: bool, expect_panic: bool, @@ -170,13 +231,6 @@ fn addCaseInstance( ) void { const b = self.b; - if (strip_debug) { - // To enable this coverage, one of two things needs to happen: - // * The compiler needs to gain the ability to strip only debug info (not symbols) - // * `std.Build.Step.ObjCopy` needs to be un-regressed - return; - } - if (strip_unwind) { // To enable this coverage, `std.Build.Step.ObjCopy` needs to be un-regressed and gain the // ability to remove individual sections. `-fno-unwind-tables` is insufficient because it @@ -187,20 +241,34 @@ fn addCaseInstance( return; } + const backend_string = if (params.use_llvm == true) + " llvm" + else if (params.use_llvm == false) + " selfhosted" + else + ""; + + const strip_string = if (params.strip == true) + " strip" + else if (params.strip == false) + " unstripped" + else + ""; + const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s})", .{ name, triple orelse "", if (triple != null) " " else "", - if (use_llvm) "llvm" else "selfhosted", - if (pie == true) " pie" else "", - if (link_libc == true) " libc" else "", - if (strip_debug) " strip" else "", + backend_string, + if (params.pie == true) " pie" else "", + if (params.link_libc == true) " libc" else "", + strip_string, if (strip_unwind) " no_unwind" else "", if (omit_frame_pointer) " no_fp" else "", }); if (self.test_filters.len > 0) { for (self.test_filters) |test_filter| { - if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + if (mem.find(u8, annotated_case_name, test_filter)) |_| break; } else return; } @@ -211,24 +279,26 @@ fn addCaseInstance( .root_module = b.createModule(.{ .root_source_file = source_zig, .optimize = .Debug, - .target = target.*, + .target = resolved_target, .omit_frame_pointer = omit_frame_pointer, - .link_libc = link_libc, + .link_libc = params.link_libc, .unwind_tables = if (strip_unwind) .none else null, // make panics single-threaded so that they don't include a thread ID .single_threaded = expect_panic, }), - .use_llvm = use_llvm, + .use_llvm = params.use_llvm, + .use_lld = params.use_lld, }); - exe.pie = pie; + exe.pie = params.pie; exe.bundle_ubsan_rt = false; const run = b.addRunArtifact(exe); + run.skip_foreign_checks = true; run.removeEnvironmentVariable("CLICOLOR_FORCE"); run.setEnvironmentVariable("NO_COLOR", "1"); run.addCheck(.{ .expect_term = term: { if (!expect_panic) break :term .{ .exited = 0 }; - if (target.result.os.tag == .windows) break :term .{ .exited = 3 }; + if (resolved_target.result.os.tag == .windows) break :term .{ .exited = 3 }; break :term .{ .signal = @fromBackingInt(@intCast(6)) }; } }); run.expectStdOutEqual(""); @@ -241,10 +311,3 @@ fn addCaseInstance( self.step.dependOn(&check_run.step); } - -const StackTrace = @This(); -const std = @import("std"); -const builtin = @import("builtin"); -const Step = std.Build.Step; -const OptimizeMode = std.builtin.OptimizeMode; -const mem = std.mem; diff --git a/test/src/TranslateC.zig b/test/src/TranslateC.zig index 57aaea6e0cacf946fc9d351eb9a7db04e4bd407d..c8cc4e3fd009f3dd3f983d042549b45b7da6e571 100644 --- a/test/src/TranslateC.zig +++ b/test/src/TranslateC.zig @@ -90,7 +90,7 @@ pub fn addCase(self: *TranslateCContext, case: *const TestCase) void { const translate_c_cmd = "translate-c"; const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s}", .{ translate_c_cmd, case.name }) catch unreachable; for (self.test_filters) |test_filter| { - if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + if (mem.find(u8, annotated_case_name, test_filter)) |_| break; } else if (self.test_filters.len > 0) return; const target = b.resolveTargetQuery(case.target); @@ -99,7 +99,7 @@ pub fn addCase(self: *TranslateCContext, case: *const TestCase) void { const triple_txt = target.query.zigTriple(b.allocator) catch @panic("OOM"); for (self.test_target_filters) |filter| { - if (std.mem.indexOf(u8, triple_txt, filter) != null) break; + if (std.mem.find(u8, triple_txt, filter) != null) break; } else return; } diff --git a/test/src/convert-stack-trace.zig b/test/src/convert-stack-trace.zig index 5d7356a2d48e92e8577d4c3013a062dec0d63899..e42fd6860c76ce0f8986d06501f310862e39a3ca 100644 --- a/test/src/convert-stack-trace.zig +++ b/test/src/convert-stack-trace.zig @@ -52,13 +52,13 @@ pub fn main(init: std.process.Init) !void { continue; } - const src_pos_end = std.mem.indexOf(u8, in_line, ": 0x") orelse { + const src_pos_end = std.mem.find(u8, in_line, ": 0x") orelse { try w.writeAll(in_line); continue; }; const src_pos_start = b: { const postfix = ".zig:"; - const postfix_index = std.mem.lastIndexOf(u8, in_line[0..src_pos_end], postfix) orelse { + const postfix_index = std.mem.findLast(u8, in_line[0..src_pos_end], postfix) orelse { try w.writeAll(in_line); continue; }; @@ -89,7 +89,7 @@ pub fn main(init: std.process.Init) !void { // ...with that first '_' being replaced by its basename. const src_path = in_line[0..src_pos_start]; - const basename_start = if (std.mem.lastIndexOfAny(u8, src_path, "/\\")) |i| i + 1 else 0; + const basename_start = if (std.mem.findLastAny(u8, src_path, "/\\")) |i| i + 1 else 0; const symbol_start = addr_end + " in ".len; try w.writeAll(in_line[basename_start..src_pos_end]); try w.writeAll(": [address] in "); diff --git a/test/stack_traces.zig b/test/stack_traces.zig index 82d7d67863c209f4a5e3825f0eeb2cb100e50ced..352950af2b307d0fb1d7a8027358c76fe064db56 100644 --- a/test/stack_traces.zig +++ b/test/stack_traces.zig @@ -1,7 +1,10 @@ const std = @import("std"); +const Context = @import("tests.zig").StackTracesContext; -pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.Os.Tag) void { +pub fn addCases(cases: *Context, params: *const Context.CaseParameters, target: *const std.Target) void { cases.addCase(.{ + .params = params, + .target = target, .name = "simple panic", .source = \\pub fn main() void { @@ -33,6 +36,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "simple panic with no unwind strategy", .source = \\pub fn main() void { @@ -50,6 +55,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump current trace", .source = \\pub fn main() void { @@ -89,6 +96,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump current trace with no unwind strategy", .source = \\pub fn main() void { @@ -114,6 +123,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump captured trace", .source = \\pub fn main() void { @@ -155,6 +166,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump captured trace with no unwind strategy", .source = \\pub fn main() void { @@ -180,6 +193,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump captured trace on thread", .source = \\pub fn main() !void { @@ -225,6 +240,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "simple inline panic", // The main function has two inline calls to ensure // that inlinees in PDBs are properly deduplicated. @@ -240,7 +257,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. , .unwind = .any, .expect_panic = true, - .expect = switch (os) { + .expect = switch (target.os.tag) { // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs, // so the first location has only a row. .windows => @@ -262,7 +279,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. \\ ^ , }, - .expect_strip = switch (os) { + .expect_strip = switch (target.os.tag) { .windows => \\panic: oh no \\???:?:?: [address] in source.foo @@ -279,6 +296,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. // Make sure all inline calls are resolved and in the right order! cases.addCase(.{ + .params = params, + .target = target, .name = "nested inline panic", .source = \\pub fn main() void { @@ -298,7 +317,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. .unwind = .any, .expect_panic = true, // This switch serves a similar purpose as in "inline panic". - .expect = switch (os) { + .expect = switch (target.os.tag) { .windows => \\panic: oh no \\source.zig:11: [address] in baz @@ -322,7 +341,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. \\ ^ , }, - .expect_strip = switch (os) { + .expect_strip = switch (target.os.tag) { .windows => \\panic: oh no \\???:?:?: [address] in baz diff --git a/test/standalone/build.zig b/test/standalone/build.zig index dc8d85d399477256b65c60dc1b4850144c641738..fa1c4186abcd7da988acfcda5ca30ed966d62a80 100644 --- a/test/standalone/build.zig +++ b/test/standalone/build.zig @@ -31,6 +31,7 @@ pub fn build(b: *std.Build) void { const tools_target = b.resolveTargetQuery(.{}); for ([_][]const u8{ // Alphabetically sorted. No need to build `tools/spirv/grammar.zig`. + "../../tools/bsp.zig", "../../tools/check_mingw.zig", "../../tools/dump-cov.zig", "../../tools/fetch_them_macos_headers.zig", @@ -39,7 +40,6 @@ pub fn build(b: *std.Build) void { "../../tools/gen_parser_oracle.zig", "../../tools/gen_spirv_spec.zig", "../../tools/gen_stubs.zig", - "../../tools/generate_c_size_and_align_checks.zig", "../../tools/generate_JSONTestSuite.zig", "../../tools/generate_linux_syscalls.zig", "../../tools/process_headers.zig", diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon index 190394704ae48cd28406511353905a2f8675dd63..e134d00bd7d5977cda3341787a3dfefca86b4b7c 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -187,9 +187,6 @@ .posix = .{ .path = "posix", }, - .debug_io_color = .{ - .path = "debug_io_color", - }, .elf2 = .{ .path = "elf2", }, diff --git a/test/standalone/compiler_rt_panic/main.c b/test/standalone/compiler_rt_panic/main.c index be64216ab7e794616bd77cf5e61980f5fdc381c8..a11df761aaa60fc388163ccd76e82906767d146f 100644 --- a/test/standalone/compiler_rt_panic/main.c +++ b/test/standalone/compiler_rt_panic/main.c @@ -1,11 +1,11 @@ #include -void* __memset(void* dest, char c, size_t n, size_t dest_n); +void *__memset_chk(void *dest, int c, size_t n, size_t dest_n); char foo[128]; int main() { - __memset(&foo[0], 0xff, 128, 128); + __memset_chk(&foo[0], 0xff, 128, 128); return foo[64]; } diff --git a/test/standalone/config_header/build.zig b/test/standalone/config_header/build.zig index 88078ca2fae1eea50cffda5dff641d1566771e08..120c65c8532459a9cfcb3702c2d9b33492090e3f 100644 --- a/test/standalone/config_header/build.zig +++ b/test/standalone/config_header/build.zig @@ -51,6 +51,27 @@ pub fn build(b: *std.Build) void { }); test_step.dependOn(&check_config_header_autoconf_at.step); + const config_header_meson = b.addConfigHeader( + .{ .style = .{ + .meson = b.path("meson/mesondefine.h.in"), + } }, + .{ + .version = "1.2.3", + .boolean_true = true, + .boolean_false = false, + .uint_64 = 42, + .int_64 = -42, + .string = "meson", + .ident = .meson, + .not_defined = null, + .is_defined = {}, + }, + ); + const check_config_header_meson = b.addCheckFile(config_header_meson.getOutputFile(), .{ + .expected_exact = @embedFile("meson/mesondefine.h"), + }); + test_step.dependOn(&check_config_header_meson.step); + const config_header_blank = b.addConfigHeader( .{ .style = .blank, diff --git a/test/standalone/config_header/meson/mesondefine.h b/test/standalone/config_header/meson/mesondefine.h new file mode 100644 index 0000000000000000000000000000000000000000..f70ffe0ef1c08bfb04071699300d4404b7905f62 --- /dev/null +++ b/test/standalone/config_header/meson/mesondefine.h @@ -0,0 +1,22 @@ +/* This file was generated by ConfigHeader using the Zig Build System. */ +// comments are preserved + +// empty lines are preserved + +#define VERSION_STR "1.2.3" + +#define boolean_true /* comment after define is okay */ + +#undef boolean_false // same for line comment + +#define uint_64 42 + +#define int_64 -42 + +#define string "meson" + +#define ident meson + +/* #undef not_defined */ + +#define is_defined diff --git a/test/standalone/config_header/meson/mesondefine.h.in b/test/standalone/config_header/meson/mesondefine.h.in new file mode 100644 index 0000000000000000000000000000000000000000..b90f3054c29c4476da7d44f05afd20e69adc4acf --- /dev/null +++ b/test/standalone/config_header/meson/mesondefine.h.in @@ -0,0 +1,21 @@ +// comments are preserved + +// empty lines are preserved + +#define VERSION_STR "@version@" + +#mesondefine boolean_true /* comment after define is okay */ + +#mesondefine boolean_false // same for line comment + +#mesondefine uint_64 + +#mesondefine int_64 + +#mesondefine string + +#mesondefine ident + +#mesondefine not_defined + +#mesondefine is_defined diff --git a/test/standalone/debug_io_color/build.zig b/test/standalone/debug_io_color/build.zig deleted file mode 100644 index 22ce7c8c22f9ab3299bf14e07e7c0b7a23f367c6..0000000000000000000000000000000000000000 --- a/test/standalone/debug_io_color/build.zig +++ /dev/null @@ -1,95 +0,0 @@ -const std = @import("std"); - -pub fn build(b: *std.Build) void { - const test_step = b.step("test", "Test"); - b.default_step = test_step; - - // Most targets handle color the same way, regardless of whether libc is linked. - const native_target = b.graph.host; - addTestCases(test_step, native_target, false); - addTestCases(test_step, native_target, true); - - // WASI behaves differently depending on whether libc is linked. - if (b.enable_wasmtime) { - const wasi_target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }); - addTestCases(test_step, wasi_target, false); - addTestCases(test_step, wasi_target, true); - } -} - -fn addTestCases( - test_step: *std.Build.Step, - target: std.Build.ResolvedTarget, - link_libc: bool, -) void { - const b = test_step.owner; - const exe = b.addExecutable(.{ - .name = b.fmt("{s}{s}", .{ @tagName(target.result.os.tag), if (link_libc) "-libc" else "" }), - .root_module = b.createModule(.{ - .root_source_file = b.path("main.zig"), - .target = target, - .link_libc = link_libc, - }), - }); - - // Should reflect 'std.process.Environ.Block' and 'std.Io.Threaded.init_single_threaded'. - const debug_io_can_read_environ = switch (target.result.os.tag) { - .windows => true, - .wasi, .emscripten => link_libc, - .freestanding, .other => false, - else => true, - }; - - // Don't forget to account for whether the build process's stderr supports color. - const parent_stderr_color_enabled = (std.Io.Terminal.Mode.detect(b.graph.io, .stderr(), false, false) catch unreachable) != .no_color; - - _ = addTestCase(test_step, exe, "neither", .inherit, .manual, parent_stderr_color_enabled); - _ = addTestCase(test_step, exe, "neither", .redirect, .manual, false); - _ = addTestCase(test_step, exe, "no_color", .inherit, .disable, if (debug_io_can_read_environ) false else parent_stderr_color_enabled); - _ = addTestCase(test_step, exe, "no_color", .redirect, .disable, false); - _ = addTestCase(test_step, exe, "clicolor_force", .inherit, .enable, if (debug_io_can_read_environ) true else parent_stderr_color_enabled); - _ = addTestCase(test_step, exe, "clicolor_force", .redirect, .enable, debug_io_can_read_environ); - - const both = addTestCase(test_step, exe, "both", .inherit, .manual, if (debug_io_can_read_environ) false else parent_stderr_color_enabled); - both.setEnvironmentVariable("NO_COLOR", "1"); - both.setEnvironmentVariable("CLICOLOR_FORCE", "1"); - - const both_redirected = addTestCase(test_step, exe, "both", .redirect, .manual, false); - both_redirected.setEnvironmentVariable("NO_COLOR", "1"); - both_redirected.setEnvironmentVariable("CLICOLOR_FORCE", "1"); -} - -fn addTestCase( - test_step: *std.Build.Step, - exe: *std.Build.Step.Compile, - test_case_name: []const u8, - stderr: enum { inherit, redirect }, - run_step_color: std.Build.Step.Run.Color, - expected_color_enabled: bool, -) *std.Build.Step.Run { - const b = test_step.owner; - const step_name = b.fmt("{s} {s}{s}", .{ - exe.name, - test_case_name, - if (stderr == .redirect) "-redirect" else "", - }); - const run_exe = b.addRunArtifact(exe); - run_exe.setName(b.fmt("run {s}", .{step_name})); - - run_exe.failing_to_execute_foreign_is_an_error = false; - if (stderr == .redirect) run_exe.expectStdErrMatch(""); - - run_exe.clearEnvironment(); - run_exe.color = run_step_color; - - // Build system quirk: Currently, Run step stdout checks will also redirect stderr, so as a - // workaround we use a CheckFile step instead. We must also mark the Run step as having side - // effects, to ensure the parent stderr is inherited when not explicitly redirected. - run_exe.has_side_effects = true; - const stdout = run_exe.captureStdOut(.{}); - const check_file = b.addCheckFile(stdout, .{ .expected_exact = if (expected_color_enabled) "true" else "false" }); - check_file.setName(b.fmt("check {s}", .{step_name})); - test_step.dependOn(&check_file.step); - - return run_exe; -} diff --git a/test/standalone/debug_io_color/main.zig b/test/standalone/debug_io_color/main.zig deleted file mode 100644 index d9627f61792dbf38b9acf6b0e54f2ea54a138fe1..0000000000000000000000000000000000000000 --- a/test/standalone/debug_io_color/main.zig +++ /dev/null @@ -1,7 +0,0 @@ -const std = @import("std"); - -pub fn main() !void { - const stderr = std.debug.lockStderr(&.{}); - defer std.debug.unlockStderr(); - try std.Io.File.stdout().writeStreamingAll(std.Options.debug_io, if (stderr.terminal_mode != .no_color) "true" else "false"); -} diff --git a/test/standalone/dependency_options/build.zig b/test/standalone/dependency_options/build.zig index 8966920617d0a9bd1c851b96a83abc1e617e6ba0..f56bef5ae48942740f0a23161357876c3f70f7e9 100644 --- a/test/standalone/dependency_options/build.zig +++ b/test/standalone/dependency_options/build.zig @@ -11,11 +11,11 @@ pub fn build(b: *std.Build) !void { const none_specified_mod = none_specified.module("dummy"); if (!none_specified_mod.resolved_target.?.query.eql(b.graph.host.query)) return error.TestFailed; const expected_optimize: std.builtin.OptimizeMode = switch (b.graph.release_mode) { - .off => .Debug, + .off => .debug, .any => unreachable, - .fast => .ReleaseFast, - .safe => .ReleaseSafe, - .small => .ReleaseSmall, + .fast => .fast, + .safe => .safe, + .small => .small, }; if (none_specified_mod.optimize.? != expected_optimize) return error.TestFailed; @@ -44,7 +44,7 @@ pub fn build(b: *std.Build) !void { const all_specified = b.dependency("other", .{ .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), - .optimize = @as(std.builtin.OptimizeMode, .ReleaseSafe), + .optimize = @as(std.builtin.OptimizeMode, .safe), .bool = @as(bool, true), .int = @as(i64, 123), .float = @as(f64, 0.5), @@ -66,11 +66,11 @@ pub fn build(b: *std.Build) !void { if (all_specified_mod.resolved_target.?.result.cpu.arch != .x86_64) return error.TestFailed; if (all_specified_mod.resolved_target.?.result.os.tag != .windows) return error.TestFailed; if (all_specified_mod.resolved_target.?.result.abi != .gnu) return error.TestFailed; - if (all_specified_mod.optimize.? != .ReleaseSafe) return error.TestFailed; + if (all_specified_mod.optimize.? != .safe) return error.TestFailed; const all_specified_optional = b.dependency("other", .{ .target = @as(?std.Build.ResolvedTarget, b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu })), - .optimize = @as(?std.builtin.OptimizeMode, .ReleaseSafe), + .optimize = @as(?std.builtin.OptimizeMode, .safe), .bool = @as(?bool, true), .int = @as(?i64, 123), .float = @as(?f64, 0.5), @@ -92,7 +92,7 @@ pub fn build(b: *std.Build) !void { const all_specified_literal = b.dependency("other", .{ .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), - .optimize = .ReleaseSafe, + .optimize = .safe, .bool = true, .int = 123, .float = 0.5, @@ -130,7 +130,7 @@ pub fn build(b: *std.Build) !void { // to the same cached dependency instance. const all_specified_alt = b.dependency("other", .{ .target = @as(std.Target.Query, .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), - .optimize = "ReleaseSafe", + .optimize = "safe", .bool = .true, .int = "123", .float = @as(f16, 0.5), diff --git a/test/standalone/glibc_compat/build.zig b/test/standalone/glibc_compat/build.zig index 2a171c2dddab4c36fbee25c08eb5465e1b218cab..69568d72d9c1fd1b190aa482a0e1749feb7fa886 100644 --- a/test/standalone/glibc_compat/build.zig +++ b/test/standalone/glibc_compat/build.zig @@ -103,6 +103,8 @@ pub fn build(b: *std.Build) void { .{ .arch_os_abi = t }, ) catch unreachable); + if (target.result.cpu.arch.isLoongArch()) continue; // https://github.com/Vexu/arocc/issues/1096 + const glibc_ver = target.result.os.version_range.linux.glibc; // only build test if glibc version supports the architecture diff --git a/test/standalone/simple/build.zig b/test/standalone/simple/build.zig index af9da93a2b8a947ad9ccd72c547eb478217330f3..a61f2f1e975a1c3e46b1546791743842773e92de 100644 --- a/test/standalone/simple/build.zig +++ b/test/standalone/simple/build.zig @@ -13,26 +13,26 @@ pub fn build(b: *std.Build) void { var optimize_modes_buf: [4]std.builtin.OptimizeMode = undefined; var optimize_modes_len: usize = 0; if (!skip_debug) { - optimize_modes_buf[optimize_modes_len] = .Debug; + optimize_modes_buf[optimize_modes_len] = .debug; optimize_modes_len += 1; } if (!skip_release_safe) { - optimize_modes_buf[optimize_modes_len] = .ReleaseSafe; + optimize_modes_buf[optimize_modes_len] = .safe; optimize_modes_len += 1; } if (!skip_release_fast) { - optimize_modes_buf[optimize_modes_len] = .ReleaseFast; + optimize_modes_buf[optimize_modes_len] = .fast; optimize_modes_len += 1; } if (!skip_release_small) { - optimize_modes_buf[optimize_modes_len] = .ReleaseSmall; + optimize_modes_buf[optimize_modes_len] = .small; optimize_modes_len += 1; } const optimize_modes = optimize_modes_buf[0..optimize_modes_len]; for (cases) |case| { for (optimize_modes) |optimize| { - if (!case.all_modes and optimize != .Debug) continue; + if (!case.all_modes and optimize != .debug) continue; if (case.os_filter) |os_tag| { if (os_tag != builtin.os.tag) continue; } diff --git a/test/standalone/windows_argv/fuzz.zig b/test/standalone/windows_argv/fuzz.zig index 5169a3f54e42688eeb16532657f012cdb9edb422..743f73f7c96712d0823448f36fe69f31d518df71 100644 --- a/test/standalone/windows_argv/fuzz.zig +++ b/test/standalone/windows_argv/fuzz.zig @@ -147,8 +147,7 @@ fn spawnVerify(verify_path: [:0]const u16, cmd_line: [:0]const u16) !windows.DWO break :spawn proc_info.hProcess; }; defer windows.CloseHandle(child_proc); - const infinite_timeout: windows.LARGE_INTEGER = std.math.minInt(windows.LARGE_INTEGER); - switch (windows.ntdll.NtWaitForSingleObject(child_proc, .FALSE, &infinite_timeout)) { + switch (windows.ntdll.NtWaitForSingleObject(child_proc, .FALSE, null)) { windows.NTSTATUS.WAIT_0 => {}, .TIMEOUT => return error.WaitTimeOut, else => |status| return windows.unexpectedStatus(status), diff --git a/test/tests.zig b/test/tests.zig index 78f397d3f4e0c47053d98c5a51049a8dd7507fa9..fbb16c5a2fe759dd4840d4670670983898985276 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -6,8 +6,6 @@ const OptimizeMode = std.builtin.OptimizeMode; const Step = std.Build.Step; // Cases -const error_traces = @import("error_traces.zig"); -const stack_traces = @import("stack_traces.zig"); const llvm_ir = @import("llvm_ir.zig"); const libc = @import("libc.zig"); const link = @import("link.zig"); @@ -23,7 +21,7 @@ pub const LinkContext = @import("src/Link.zig"); const ModuleTestTarget = struct { linkage: ?std.builtin.LinkMode = null, target: std.Target.Query = .{}, - optimize_mode: std.builtin.OptimizeMode = .Debug, + optimize_mode: std.builtin.OptimizeMode = .debug, link_libc: ?bool = null, single_threaded: ?bool = null, use_llvm: ?bool = null, @@ -57,38 +55,38 @@ const module_test_targets = blk: { }, .{ - .optimize_mode = .ReleaseFast, + .optimize_mode = .fast, }, .{ .link_libc = true, - .optimize_mode = .ReleaseFast, + .optimize_mode = .fast, }, .{ - .optimize_mode = .ReleaseFast, + .optimize_mode = .fast, .single_threaded = true, }, .{ - .optimize_mode = .ReleaseSafe, + .optimize_mode = .safe, }, .{ .link_libc = true, - .optimize_mode = .ReleaseSafe, + .optimize_mode = .safe, }, .{ - .optimize_mode = .ReleaseSafe, + .optimize_mode = .safe, .single_threaded = true, }, .{ - .optimize_mode = .ReleaseSmall, + .optimize_mode = .small, }, .{ .link_libc = true, - .optimize_mode = .ReleaseSmall, + .optimize_mode = .small, }, .{ - .optimize_mode = .ReleaseSmall, + .optimize_mode = .small, .single_threaded = true, }, @@ -200,7 +198,7 @@ const module_test_targets = blk: { // }, // .use_llvm = false, // .use_lld = false, - // .optimize_mode = .ReleaseFast, + // .optimize_mode = .fast, // .strip = true, // .skip_modules = &.{"std"}, // TODO get these passing //}, @@ -213,7 +211,7 @@ const module_test_targets = blk: { // }, // .use_llvm = false, // .use_lld = false, - // .optimize_mode = .ReleaseFast, + // .optimize_mode = .fast, // .strip = true, // .skip_modules = &.{"std"}, // TODO get these passing //}, @@ -274,6 +272,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .arm, + .os_tag = .linux, + .abi = .musleabi, + .ofmt = .c, + }, + .link_libc = true, + }, .{ .target = .{ .cpu_arch = .arm, @@ -292,6 +299,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .arm, + .os_tag = .linux, + .abi = .musleabihf, + .ofmt = .c, + }, + .link_libc = true, + }, .{ .target = .{ .cpu_arch = .arm, @@ -341,6 +357,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .armeb, + .os_tag = .linux, + .abi = .musleabi, + .ofmt = .c, + }, + .link_libc = true, + }, // Crashes in weird ways when applying relocations. // .{ // .target = .{ @@ -360,6 +385,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .armeb, + .os_tag = .linux, + .abi = .musleabihf, + .ofmt = .c, + }, + .link_libc = true, + }, // Crashes in weird ways when applying relocations. // .{ // .target = .{ @@ -419,6 +453,23 @@ const module_test_targets = blk: { .abi = .none, }, }, + .{ + .target = .{ + .cpu_arch = .loongarch32, + .os_tag = .linux, + .abi = .gnu, + }, + .link_libc = true, + }, + .{ + .target = .{ + .cpu_arch = .loongarch32, + .os_tag = .linux, + .abi = .gnusf, + }, + .link_libc = true, + .extra_target = true, + }, .{ .target = .{ @@ -1107,6 +1158,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .x86, + .os_tag = .linux, + .abi = .musl, + .ofmt = .c, + }, + .link_libc = true, + }, .{ .target = .{ .cpu_arch = .x86, @@ -1257,7 +1317,7 @@ const module_test_targets = blk: { // }, // .use_llvm = false, // .use_lld = false, - // .optimize_mode = .ReleaseFast, + // .optimize_mode = .fast, // .strip = true, //}, @@ -1523,7 +1583,6 @@ const module_test_targets = blk: { .os_tag = .wasi, .abi = .none, }, - .skip_modules = &.{"compiler-rt"}, .use_llvm = false, .use_lld = false, }, @@ -1645,6 +1704,15 @@ const module_test_targets = blk: { }, .link_libc = true, }, + .{ + .target = .{ + .cpu_arch = .x86, + .os_tag = .windows, + .abi = .gnu, + .ofmt = .c, + }, + .link_libc = true, + }, .{ .target = .{ @@ -1961,7 +2029,6 @@ const c_abi_targets = blk: { .abi = .musl, }, .use_llvm = false, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -1972,7 +2039,6 @@ const c_abi_targets = blk: { }, .use_llvm = false, .strip = true, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -1983,7 +2049,6 @@ const c_abi_targets = blk: { }, .use_llvm = false, .pic = true, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -2010,6 +2075,15 @@ const c_abi_targets = blk: { .abi = .musl, }, }, + .{ + .target = .{ + .cpu_arch = .wasm32, + .os_tag = .wasi, + .abi = .musl, + }, + .use_llvm = false, + .use_lld = false, + }, // Windows Targets @@ -2028,7 +2102,6 @@ const c_abi_targets = blk: { .abi = .gnu, }, .use_llvm = false, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -2038,7 +2111,6 @@ const c_abi_targets = blk: { .abi = .gnu, }, .use_llvm = false, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -2048,7 +2120,6 @@ const c_abi_targets = blk: { .abi = .gnu, }, .use_llvm = false, - .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, }, .{ .target = .{ @@ -2063,7 +2134,7 @@ const c_abi_targets = blk: { const LinkTarget = struct { target: std.Target.Query = .{}, - optimize_mode: std.builtin.OptimizeMode = .Debug, + optimize_mode: std.builtin.OptimizeMode = .debug, link_libc: bool = false, use_llvm: bool = false, use_lld: bool = false, @@ -2308,59 +2379,7 @@ pub fn isNative(actual_target: *const std.Build.ResolvedTarget, host: *const std return true; } -/// For stack trace tests, we only test native by default, because external executors are pretty -/// unreliable at stack tracing. However, if there's a 32-bit equivalent target which the host can -/// trivially run, we may as well at least test that! -fn nativeAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget { - const host = b.graph.host.result; - const only_native = (&b.graph.host)[0..1]; - if (skip_non_native) return only_native; - const arch32 = compatible32bitArch(&b.graph.host.result) orelse return only_native; - return b.graph.arena.dupe(std.Build.ResolvedTarget, &.{ - b.graph.host, - b.resolveTargetQuery(.{ .cpu_arch = arch32, .os_tag = host.os.tag }), - }) catch @panic("OOM"); -} - -fn wineAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget { - var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty; - - const host = b.graph.host.result; - - targets.append(b.graph.arena, b.resolveTargetQuery(.{ - .cpu_arch = host.cpu.arch, - .os_tag = .windows, - })) catch @panic("OOM"); - if (!skip_non_native) { - if (compatible32bitArch(&b.graph.host.result)) |arch| { - targets.append(b.graph.arena, b.resolveTargetQuery(.{ - .cpu_arch = arch, - .os_tag = .windows, - })) catch @panic("OOM"); - } - } - - return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM"); -} - -fn darlingTargets(b: *std.Build) []const std.Build.ResolvedTarget { - var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty; - - const host = b.graph.host.result; - - targets.append(b.graph.arena, b.resolveTargetQuery(.{ - .cpu_arch = host.cpu.arch, - .os_tag = .macos, - })) catch @panic("OOM"); - - return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM"); -} - -pub fn addStackTraceTests( - b: *std.Build, - test_filters: []const []const u8, - skip_non_native: bool, -) *Step { +pub fn addStackTraceTests(b: *std.Build, test_filters: []const []const u8, skip_non_native: bool) *Step { const step = b.step("test-stack-traces", "Run the stack trace tests"); const convert_exe = b.addExecutable(.{ @@ -2368,43 +2387,19 @@ pub fn addStackTraceTests( .root_module = b.createModule(.{ .root_source_file = b.path("test/src/convert-stack-trace.zig"), .target = b.graph.host, - .optimize = .Debug, + .optimize = .debug, }), }); - const host_cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); - host_cases.* = .{ + const stack_traces_context = b.allocator.create(StackTracesContext) catch @panic("OOM"); + stack_traces_context.* = .{ .b = b, .step = step, .test_filters = test_filters, - .targets = nativeAndCompatible32bit(b, skip_non_native), + .skip_non_native = skip_non_native, .convert_exe = convert_exe, }; - stack_traces.addCases(host_cases, b.graph.host.result.os.tag); - - if (b.enable_wine) { - const wine_cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); - wine_cases.* = .{ - .b = b, - .step = step, - .test_filters = test_filters, - .targets = wineAndCompatible32bit(b, skip_non_native), - .convert_exe = convert_exe, - }; - stack_traces.addCases(wine_cases, .windows); - } - - if (b.enable_darling) { - const darling_cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); - darling_cases.* = .{ - .b = b, - .step = step, - .test_filters = test_filters, - .targets = darlingTargets(b), - .convert_exe = convert_exe, - }; - stack_traces.addCases(darling_cases, .macos); - } + stack_traces_context.addCases(); return step; } @@ -2422,56 +2417,24 @@ pub fn addErrorTraceTests( .root_module = b.createModule(.{ .root_source_file = b.path("test/src/convert-stack-trace.zig"), .target = b.graph.host, - .optimize = .Debug, + .optimize = .debug, }), }); - const host_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); - host_cases.* = .{ + const error_traces_context = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); + error_traces_context.* = .{ .b = b, .step = step, .test_filters = test_filters, - .targets = nativeAndCompatible32bit(b, skip_non_native), + .skip_non_native = skip_non_native, .optimize_modes = optimize_modes, .convert_exe = convert_exe, }; - error_traces.addCases(host_cases, b.graph.host.result.os.tag); - - if (b.enable_wine) { - const wine_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); - wine_cases.* = .{ - .b = b, - .step = step, - .test_filters = test_filters, - .targets = wineAndCompatible32bit(b, skip_non_native), - .optimize_modes = optimize_modes, - .convert_exe = convert_exe, - }; - error_traces.addCases(wine_cases, .windows); - } - - if (b.enable_darling) { - const darling_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); - darling_cases.* = .{ - .b = b, - .step = step, - .test_filters = test_filters, - .targets = darlingTargets(b), - .optimize_modes = optimize_modes, - .convert_exe = convert_exe, - }; - error_traces.addCases(darling_cases, .macos); - } + error_traces_context.addCases(); return step; } -fn compilerHasPackageManager(b: *std.Build) bool { - // We can only use dependencies if the compiler was built with support for package management. - // (zig2 doesn't support it, but we still need to construct a build graph to build stage3.) - return b.available_deps.len != 0; -} - pub fn addStandaloneTests( b: *std.Build, optimize_modes: []const OptimizeMode, @@ -2480,21 +2443,19 @@ pub fn addStandaloneTests( enable_symlinks_windows: bool, ) *Step { const step = b.step("test-standalone", "Run the standalone tests"); - if (compilerHasPackageManager(b)) { - const test_cases_dep_name = "standalone_test_cases"; - const test_cases_dep = b.dependency(test_cases_dep_name, .{ - .enable_ios_sdk = enable_ios_sdk, - .enable_macos_sdk = enable_macos_sdk, - .enable_symlinks_windows = enable_symlinks_windows, - .simple_skip_debug = mem.indexOfScalar(OptimizeMode, optimize_modes, .Debug) == null, - .simple_skip_release_safe = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSafe) == null, - .simple_skip_release_fast = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseFast) == null, - .simple_skip_release_small = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSmall) == null, - }); - const test_cases_dep_step = test_cases_dep.builder.default_step; - test_cases_dep_step.name = b.dupe(test_cases_dep_name); - step.dependOn(test_cases_dep.builder.default_step); - } + const test_cases_dep_name = "standalone_test_cases"; + const test_cases_dep = b.dependency(test_cases_dep_name, .{ + .enable_ios_sdk = enable_ios_sdk, + .enable_macos_sdk = enable_macos_sdk, + .enable_symlinks_windows = enable_symlinks_windows, + .simple_skip_debug = mem.findScalar(OptimizeMode, optimize_modes, .debug) == null, + .simple_skip_release_safe = mem.findScalar(OptimizeMode, optimize_modes, .safe) == null, + .simple_skip_release_fast = mem.findScalar(OptimizeMode, optimize_modes, .fast) == null, + .simple_skip_release_small = mem.findScalar(OptimizeMode, optimize_modes, .small) == null, + }); + const test_cases_dep_step = test_cases_dep.builder.default_step; + test_cases_dep_step.name = b.graph.dupeString(test_cases_dep_name); + step.dependOn(test_cases_dep.builder.default_step); return step; } @@ -2782,16 +2743,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { const target = &resolved_target.result; - if (target.cpu.arch == .s390x and target.ofmt == .c) { - // https://codeberg.org/ziglang/zig/issues/35523 - continue; - } - - if (target.cpu.arch == .riscv64 and target.ofmt == .c) { - // https://codeberg.org/ziglang/zig/issues/30930 - continue; - } - if (std.mem.eql(u8, options.name, "libc")) { // The libc API tests obviously need to link libc. So for test // target entries where we wouldn't link libc by default, skip the @@ -2816,7 +2767,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { if (options.test_target_filters.len > 0) { for (options.test_target_filters) |filter| { - if (std.mem.indexOf(u8, triple_txt, filter) != null) break; + if (std.mem.find(u8, triple_txt, filter) != null) break; } else continue; } @@ -3057,7 +3008,7 @@ pub fn wouldUseLlvm(use_llvm: ?bool, query: std.Target.Query, optimize_mode: Opt if (use_llvm) |x| return x; if (query.ofmt == .c) return false; switch (optimize_mode) { - .Debug => {}, + .debug => {}, else => return true, } const cpu_arch = query.cpu_arch orelse builtin.cpu.arch; @@ -3114,7 +3065,7 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step { if (options.test_target_filters.len > 0) { for (options.test_target_filters) |filter| { - if (std.mem.indexOf(u8, triple_txt, filter) != null) break; + if (std.mem.find(u8, triple_txt, filter) != null) break; } else continue; } @@ -3203,7 +3154,7 @@ pub fn addLinkTests(b: *std.Build, options: LinkTestOptions) *Step { if (options.test_target_filters.len > 0) { for (options.test_target_filters) |filter| { - if (std.mem.indexOf(u8, triple_txt, filter) != null) break; + if (std.mem.find(u8, triple_txt, filter) != null) break; } else continue; } @@ -3314,7 +3265,7 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step, test_filters: []cons .root_module = b.createModule(.{ .root_source_file = b.path("tools/incr-check.zig"), .target = b.graph.host, - .optimize = .Debug, + .optimize = .debug, }), }); @@ -3328,7 +3279,7 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step, test_filters: []cons if (std.mem.endsWith(u8, entry.basename, ".swp")) continue; for (test_filters) |test_filter| { - if (std.mem.indexOf(u8, entry.path, test_filter)) |_| break; + if (std.mem.find(u8, entry.path, test_filter)) |_| break; } else if (test_filters.len > 0) continue; switch (entry.kind) { @@ -3354,10 +3305,11 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step, test_filters: []cons run.addArg("--quiet"); // don't fill stderr telling us about skipped tests etc - if (b.enable_qemu) run.addArg("-fqemu"); - if (b.enable_wine) run.addArg("-fwine"); - if (b.enable_wasmtime) run.addArg("-fwasmtime"); - if (b.enable_darling) run.addArg("-fdarling"); + run.addThirdPartyEnabledArgDarling(.{ .enabled = "-fdarling" }); + run.addThirdPartyEnabledArgQemu(.{ .enabled = "-fqemu" }); + run.addThirdPartyEnabledArgRosetta(.{ .enabled = "-frosetta" }); + run.addThirdPartyEnabledArgWasmtime(.{ .enabled = "-fwasmtime" }); + run.addThirdPartyEnabledArgWine(.{ .enabled = "-fwine" }); run.addCheck(.{ .expect_term = .{ .exited = 0 } }); test_step.dependOn(&run.step); diff --git a/tools/bsp.zig b/tools/bsp.zig new file mode 100644 index 0000000000000000000000000000000000000000..b86e30c3af07b53b352602e5b480c0d785055830 --- /dev/null +++ b/tools/bsp.zig @@ -0,0 +1,242 @@ +//! CLI tool to interface with the build system protocol (zig build --listen=-) + +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const Configuration = std.Build.Configuration; +const Client = std.zig.Client; +const Server = std.zig.Server; +const log = std.log.scoped(.bsp); + +pub fn main(init: std.process.Init) !void { + const io = init.io; + const gpa = init.gpa; + const arena = init.arena.allocator(); + + var maker_args: std.ArrayList([]const u8) = .empty; + + const args = try init.minimal.args.toSlice(arena); + for (args[1..]) |arg| { + try maker_args.append(arena, try arena.dupe(u8, arg)); + } + if (maker_args.items.len < 1) try maker_args.append(arena, "zig"); + if (maker_args.items.len < 2) try maker_args.append(arena, "build"); + if (!std.mem.eql(u8, maker_args.last().?, "--listen=-")) try maker_args.append(arena, "--listen=-"); + + log.debug("cmd: {f}", .{std.zig.SubprocessCommand{ + .argv = maker_args.items, + }}); + + var child_process = std.process.spawn(io, .{ + .argv = maker_args.items, + .stdin = .pipe, + .stdout = .pipe, + .stderr = .pipe, + }) catch |err| std.debug.panic("failed to spawn process: {}", .{err}); + errdefer child_process.kill(io); + + var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined; + var multi_reader: Io.File.MultiReader = undefined; + defer multi_reader.deinit(); + multi_reader.init( + gpa, + io, + multi_reader_buffer.toStreams(), + &.{ child_process.stdout.?, child_process.stderr.? }, + ); + const client_stdout = multi_reader.reader(0); + const client_stderr = multi_reader.reader(1); + + var client_stdout_buffer: [256]u8 = undefined; + var client_stdout_writer = child_process.stdin.?.writerStreaming(io, &client_stdout_buffer); + + var client: Client = .{ + .in = client_stdout, + .out = &client_stdout_writer.interface, + }; + + const err = blk: { + const handshake: Server.Message.Handshake = handshake: { + const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { + error.Canceled, error.ConcurrencyUnavailable => |e| return e, + error.Timeout => unreachable, + else => |e| { + log.err("failed to receive message: {t}", .{err}); + break :blk e; + }, + }; + const body = client_stdout.take(header.bytes_len) catch unreachable; + log.debug("received {f} ({d} bytes)", .{ fmtEnum(header.tag), body.len }); + + if (header.tag != .bsp_handshake) { + log.err("received unexpected message: {f}", .{fmtEnum(header.tag)}); + return error.UnexpectedMessage; + } + + var r: Io.Reader = .fixed(body); + break :handshake try r.takeStruct(Server.Message.Handshake, .little); + }; + _ = handshake; + + var conf_arena_allocator: std.heap.ArenaAllocator = .init(gpa); + defer conf_arena_allocator.deinit(); + const conf_arena = conf_arena_allocator.allocator(); + + const configuration = configuration: { + const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { + error.Canceled, error.ConcurrencyUnavailable => |e| return e, + error.Timeout => unreachable, + else => |e| { + log.err("failed to receive message: {t}", .{err}); + break :blk e; + }, + }; + const body = client_stdout.take(header.bytes_len) catch unreachable; + log.debug("received {t} ({d} bytes)", .{ header.tag, body.len }); + + if (header.tag != .bsp_configuration) { + log.err("received unexpected message: {f}", .{fmtEnum(header.tag)}); + return error.UnexpectedMessage; + } + + const configuration_path = body; + var file = Io.Dir.cwd().openFile(io, configuration_path, .{}) catch |err| + std.debug.panic("failed to open configuration file {q}: {t}", .{ configuration_path, err }); + defer file.close(io); + break :configuration Configuration.loadFile(conf_arena, io, file) catch |err| + std.debug.panic("failed to load configuration file {q}: {t}", .{ configuration_path, err }); + }; + const c = &configuration; + + var top_level_steps: std.array_hash_map.String(Configuration.Step.Index) = .empty; + defer top_level_steps.deinit(gpa); + + for (c.steps, 0..) |*conf_step, step_index_usize| { + if (conf_step.owner != .root) continue; + const step_index: Configuration.Step.Index = @fromBackingInt(@intCast(step_index_usize)); + const flags = conf_step.flags(c); + if (flags.tag != .top_level) continue; + const name = step_index.ptr(c).name.slice(c); + try top_level_steps.putNoClobber(gpa, name, step_index); + } + + std.debug.print("Steps:\n", .{}); + for (top_level_steps.keys()) |name| { + std.debug.print(" - {q}\n", .{name}); + } + std.debug.print( + \\Available Commands: + \\ - build [step names / step indices] + \\ - watch [step names / step indices] + \\ - exit + \\ + , .{}); + + var stdin_reader_buffer: [256]u8 = undefined; + var stdin_reader = Io.File.stdin().reader(io, &stdin_reader_buffer); + const stdin = &stdin_reader.interface; + + while (true) { + try Io.File.stdout().writeStreamingAll(io, "> "); + const command = try stdin.takeDelimiterExclusive('\n'); + stdin.toss(1); + if (std.mem.startsWith(u8, command, "build") or + std.mem.startsWith(u8, command, "watch")) + { + var steps: std.ArrayList(Configuration.Step.Index) = .empty; + defer steps.deinit(gpa); + + const watch = std.mem.startsWith(u8, command, "watch"); + + if (std.mem.cutPrefix(u8, command, "build ") orelse + std.mem.cutPrefix(u8, command, "watch ")) |command_args| + { + var it = std.mem.tokenizeScalar(u8, command_args, ' '); + while (it.next()) |arg| { + const step: Configuration.Step.Index = + if (std.fmt.parseInt(u32, arg, 10)) |i| + @fromBackingInt(i) + else |_| + top_level_steps.get(arg) orelse std.debug.panic("unexpected step name or index", .{}); + try steps.append(gpa, step); + } + } + + if (steps.items.len < 1) { + try steps.append(gpa, c.default_step); + } + + try client.serveBuildSteps(steps.items, .{ .watch = watch }); + + while (true) { + const header: Server.Message.Header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { + error.Canceled, error.ConcurrencyUnavailable => |e| return e, + error.Timeout => unreachable, + else => |e| { + log.err("failed to receive message: {t}", .{err}); + break :blk e; + }, + }; + const body = client_stdout.take(header.bytes_len) catch unreachable; + log.debug("received {f} ({d} bytes)", .{ fmtEnum(header.tag), body.len }); + + switch (header.tag) { + .bsp_build_started => {}, + .bsp_build_completed => if (!watch) break, + .bsp_step_started => {}, + .bsp_step_completed => {}, + .bsp_configuration => @panic("TODO"), + else => std.debug.panic("received unexpected message: {f}", .{fmtEnum(header.tag)}), + } + } + continue; + } else if (std.mem.eql(u8, command, "exit")) { + try client.serveBodylessMessage(.exit); + break; + } else { + log.err("unknown command: {q}", .{command}); + continue; + } + } + }; + + try multi_reader.fillRemaining(.none); + + if (client_stderr.bufferedLen() > 0) { + log.err("stderr:\n{s}\n", .{client_stderr.buffered()}); + } + + try err; + + const term = try child_process.wait(io); + + if (!term.success()) { + log.err("maker {f}", .{term}); + } +} + +const FormatEnum = union(enum) { + named: []const u8, + unnamed: usize, + + pub fn format( + e: FormatEnum, + writer: *std.Io.Writer, + ) std.Io.Writer.Error!void { + switch (e) { + .named => |name| { + try writer.writeByte('.'); + try writer.writeAll(name); + }, + .unnamed => |number| try writer.print("0x{x}", .{number}), + } + } +}; + +fn fmtEnum(e: anytype) FormatEnum { + if (std.enums.tagName(@TypeOf(e), e)) |name| { + return .{ .named = name }; + } else { + return .{ .unnamed = @backingInt(e) }; + } +} diff --git a/tools/docgen.zig b/tools/docgen.zig index 9f182f350cc73069a44bfe7b2cc52ade250f228e..5e78dbecc98f37d1d4186011a2601683a29713e1 100644 --- a/tools/docgen.zig +++ b/tools/docgen.zig @@ -712,10 +712,10 @@ fn tokenizeAndPrintRaw( next_tok_is_fn = false; const token = tokenizer.next(); - if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| { + if (mem.find(u8, src[index..token.loc.start], "//")) |comment_start_off| { // render one comment const comment_start = index + comment_start_off; - const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n"); + const comment_end_off = mem.find(u8, src[comment_start..token.loc.start], "\n"); const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start; try writeEscapedLines(out, src[index..comment_start]); diff --git a/tools/doctest.zig b/tools/doctest.zig index d1d7919a51f299ecea3914ac8307d6b6741723a6..b653b84a8e3195d01c061921428273d3c351839a 100644 --- a/tools/doctest.zig +++ b/tools/doctest.zig @@ -383,7 +383,7 @@ fn printOutput( fatal("example compile crashed", .{}); }, } - if (mem.indexOf(u8, result.stderr, error_match) == null) { + if (mem.find(u8, result.stderr, error_match) == null) { print("{s}\nExpected to find '{s}' in stderr\n", .{ result.stderr, error_match }); fatal("example did not have expected compile error", .{}); } @@ -438,7 +438,7 @@ fn printOutput( fatal("example compile crashed", .{}); }, } - if (mem.indexOf(u8, result.stderr, error_match) == null) { + if (mem.find(u8, result.stderr, error_match) == null) { print("{s}\nExpected to find '{s}' in stderr\n", .{ result.stderr, error_match }); fatal("example did not have expected runtime safety error message", .{}); } @@ -513,7 +513,7 @@ fn printOutput( fatal("example compile crashed", .{}); }, } - if (mem.indexOf(u8, result.stderr, error_match) == null) { + if (mem.find(u8, result.stderr, error_match) == null) { print("{s}\nExpected to find '{s}' in stderr\n", .{ result.stderr, error_match }); fatal("example did not have expected compile error message", .{}); } @@ -623,10 +623,10 @@ fn tokenizeAndPrint(arena: Allocator, out: *Writer, raw_src: []const u8) !void { next_tok_is_fn = false; const token = tokenizer.next(); - if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| { + if (mem.find(u8, src[index..token.loc.start], "//")) |comment_start_off| { // render one comment const comment_start = index + comment_start_off; - const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n"); + const comment_end_off = mem.find(u8, src[comment_start..token.loc.start], "\n"); const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start; try writeEscapedLines(out, src[index..comment_start]); @@ -870,13 +870,13 @@ const Code = struct { }; fn stripManifest(source_bytes: []const u8) []const u8 { - const manifest_start = mem.lastIndexOf(u8, source_bytes, "\n\n// ") orelse + const manifest_start = mem.findLast(u8, source_bytes, "\n\n// ") orelse fatal("missing manifest comment", .{}); return source_bytes[0 .. manifest_start + 1]; } fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code { - const manifest_start = mem.lastIndexOf(u8, source_bytes, "\n\n// ") orelse + const manifest_start = mem.findLast(u8, source_bytes, "\n\n// ") orelse fatal("missing manifest comment", .{}); var it = mem.tokenizeScalar(u8, source_bytes[manifest_start..], '\n'); const first_line = skipPrefix(it.next().?); @@ -915,11 +915,11 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code { while (it.next()) |prefixed_line| { const line = skipPrefix(prefixed_line); if (mem.startsWith(u8, line, "optimize=")) { - mode = std.meta.stringToEnum(std.builtin.OptimizeMode, line["optimize=".len..]) orelse - fatal("bad optimization mode line: '{s}'", .{line}); + mode = std.builtin.Optimize.fromString(line["optimize=".len..]) orelse + fatal("bad optimization mode line: {q}", .{line}); } else if (mem.startsWith(u8, line, "link_mode=")) { link_mode = std.meta.stringToEnum(std.builtin.LinkMode, line["link_mode=".len..]) orelse - fatal("bad link mode line: '{s}'", .{line}); + fatal("bad link mode line: {q}", .{line}); } else if (mem.startsWith(u8, line, "link_object=")) { try link_objects.append(arena, line["link_object=".len..]); } else if (mem.startsWith(u8, line, "additional_option=")) { @@ -1104,7 +1104,7 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { // Returns true if number is in slice. fn in(slice: []const u8, number: u8) bool { - return mem.indexOfScalar(u8, slice, number) != null; + return mem.findScalar(u8, slice, number) != null; } fn run( diff --git a/tools/fetch_them_macos_headers.zig b/tools/fetch_them_macos_headers.zig index d15bf8b7dfa9f8ccb3acbbb5d978726c16379731..d2b7dd2f933e50d25f5f46f53888abad9986c8f3 100644 --- a/tools/fetch_them_macos_headers.zig +++ b/tools/fetch_them_macos_headers.zig @@ -187,8 +187,8 @@ fn fetchTarget( var it = mem.splitScalar(u8, headers_list_str, '\n'); while (it.next()) |line| { - if (mem.lastIndexOf(u8, line, "clang") != null) continue; - if (mem.lastIndexOf(u8, line, prefix[0..])) |idx| { + if (mem.findLast(u8, line, "clang") != null) continue; + if (mem.findLast(u8, line, prefix[0..])) |idx| { const out_rel_path = line[idx + prefix.len + 1 ..]; const out_rel_path_stripped = mem.trim(u8, out_rel_path, " \\"); const dirname = Dir.path.dirname(out_rel_path_stripped) orelse "."; diff --git a/tools/generate_c_size_and_align_checks.zig b/tools/generate_c_size_and_align_checks.zig deleted file mode 100644 index 09400615f2c526bdde3ce99c62b0f5a0bf386932..0000000000000000000000000000000000000000 --- a/tools/generate_c_size_and_align_checks.zig +++ /dev/null @@ -1,62 +0,0 @@ -//! Usage: zig run tools/generate_c_size_and_align_checks.zig -- [target_triple] -//! e.g. zig run tools/generate_c_size_and_align_checks.zig -- x86_64-linux-gnu -//! -//! Prints _Static_asserts for the size and alignment of all the basic built-in C -//! types. The output can be run through a compiler for the specified target to -//! verify that Zig's values are the same as those used by a C compiler for the -//! target. - -const std = @import("std"); -const Io = std.Io; - -fn cName(ty: std.Target.CType) []const u8 { - return switch (ty) { - .char => "char", - .short => "short", - .ushort => "unsigned short", - .int => "int", - .uint => "unsigned int", - .long => "long", - .ulong => "unsigned long", - .longlong => "long long", - .ulonglong => "unsigned long long", - .float => "float", - .double => "double", - .longdouble => "long double", - }; -} - -var general_purpose_allocator: std.heap.DebugAllocator(.{}) = .init; - -pub fn main(init: std.process.Init) !void { - const args = try init.minimal.args.toSlice(init.arena.allocator()); - const io = init.io; - - if (args.len != 2) { - std.debug.print("Usage: {s} [target_triple]\n", .{args[0]}); - std.process.exit(1); - } - - const query = try std.Target.Query.parse(.{ .arch_os_abi = args[1] }); - const target = try std.zig.system.resolveTargetQuery(io, query); - - var buffer: [2000]u8 = undefined; - var stdout_writer = Io.File.stdout().writerStreaming(io, &buffer); - const w = &stdout_writer.interface; - inline for (@typeInfo(std.Target.CType).@"enum".field_values) |field_value| { - const c_type: std.Target.CType = @fromBackingInt(@intCast(field_value)); - try w.print("_Static_assert(sizeof({0s}) == {1d}, \"sizeof({0s}) == {1d}\");\n", .{ - cName(c_type), - target.cTypeByteSize(c_type), - }); - try w.print("_Static_assert(_Alignof({0s}) == {1d}, \"_Alignof({0s}) == {1d}\");\n", .{ - cName(c_type), - target.cTypeAlignment(c_type), - }); - try w.print("_Static_assert(__alignof({0s}) == {1d}, \"__alignof({0s}) == {1d}\");\n\n", .{ - cName(c_type), - target.cTypePreferredAlignment(c_type), - }); - } - try w.flush(); -} diff --git a/tools/incr-check.zig b/tools/incr-check.zig index 89c14ce1e7f60a710e863349025d3803f2dc37bb..500635b24972b5a54f69a873489c130e3f39a7f0 100644 --- a/tools/incr-check.zig +++ b/tools/incr-check.zig @@ -305,21 +305,23 @@ const Eval = struct { fn check(eval: *Eval, mr: *Io.File.MultiReader, update: Case.Update, prog_node: std.Progress.Node) !void { const arena = eval.arena; - const stdout = mr.fileReader(0); - const stderr = &mr.fileReader(1).interface; - const Header = std.zig.Server.Message.Header; + const stdout = mr.reader(0); + const stderr = mr.reader(1); + + var client: std.zig.Client = .{ + .in = stdout, + .out = undefined, + }; while (true) { - const header = stdout.interface.takeStruct(Header, .little) catch |err| switch (err) { - error.EndOfStream => break, - error.ReadFailed => return stdout.err.?, - }; - const body = stdout.interface.take(header.bytes_len) catch |err| switch (err) { + const header = client.receiveMessageWithMultiReader(mr, .none) catch |err| switch (err) { + error.Timeout => unreachable, // If this panic triggers it might be helpful to rework this // code to print the stderr from the abnormally terminated child. error.EndOfStream => @panic("unexpected mid-message end of stream"), - error.ReadFailed => return stdout.err.?, + else => |e| return e, }; + const body = client.in.take(header.bytes_len) catch unreachable; switch (header.tag) { .error_bundle => { @@ -448,7 +450,7 @@ const Eval = struct { const raw_filename = eb.nullTerminatedString(src.src_path); // We need to replace backslashes for consistency between platforms. const filename = name: { - if (std.mem.indexOfScalar(u8, raw_filename, '\\') == null) break :name raw_filename; + if (std.mem.findScalar(u8, raw_filename, '\\') == null) break :name raw_filename; const copied = try eval.arena.dupe(u8, raw_filename); std.mem.replaceScalar(u8, copied, '\\', '/'); break :name copied; @@ -605,12 +607,13 @@ const Eval = struct { fn requestUpdate(eval: *Eval) !void { const io = eval.io; - const header: std.zig.Client.Message.Header = .{ - .tag = .update, - .bytes_len = 0, + + var w = eval.child.stdin.?.writerStreaming(io, &.{}); + var client: std.zig.Client = .{ + .in = undefined, + .out = &w.interface, }; - var w = eval.child.stdin.?.writer(io, &.{}); - w.interface.writeStruct(header, .little) catch |err| switch (err) { + client.serveBodylessMessage(.update) catch |err| switch (err) { error.WriteFailed => return w.err.?, }; } @@ -618,22 +621,23 @@ const Eval = struct { fn end(eval: *Eval, mr: *Io.File.MultiReader) !void { requestExit(eval.child, eval); - const stdout = mr.fileReader(0); - const Header = std.zig.Server.Message.Header; + var client: std.zig.Client = .{ + .in = mr.reader(0), + .out = undefined, + }; while (true) { - const header = stdout.interface.takeStruct(Header, .little) catch |err| switch (err) { - error.EndOfStream => break, - error.ReadFailed => return stdout.err.?, - }; - stdout.interface.discardAll(header.bytes_len) catch |err| switch (err) { - error.ReadFailed => return stdout.err.?, - error.EndOfStream => |e| return e, + const header = client.receiveMessageWithMultiReader(mr, .none) catch |err| switch (err) { + error.Timeout => unreachable, + error.EndOfStream => |e| { + if (client.in.bufferedLen() == 0) break; + return e; + }, + else => |e| return e, }; + try client.in.discardAll(header.bytes_len); } - try mr.fillRemaining(.none); - const stderr = mr.reader(1).buffered(); if (stderr.len > 0) eval.fatal("unexpected stderr:\n{s}", .{stderr}); } @@ -773,7 +777,7 @@ const Case = struct { .backend = backend, }); } else if (std.mem.eql(u8, key, "module")) { - const split_idx = std.mem.indexOfScalar(u8, val, '=') orelse + const split_idx = std.mem.findScalar(u8, val, '=') orelse fatal("line {d}: module does not include file", .{line_n}); const name = val[0..split_idx]; const file = val[split_idx + 1 ..]; @@ -899,12 +903,12 @@ fn requestExit(child: *std.process.Child, eval: *Eval) void { if (child.stdin == null) return; const io = eval.io; - const header: std.zig.Client.Message.Header = .{ - .tag = .exit, - .bytes_len = 0, + var w = eval.child.stdin.?.writerStreaming(io, &.{}); + var client: std.zig.Client = .{ + .in = undefined, + .out = &w.interface, }; - var w = eval.child.stdin.?.writer(io, &.{}); - w.interface.writeStruct(header, .little) catch |err| switch (err) { + client.serveBodylessMessage(.exit) catch |err| switch (err) { error.WriteFailed => switch (w.err.?) { error.BrokenPipe => {}, else => |e| eval.fatal("failed to send exit: {t}", .{e}), @@ -979,7 +983,7 @@ fn rand64(io: Io) u64 { fn parseTargetQueryAndBackend(input_str: []const u8, err_prefix: []const u8) struct { std.Target.Query, Backend } { const fatal = std.process.fatal; - const split_idx = std.mem.lastIndexOfScalar(u8, input_str, '-') orelse + const split_idx = std.mem.findScalarLast(u8, input_str, '-') orelse fatal("{s}target does not include backend", .{err_prefix}); const query = input_str[0..split_idx]; diff --git a/tools/migrate_langref.zig b/tools/migrate_langref.zig index 2810bfd3eaa60752eaa075746d18735a441a2760..4c48113a8698f91067d5b7887adb3286df3bc351 100644 --- a/tools/migrate_langref.zig +++ b/tools/migrate_langref.zig @@ -319,7 +319,7 @@ fn walk(arena: Allocator, io: Io, tokenizer: *Tokenizer, out_dir: Dir, w: anytyp return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {s}", .{code_kind_str}); } - var mode: std.builtin.OptimizeMode = .Debug; + var mode: std.builtin.OptimizeMode = .debug; var link_objects = std.array_list.Managed([]const u8).init(arena); var target_str: ?[]const u8 = null; var link_libc = false; @@ -403,7 +403,7 @@ fn walk(arena: Allocator, io: Io, tokenizer: *Tokenizer, out_dir: Dir, w: anytyp }, } - if (mode != .Debug) + if (mode != .debug) try code.print("// optimize={s}\n", .{@tagName(mode)}); for (link_objects.items) |link_object| { diff --git a/tools/process_headers.zig b/tools/process_headers.zig index 3e912c742e79c4c89d242d72a3e8c7126741c3f7..976f17b18207bd12bd915a64b4318d9543e63399 100644 --- a/tools/process_headers.zig +++ b/tools/process_headers.zig @@ -36,6 +36,8 @@ const glibc_targets = [_]LibCTarget{ .{ .arch = .aarch64_be, .abi = .gnu, .dest = "aarch64-linux-gnu" }, .{ .arch = .csky, .abi = .gnueabi, .dest = "csky-linux-gnu" }, .{ .arch = .csky, .abi = .gnueabihf, .dest = "csky-linux-gnu" }, + .{ .arch = .loongarch32, .abi = .gnu, .dest = "loongarch-linux-gnu" }, + .{ .arch = .loongarch32, .abi = .gnusf, .dest = "loongarch-linux-gnu" }, .{ .arch = .loongarch64, .abi = .gnu, .dest = "loongarch-linux-gnu" }, .{ .arch = .loongarch64, .abi = .gnusf, .dest = "loongarch-linux-gnu" }, .{ .arch = .m68k, .abi = .gnu }, diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index 43b81238703433538070330f5d96e3fe4a337f41..a89ec3724ee72099aabe7f5ff50e47625ec1bc75 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -599,7 +599,7 @@ const known_options = [_]KnownOpt{ const blacklisted_options = [_][]const u8{}; fn knownOption(name: []const u8) ?[]const u8 { - const chopped_name = if (std.mem.indexOfScalar(u8, name, '=')) |idx| name[0..idx] else name; + const chopped_name = if (std.mem.findScalar(u8, name, '=')) |idx| name[0..idx] else name; for (known_options) |item| { if (std.mem.eql(u8, chopped_name, item.name)) { return item.ident; diff --git a/tools/update_crc_catalog.zig b/tools/update_crc_catalog.zig index 55f51ce92b4f4a36f51fd176b681487de16d1621..c39008f495d3036cc4d1f9a4b93bfa235117c58d 100644 --- a/tools/update_crc_catalog.zig +++ b/tools/update_crc_catalog.zig @@ -99,7 +99,7 @@ fn @"i like cheese"(arena: std.mem.Allocator, io: Io, args: []const []const u8) var it = mem.splitSequence(u8, line, " "); while (it.next()) |property| { - const i = mem.indexOf(u8, property, "=").?; + const i = mem.find(u8, property, "=").?; const key = property[0..i]; const value = property[i + 1 ..]; if (mem.eql(u8, key, "width")) { diff --git a/tools/update_glibc.zig b/tools/update_glibc.zig index 29df298bf6c49d5e5f140069d5b607550ecca979..46242d8e8cad829c216b5ff3956f129c1c000e0c 100644 --- a/tools/update_glibc.zig +++ b/tools/update_glibc.zig @@ -36,6 +36,7 @@ const exempt_extensions = [_][]const u8{ // These are the start files we use when targeting glibc <= 2.33. "-2.33.S", "-2.33.c", + "-2.32.c", }; pub fn main(init: std.process.Init) !void {